merge trunk, fixed unittests, added i18n strings, cleanups etc etc.
This commit is contained in:
1
Authors
1
Authors
@@ -27,6 +27,7 @@ Rick Clark <rick@openstack.org>
|
||||
Ryan Lucio <rlucio@internap.com>
|
||||
Sandy Walsh <sandy.walsh@rackspace.com>
|
||||
Soren Hansen <soren.hansen@rackspace.com>
|
||||
Thierry Carrez <thierry@openstack.org>
|
||||
Todd Willey <todd@ansolabs.com>
|
||||
Trey Morris <trey.morris@rackspace.com>
|
||||
Vishvananda Ishaya <vishvananda@gmail.com>
|
||||
|
||||
@@ -16,16 +16,24 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
# ARG is the id of the user
|
||||
export SUBJ="/C=US/ST=California/L=MountainView/O=AnsoLabs/OU=NovaDev/CN=customer-intCA-$1"
|
||||
mkdir INTER/$1
|
||||
cd INTER/$1
|
||||
# $1 is the id of the project and $2 is the subject of the cert
|
||||
NAME=$1
|
||||
SUBJ=$2
|
||||
mkdir -p projects/$NAME
|
||||
cd projects/$NAME
|
||||
cp ../../openssl.cnf.tmpl openssl.cnf
|
||||
sed -i -e s/%USERNAME%/$1/g openssl.cnf
|
||||
sed -i -e s/%USERNAME%/$NAME/g openssl.cnf
|
||||
mkdir certs crl newcerts private
|
||||
openssl req -new -x509 -extensions v3_ca -keyout private/cakey.pem -out cacert.pem -days 365 -config ./openssl.cnf -batch -nodes
|
||||
echo "10" > serial
|
||||
touch index.txt
|
||||
openssl genrsa -out private/cakey.pem 1024 -config ./openssl.cnf -batch -nodes
|
||||
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
|
||||
# NOTE(vish): Disabling intermediate ca's because we don't actually need them.
|
||||
# It makes more sense to have each project have its own root ca.
|
||||
# openssl genrsa -out private/cakey.pem 1024 -config ./openssl.cnf -batch -nodes
|
||||
# openssl req -new -sha256 -key private/cakey.pem -out ../../reqs/inter$NAME.csr -batch -subj "$SUBJ"
|
||||
openssl ca -gencrl -config ./openssl.cnf -out crl.pem
|
||||
if [ "`id -u`" != "`grep nova /etc/passwd | cut -d':' -f3`" ]; then
|
||||
sudo chown -R nova:nogroup .
|
||||
fi
|
||||
# cd ../../
|
||||
# openssl ca -extensions v3_ca -days 365 -out INTER/$NAME/cacert.pem -in reqs/inter$NAME.csr -config openssl.cnf -batch
|
||||
|
||||
@@ -25,4 +25,5 @@ else
|
||||
openssl req -new -x509 -extensions v3_ca -keyout private/cakey.pem -out cacert.pem -days 365 -config ./openssl.cnf -batch -nodes
|
||||
touch index.txt
|
||||
echo "10" > serial
|
||||
openssl ca -gencrl -config ./openssl.cnf -out crl.pem
|
||||
fi
|
||||
|
||||
36
CA/genvpn.sh
Executable file
36
CA/genvpn.sh
Executable file
@@ -0,0 +1,36 @@
|
||||
#!/bin/bash
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2010 United States Government as represented by the
|
||||
# Administrator of the National Aeronautics and Space Administration.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# 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
|
||||
NAME=$1
|
||||
SUBJ=$2
|
||||
|
||||
mkdir -p projects/$NAME
|
||||
cd projects/$NAME
|
||||
|
||||
# generate a server priv key
|
||||
openssl genrsa -out server.key 2048
|
||||
|
||||
# generate a server CSR
|
||||
openssl req -new -key server.key -out server.csr -batch -subj "$SUBJ"
|
||||
|
||||
novauid=`getent passwd nova | awk -F: '{print $3}'`
|
||||
if [ ! -z "${novauid}" ] && [ "`id -u`" != "${novauid}" ]; then
|
||||
sudo chown -R nova:nogroup .
|
||||
fi
|
||||
@@ -24,7 +24,6 @@ dir = .
|
||||
|
||||
[ ca ]
|
||||
default_ca = CA_default
|
||||
unique_subject = no
|
||||
|
||||
[ CA_default ]
|
||||
serial = $dir/serial
|
||||
@@ -32,6 +31,8 @@ database = $dir/index.txt
|
||||
new_certs_dir = $dir/newcerts
|
||||
certificate = $dir/cacert.pem
|
||||
private_key = $dir/private/cakey.pem
|
||||
unique_subject = no
|
||||
default_crl_days = 365
|
||||
default_days = 365
|
||||
default_md = md5
|
||||
preserve = no
|
||||
|
||||
@@ -72,6 +72,7 @@ if os.path.exists(os.path.join(possible_topdir, 'nova', '__init__.py')):
|
||||
gettext.install('nova', unicode=1)
|
||||
|
||||
from nova import context
|
||||
from nova import crypto
|
||||
from nova import db
|
||||
from nova import exception
|
||||
from nova import flags
|
||||
@@ -96,47 +97,43 @@ class VpnCommands(object):
|
||||
self.manager = manager.AuthManager()
|
||||
self.pipe = pipelib.CloudPipe()
|
||||
|
||||
def list(self):
|
||||
"""Print a listing of the VPNs for all projects."""
|
||||
def list(self, project=None):
|
||||
"""Print a listing of the VPN data for one or all projects.
|
||||
|
||||
args: [project=all]"""
|
||||
print "%-12s\t" % 'project',
|
||||
print "%-20s\t" % 'ip:port',
|
||||
print "%-20s\t" % 'private_ip',
|
||||
print "%s" % 'state'
|
||||
for project in self.manager.get_projects():
|
||||
print "%-12s\t" % project.name,
|
||||
|
||||
try:
|
||||
s = "%s:%s" % (project.vpn_ip, project.vpn_port)
|
||||
except exception.NotFound:
|
||||
s = "None"
|
||||
print "%-20s\t" % s,
|
||||
|
||||
vpn = self._vpn_for(project.id)
|
||||
if vpn:
|
||||
command = "ping -c1 -w1 %s > /dev/null; echo $?"
|
||||
out, _err = utils.execute(command % vpn['private_dns_name'],
|
||||
check_exit_code=False)
|
||||
if out.strip() == '0':
|
||||
net = 'up'
|
||||
if project:
|
||||
projects = [self.manager.get_project(project)]
|
||||
else:
|
||||
net = 'down'
|
||||
print vpn['private_dns_name'],
|
||||
print vpn['node_name'],
|
||||
print vpn['instance_id'],
|
||||
projects = self.manager.get_projects()
|
||||
# NOTE(vish): This hits the database a lot. We could optimize
|
||||
# by getting all networks in one query and all vpns
|
||||
# in aother query, then doing lookups by project
|
||||
for project in projects:
|
||||
print "%-12s\t" % project.name,
|
||||
ipport = "%s:%s" % (project.vpn_ip, project.vpn_port)
|
||||
print "%-20s\t" % ipport,
|
||||
ctxt = context.get_admin_context()
|
||||
vpn = db.instance_get_project_vpn(ctxt, project.id)
|
||||
if vpn:
|
||||
address = None
|
||||
state = 'down'
|
||||
if vpn.get('fixed_ip', None):
|
||||
address = vpn['fixed_ip']['address']
|
||||
if project.vpn_ip and utils.vpn_ping(project.vpn_ip,
|
||||
project.vpn_port):
|
||||
state = 'up'
|
||||
print address,
|
||||
print vpn['host'],
|
||||
print vpn['ec2_id'],
|
||||
print vpn['state_description'],
|
||||
print net
|
||||
|
||||
print state
|
||||
else:
|
||||
print None
|
||||
|
||||
def _vpn_for(self, project_id):
|
||||
"""Get the VPN instance for a project ID."""
|
||||
for instance in db.instance_get_all(context.get_admin_context()):
|
||||
if (instance['image_id'] == FLAGS.vpn_image_id
|
||||
and not instance['state_description'] in
|
||||
['shutting_down', 'shutdown']
|
||||
and instance['project_id'] == project_id):
|
||||
return instance
|
||||
|
||||
def spawn(self):
|
||||
"""Run all VPNs."""
|
||||
for p in reversed(self.manager.get_projects()):
|
||||
@@ -149,6 +146,21 @@ class VpnCommands(object):
|
||||
"""Start the VPN for a given project."""
|
||||
self.pipe.launch_vpn_instance(project_id)
|
||||
|
||||
def change(self, project_id, ip, port):
|
||||
"""Change the ip and port for a vpn.
|
||||
|
||||
args: project, ip, port"""
|
||||
project = self.manager.get_project(project_id)
|
||||
if not project:
|
||||
print 'No project %s' % (project_id)
|
||||
return
|
||||
admin = context.get_admin_context()
|
||||
network_ref = db.project_get_network(admin, project_id)
|
||||
db.network_update(admin,
|
||||
network_ref['id'],
|
||||
{'vpn_public_address': ip,
|
||||
'vpn_public_port': int(port)})
|
||||
|
||||
|
||||
class ShellCommands(object):
|
||||
def bpython(self):
|
||||
@@ -295,6 +307,14 @@ class UserCommands(object):
|
||||
is_admin = False
|
||||
self.manager.modify_user(name, access_key, secret_key, is_admin)
|
||||
|
||||
def revoke(self, user_id, project_id=None):
|
||||
"""revoke certs for a user
|
||||
arguments: user_id [project_id]"""
|
||||
if project_id:
|
||||
crypto.revoke_certs_by_user_and_project(user_id, project_id)
|
||||
else:
|
||||
crypto.revoke_certs_by_user(user_id)
|
||||
|
||||
|
||||
class ProjectCommands(object):
|
||||
"""Class for managing projects."""
|
||||
|
||||
@@ -64,12 +64,9 @@ 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('credential_cert_subject',
|
||||
'/C=US/ST=California/L=MountainView/O=AnsoLabs/'
|
||||
'OU=NovaDev/CN=%s-%s',
|
||||
'Subject for certificate for users')
|
||||
flags.DEFINE_string('credential_rc_file', '%src',
|
||||
'Filename of rc in credentials zip, %s will be '
|
||||
'replaced by name of the region (nova by default)')
|
||||
flags.DEFINE_string('auth_driver', 'nova.auth.dbdriver.DbDriver',
|
||||
'Driver that auth manager uses')
|
||||
|
||||
@@ -543,11 +540,10 @@ class AuthManager(object):
|
||||
"""
|
||||
|
||||
network_ref = db.project_get_network(context.get_admin_context(),
|
||||
Project.safe_id(project))
|
||||
Project.safe_id(project), False)
|
||||
|
||||
if not network_ref['vpn_public_port']:
|
||||
raise exception.NotFound(_('project network data has not '
|
||||
'been set'))
|
||||
if not network_ref:
|
||||
return (None, None)
|
||||
return (network_ref['vpn_public_address'],
|
||||
network_ref['vpn_public_port'])
|
||||
|
||||
@@ -629,27 +625,37 @@ class AuthManager(object):
|
||||
def get_key_pairs(context):
|
||||
return db.key_pair_get_all_by_user(context.elevated(), context.user_id)
|
||||
|
||||
def get_credentials(self, user, project=None):
|
||||
def get_credentials(self, user, project=None, use_dmz=True):
|
||||
"""Get credential zip for user in project"""
|
||||
if not isinstance(user, User):
|
||||
user = self.get_user(user)
|
||||
if project is None:
|
||||
project = user.id
|
||||
pid = Project.safe_id(project)
|
||||
rc = self.__generate_rc(user.access, user.secret, pid)
|
||||
private_key, signed_cert = self._generate_x509_cert(user.id, pid)
|
||||
private_key, signed_cert = crypto.generate_x509_cert(user.id, pid)
|
||||
|
||||
tmpdir = tempfile.mkdtemp()
|
||||
zf = os.path.join(tmpdir, "temp.zip")
|
||||
zippy = zipfile.ZipFile(zf, 'w')
|
||||
zippy.writestr(FLAGS.credential_rc_file, rc)
|
||||
if use_dmz and FLAGS.region_list:
|
||||
regions = {}
|
||||
for item in FLAGS.region_list:
|
||||
region, _sep, region_host = item.partition("=")
|
||||
regions[region] = region_host
|
||||
else:
|
||||
regions = {'nova': FLAGS.cc_host}
|
||||
for region, host in regions.iteritems():
|
||||
rc = self.__generate_rc(user.access,
|
||||
user.secret,
|
||||
pid,
|
||||
use_dmz,
|
||||
host)
|
||||
zippy.writestr(FLAGS.credential_rc_file % region, rc)
|
||||
|
||||
zippy.writestr(FLAGS.credential_key_file, private_key)
|
||||
zippy.writestr(FLAGS.credential_cert_file, signed_cert)
|
||||
|
||||
try:
|
||||
(vpn_ip, vpn_port) = self.get_project_vpn_data(project)
|
||||
except exception.NotFound:
|
||||
vpn_ip = None
|
||||
if vpn_ip:
|
||||
configfile = open(FLAGS.vpn_client_template, "r")
|
||||
s = string.Template(configfile.read())
|
||||
@@ -662,7 +668,7 @@ class AuthManager(object):
|
||||
else:
|
||||
logging.warn(_("No vpn data for project %s"), pid)
|
||||
|
||||
zippy.writestr(FLAGS.ca_file, crypto.fetch_ca(user.id))
|
||||
zippy.writestr(FLAGS.ca_file, crypto.fetch_ca(pid))
|
||||
zippy.close()
|
||||
with open(zf, 'rb') as f:
|
||||
read_buffer = f.read()
|
||||
@@ -670,38 +676,38 @@ class AuthManager(object):
|
||||
shutil.rmtree(tmpdir)
|
||||
return read_buffer
|
||||
|
||||
def get_environment_rc(self, user, project=None):
|
||||
def get_environment_rc(self, user, project=None, use_dmz=True):
|
||||
"""Get credential zip for user in project"""
|
||||
if not isinstance(user, User):
|
||||
user = self.get_user(user)
|
||||
if project is None:
|
||||
project = user.id
|
||||
pid = Project.safe_id(project)
|
||||
return self.__generate_rc(user.access, user.secret, pid)
|
||||
return self.__generate_rc(user.access, user.secret, pid, use_dmz)
|
||||
|
||||
@staticmethod
|
||||
def __generate_rc(access, secret, pid):
|
||||
def __generate_rc(access, secret, pid, use_dmz=True, host=None):
|
||||
"""Generate rc file for user"""
|
||||
if use_dmz:
|
||||
cc_host = FLAGS.cc_dmz
|
||||
else:
|
||||
cc_host = FLAGS.cc_host
|
||||
# NOTE(vish): Always use the dmz since it is used from inside the
|
||||
# instance
|
||||
s3_host = FLAGS.s3_dmz
|
||||
if host:
|
||||
s3_host = host
|
||||
cc_host = host
|
||||
rc = open(FLAGS.credentials_template).read()
|
||||
rc = rc % {'access': access,
|
||||
'project': pid,
|
||||
'secret': secret,
|
||||
'ec2': FLAGS.ec2_url,
|
||||
's3': 'http://%s:%s' % (FLAGS.s3_host, FLAGS.s3_port),
|
||||
'ec2': '%s://%s:%s%s' % (FLAGS.ec2_prefix,
|
||||
cc_host,
|
||||
FLAGS.cc_port,
|
||||
FLAGS.ec2_suffix),
|
||||
's3': 'http://%s:%s' % (s3_host, FLAGS.s3_port),
|
||||
'nova': FLAGS.ca_file,
|
||||
'cert': FLAGS.credential_cert_file,
|
||||
'key': FLAGS.credential_key_file}
|
||||
return rc
|
||||
|
||||
def _generate_x509_cert(self, uid, pid):
|
||||
"""Generate x509 cert for user"""
|
||||
(private_key, csr) = crypto.generate_x509_cert(
|
||||
self.__cert_subject(uid))
|
||||
# TODO(joshua): This should be async call back to the cloud controller
|
||||
signed_cert = crypto.sign_csr(csr, pid)
|
||||
return (private_key, signed_cert)
|
||||
|
||||
@staticmethod
|
||||
def __cert_subject(uid):
|
||||
"""Helper to generate cert subject"""
|
||||
return FLAGS.credential_cert_subject % (uid, utils.isotime())
|
||||
|
||||
59
nova/fakememcache.py
Normal file
59
nova/fakememcache.py
Normal file
@@ -0,0 +1,59 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2010 United States Government as represented by the
|
||||
# Administrator of the National Aeronautics and Space Administration.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# 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.
|
||||
|
||||
"""Super simple fake memcache client."""
|
||||
|
||||
import utils
|
||||
|
||||
|
||||
class Client(object):
|
||||
"""Replicates a tiny subset of memcached client interface."""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
"""Ignores the passed in args"""
|
||||
self.cache = {}
|
||||
|
||||
def get(self, key):
|
||||
"""Retrieves the value for a key or None."""
|
||||
(timeout, value) = self.cache.get(key, (0, None))
|
||||
if timeout == 0 or utils.utcnow_ts() < timeout:
|
||||
return value
|
||||
return None
|
||||
|
||||
def set(self, key, value, time=0, min_compress_len=0):
|
||||
"""Sets the value for a key."""
|
||||
timeout = 0
|
||||
if time != 0:
|
||||
timeout = utils.utcnow_ts() + time
|
||||
self.cache[key] = (timeout, value)
|
||||
return True
|
||||
|
||||
def add(self, key, value, time=0, min_compress_len=0):
|
||||
"""Sets the value for a key if it doesn't exist."""
|
||||
if not self.get(key) is None:
|
||||
return False
|
||||
return self.set(key, value, time, min_compress_len)
|
||||
|
||||
def incr(self, key, delta=1):
|
||||
"""Increments the value for a key."""
|
||||
value = self.get(key)
|
||||
if value is None:
|
||||
return None
|
||||
new_value = int(value) + delta
|
||||
self.cache[key] = (self.cache[key][0], str(new_value))
|
||||
return new_value
|
||||
@@ -25,6 +25,10 @@ from carrot.backends import base
|
||||
from eventlet import greenthread
|
||||
|
||||
|
||||
EXCHANGES = {}
|
||||
QUEUES = {}
|
||||
|
||||
|
||||
class Message(base.BaseMessage):
|
||||
pass
|
||||
|
||||
@@ -68,39 +72,31 @@ class Queue(object):
|
||||
return self._queue.get()
|
||||
|
||||
|
||||
class Backend(object):
|
||||
""" Singleton backend for testing """
|
||||
class __impl(base.BaseBackend):
|
||||
def __init__(self, *args, **kwargs):
|
||||
#super(__impl, self).__init__(*args, **kwargs)
|
||||
self._exchanges = {}
|
||||
self._queues = {}
|
||||
|
||||
def _reset_all(self):
|
||||
self._exchanges = {}
|
||||
self._queues = {}
|
||||
|
||||
class Backend(base.BaseBackend):
|
||||
def queue_declare(self, queue, **kwargs):
|
||||
if queue not in self._queues:
|
||||
global QUEUES
|
||||
if queue not in QUEUES:
|
||||
logging.debug(_('Declaring queue %s'), queue)
|
||||
self._queues[queue] = Queue(queue)
|
||||
QUEUES[queue] = Queue(queue)
|
||||
|
||||
def exchange_declare(self, exchange, type, *args, **kwargs):
|
||||
if exchange not in self._exchanges:
|
||||
global EXCHANGES
|
||||
if exchange not in EXCHANGES:
|
||||
logging.debug(_('Declaring exchange %s'), exchange)
|
||||
self._exchanges[exchange] = Exchange(exchange, type)
|
||||
EXCHANGES[exchange] = Exchange(exchange, type)
|
||||
|
||||
def queue_bind(self, queue, exchange, routing_key, **kwargs):
|
||||
global EXCHANGES
|
||||
global QUEUES
|
||||
logging.debug(_('Binding %s to %s with key %s'),
|
||||
queue, exchange, routing_key)
|
||||
self._exchanges[exchange].bind(self._queues[queue].push,
|
||||
routing_key)
|
||||
EXCHANGES[exchange].bind(QUEUES[queue].push, routing_key)
|
||||
|
||||
def declare_consumer(self, queue, callback, *args, **kwargs):
|
||||
self.current_queue = queue
|
||||
self.current_callback = callback
|
||||
|
||||
def consume(self, *args, **kwargs):
|
||||
def consume(self, limit=None):
|
||||
while True:
|
||||
item = self.get(self.current_queue)
|
||||
if item:
|
||||
@@ -109,10 +105,10 @@ class Backend(object):
|
||||
greenthread.sleep(0)
|
||||
|
||||
def get(self, queue, no_ack=False):
|
||||
if not queue in self._queues or not self._queues[queue].size():
|
||||
global QUEUES
|
||||
if not queue in QUEUES or not QUEUES[queue].size():
|
||||
return None
|
||||
(message_data, content_type, content_encoding) = \
|
||||
self._queues[queue].pop()
|
||||
(message_data, content_type, content_encoding) = QUEUES[queue].pop()
|
||||
message = Message(backend=self, body=message_data,
|
||||
content_type=content_type,
|
||||
content_encoding=content_encoding)
|
||||
@@ -126,23 +122,13 @@ class Backend(object):
|
||||
return (message_data, content_type, content_encoding)
|
||||
|
||||
def publish(self, message, exchange, routing_key, **kwargs):
|
||||
if exchange in self._exchanges:
|
||||
self._exchanges[exchange].publish(
|
||||
message, routing_key=routing_key)
|
||||
|
||||
__instance = None
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
if Backend.__instance is None:
|
||||
Backend.__instance = Backend.__impl(*args, **kwargs)
|
||||
self.__dict__['_Backend__instance'] = Backend.__instance
|
||||
|
||||
def __getattr__(self, attr):
|
||||
return getattr(self.__instance, attr)
|
||||
|
||||
def __setattr__(self, attr, value):
|
||||
return setattr(self.__instance, attr, value)
|
||||
global EXCHANGES
|
||||
if exchange in EXCHANGES:
|
||||
EXCHANGES[exchange].publish(message, routing_key=routing_key)
|
||||
|
||||
|
||||
def reset_all():
|
||||
Backend()._reset_all()
|
||||
global EXCHANGES
|
||||
global QUEUES
|
||||
EXCHANGES = {}
|
||||
QUEUES = {}
|
||||
|
||||
@@ -29,6 +29,8 @@ import sys
|
||||
|
||||
import gflags
|
||||
|
||||
from nova import utils
|
||||
|
||||
|
||||
class FlagValues(gflags.FlagValues):
|
||||
"""Extension of gflags.FlagValues that allows undefined and runtime flags.
|
||||
@@ -211,7 +213,8 @@ DEFINE_string('connection_type', 'libvirt', 'libvirt, xenapi or fake')
|
||||
DEFINE_string('aws_access_key_id', 'admin', 'AWS Access ID')
|
||||
DEFINE_string('aws_secret_access_key', 'admin', 'AWS Access Key')
|
||||
DEFINE_integer('s3_port', 3333, 's3 port')
|
||||
DEFINE_string('s3_host', '127.0.0.1', 's3 host')
|
||||
DEFINE_string('s3_host', utils.get_my_ip(), 's3 host (for infrastructure)')
|
||||
DEFINE_string('s3_dmz', utils.get_my_ip(), 's3 dmz ip (for instances)')
|
||||
DEFINE_string('compute_topic', 'compute', 'the topic compute nodes listen on')
|
||||
DEFINE_string('scheduler_topic', 'scheduler',
|
||||
'the topic scheduler nodes listen on')
|
||||
@@ -230,8 +233,11 @@ DEFINE_string('rabbit_virtual_host', '/', 'rabbit virtual host')
|
||||
DEFINE_integer('rabbit_retry_interval', 10, 'rabbit connection retry interval')
|
||||
DEFINE_integer('rabbit_max_retries', 12, 'rabbit connection attempts')
|
||||
DEFINE_string('control_exchange', 'nova', 'the main exchange to connect to')
|
||||
DEFINE_string('ec2_url', 'http://127.0.0.1:8773/services/Cloud',
|
||||
'Url to ec2 api server')
|
||||
DEFINE_string('ec2_prefix', 'http', 'prefix for ec2')
|
||||
DEFINE_string('cc_host', utils.get_my_ip(), 'ip of api server')
|
||||
DEFINE_string('cc_dmz', utils.get_my_ip(), 'internal ip of api server')
|
||||
DEFINE_integer('cc_port', 8773, 'cloud controller port')
|
||||
DEFINE_string('ec2_suffix', '/services/Cloud', 'suffix for ec2')
|
||||
|
||||
DEFINE_string('default_image', 'ami-11111',
|
||||
'default image to use, testing only')
|
||||
@@ -241,10 +247,10 @@ DEFINE_string('null_kernel', 'nokernel',
|
||||
'kernel image that indicates not to use a kernel,'
|
||||
' but to use a raw disk image instead')
|
||||
|
||||
DEFINE_string('vpn_image_id', 'ami-CLOUDPIPE', 'AMI for cloudpipe vpn server')
|
||||
DEFINE_string('vpn_image_id', 'ami-cloudpipe', 'AMI for cloudpipe vpn server')
|
||||
DEFINE_string('vpn_key_suffix',
|
||||
'-key',
|
||||
'Suffix to add to project name for vpn key')
|
||||
'-vpn',
|
||||
'Suffix to add to project name for vpn key and secgroups')
|
||||
|
||||
DEFINE_integer('auth_token_ttl', 3600, 'Seconds for auth tokens to linger')
|
||||
|
||||
|
||||
@@ -245,7 +245,7 @@ def msg_reply(msg_id, reply=None, failure=None):
|
||||
logging.error(_("Returning exception %s to caller"), message)
|
||||
logging.error(tb)
|
||||
failure = (failure[0].__name__, str(failure[1]), tb)
|
||||
conn = Connection.instance()
|
||||
conn = Connection.instance(True)
|
||||
publisher = DirectPublisher(connection=conn, msg_id=msg_id)
|
||||
try:
|
||||
publisher.send({'result': reply, 'failure': failure})
|
||||
|
||||
@@ -208,17 +208,13 @@ class AuthManagerTestCase(object):
|
||||
# so it probably belongs in crypto_unittest
|
||||
# but I'm leaving it where I found it.
|
||||
with user_and_project_generator(self.manager) as (user, project):
|
||||
# NOTE(todd): Should mention why we must setup controller first
|
||||
# (somebody please clue me in)
|
||||
cloud_controller = cloud.CloudController()
|
||||
cloud_controller.setup()
|
||||
_key, cert_str = self.manager._generate_x509_cert('test1',
|
||||
'testproj')
|
||||
# NOTE(vish): Setup runs genroot.sh if it hasn't been run
|
||||
cloud.CloudController().setup()
|
||||
_key, cert_str = crypto.generate_x509_cert(user.id, project.id)
|
||||
logging.debug(cert_str)
|
||||
|
||||
# Need to verify that it's signed by the right intermediate CA
|
||||
full_chain = crypto.fetch_ca(project_id='testproj', chain=True)
|
||||
int_cert = crypto.fetch_ca(project_id='testproj', chain=False)
|
||||
full_chain = crypto.fetch_ca(project_id=project.id, chain=True)
|
||||
int_cert = crypto.fetch_ca(project_id=project.id, chain=False)
|
||||
cloud_cert = crypto.fetch_ca()
|
||||
logging.debug("CA chain:\n\n =====\n%s\n\n=====" % full_chain)
|
||||
signed_cert = X509.load_cert_string(cert_str)
|
||||
@@ -227,7 +223,8 @@ class AuthManagerTestCase(object):
|
||||
cloud_cert = X509.load_cert_string(cloud_cert)
|
||||
self.assertTrue(signed_cert.verify(chain_cert.get_pubkey()))
|
||||
self.assertTrue(signed_cert.verify(int_cert.get_pubkey()))
|
||||
if not FLAGS.use_intermediate_ca:
|
||||
|
||||
if not FLAGS.use_project_ca:
|
||||
self.assertTrue(signed_cert.verify(cloud_cert.get_pubkey()))
|
||||
else:
|
||||
self.assertFalse(signed_cert.verify(cloud_cert.get_pubkey()))
|
||||
|
||||
@@ -22,20 +22,18 @@ import logging
|
||||
from M2Crypto import BIO
|
||||
from M2Crypto import RSA
|
||||
import os
|
||||
import StringIO
|
||||
import tempfile
|
||||
import time
|
||||
|
||||
from eventlet import greenthread
|
||||
from xml.etree import ElementTree
|
||||
|
||||
from nova import context
|
||||
from nova import crypto
|
||||
from nova import db
|
||||
from nova import flags
|
||||
from nova import rpc
|
||||
from nova import service
|
||||
from nova import test
|
||||
from nova import utils
|
||||
from nova.auth import manager
|
||||
from nova.compute import power_state
|
||||
from nova.api.ec2 import cloud
|
||||
@@ -54,7 +52,8 @@ os.makedirs(IMAGES_PATH)
|
||||
class CloudTestCase(test.TestCase):
|
||||
def setUp(self):
|
||||
super(CloudTestCase, self).setUp()
|
||||
self.flags(connection_type='fake', images_path=IMAGES_PATH)
|
||||
self.flags(connection_type='fake',
|
||||
images_path=IMAGES_PATH)
|
||||
|
||||
self.conn = rpc.Connection.instance()
|
||||
logging.getLogger().setLevel(logging.DEBUG)
|
||||
@@ -62,17 +61,11 @@ class CloudTestCase(test.TestCase):
|
||||
# set up our cloud
|
||||
self.cloud = cloud.CloudController()
|
||||
|
||||
# set up a service
|
||||
self.compute = utils.import_object(FLAGS.compute_manager)
|
||||
self.compute_consumer = rpc.AdapterConsumer(connection=self.conn,
|
||||
topic=FLAGS.compute_topic,
|
||||
proxy=self.compute)
|
||||
self.compute_consumer.attach_to_eventlet()
|
||||
self.network = utils.import_object(FLAGS.network_manager)
|
||||
self.network_consumer = rpc.AdapterConsumer(connection=self.conn,
|
||||
topic=FLAGS.network_topic,
|
||||
proxy=self.network)
|
||||
self.network_consumer.attach_to_eventlet()
|
||||
# set up services
|
||||
self.compute = service.Service.create(binary='nova-compute')
|
||||
self.compute.start()
|
||||
self.network = service.Service.create(binary='nova-network')
|
||||
self.network.start()
|
||||
|
||||
self.manager = manager.AuthManager()
|
||||
self.user = self.manager.create_user('admin', 'admin', 'admin', True)
|
||||
@@ -83,6 +76,8 @@ class CloudTestCase(test.TestCase):
|
||||
def tearDown(self):
|
||||
self.manager.delete_project(self.project)
|
||||
self.manager.delete_user(self.user)
|
||||
self.compute.kill()
|
||||
self.network.kill()
|
||||
super(CloudTestCase, self).tearDown()
|
||||
|
||||
def _create_key(self, name):
|
||||
@@ -109,12 +104,13 @@ class CloudTestCase(test.TestCase):
|
||||
{'address': address,
|
||||
'host': FLAGS.host})
|
||||
self.cloud.allocate_address(self.context)
|
||||
inst = db.instance_create(self.context, {})
|
||||
inst = db.instance_create(self.context, {'host': FLAGS.host})
|
||||
fixed = self.network.allocate_fixed_ip(self.context, inst['id'])
|
||||
ec2_id = cloud.internal_id_to_ec2_id(inst['internal_id'])
|
||||
self.cloud.associate_address(self.context,
|
||||
instance_id=ec2_id,
|
||||
public_ip=address)
|
||||
greenthread.sleep(0.3)
|
||||
self.cloud.disassociate_address(self.context,
|
||||
public_ip=address)
|
||||
self.cloud.release_address(self.context,
|
||||
|
||||
@@ -41,6 +41,7 @@ class ComputeTestCase(test.TestCase):
|
||||
logging.getLogger().setLevel(logging.DEBUG)
|
||||
super(ComputeTestCase, self).setUp()
|
||||
self.flags(connection_type='fake',
|
||||
stub_network=True,
|
||||
network_manager='nova.network.manager.FlatManager')
|
||||
self.compute = utils.import_object(FLAGS.compute_manager)
|
||||
self.compute_api = compute_api.ComputeAPI()
|
||||
|
||||
86
nova/tests/middleware_unittest.py
Normal file
86
nova/tests/middleware_unittest.py
Normal file
@@ -0,0 +1,86 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2010 United States Government as represented by the
|
||||
# Administrator of the National Aeronautics and Space Administration.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# 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.
|
||||
|
||||
import datetime
|
||||
import webob
|
||||
import webob.dec
|
||||
import webob.exc
|
||||
|
||||
from nova.api import ec2
|
||||
from nova import flags
|
||||
from nova import test
|
||||
from nova import utils
|
||||
|
||||
|
||||
FLAGS = flags.FLAGS
|
||||
|
||||
|
||||
@webob.dec.wsgify
|
||||
def conditional_forbid(req):
|
||||
"""Helper wsgi app returns 403 if param 'die' is 1."""
|
||||
if 'die' in req.params and req.params['die'] == '1':
|
||||
raise webob.exc.HTTPForbidden()
|
||||
return 'OK'
|
||||
|
||||
|
||||
class LockoutTestCase(test.TrialTestCase):
|
||||
"""Test case for the Lockout middleware."""
|
||||
def setUp(self): # pylint: disable-msg=C0103
|
||||
super(LockoutTestCase, self).setUp()
|
||||
utils.set_time_override()
|
||||
self.lockout = ec2.Lockout(conditional_forbid)
|
||||
|
||||
def tearDown(self): # pylint: disable-msg=C0103
|
||||
utils.clear_time_override()
|
||||
super(LockoutTestCase, self).tearDown()
|
||||
|
||||
def _send_bad_attempts(self, access_key, num_attempts=1):
|
||||
"""Fail x."""
|
||||
for i in xrange(num_attempts):
|
||||
req = webob.Request.blank('/?AWSAccessKeyId=%s&die=1' % access_key)
|
||||
self.assertEqual(req.get_response(self.lockout).status_int, 403)
|
||||
|
||||
def _is_locked_out(self, access_key):
|
||||
"""Sends a test request to see if key is locked out."""
|
||||
req = webob.Request.blank('/?AWSAccessKeyId=%s' % access_key)
|
||||
return (req.get_response(self.lockout).status_int == 403)
|
||||
|
||||
def test_lockout(self):
|
||||
self._send_bad_attempts('test', FLAGS.lockout_attempts)
|
||||
self.assertTrue(self._is_locked_out('test'))
|
||||
|
||||
def test_timeout(self):
|
||||
self._send_bad_attempts('test', FLAGS.lockout_attempts)
|
||||
self.assertTrue(self._is_locked_out('test'))
|
||||
utils.advance_time_seconds(FLAGS.lockout_minutes * 60)
|
||||
self.assertFalse(self._is_locked_out('test'))
|
||||
|
||||
def test_multiple_keys(self):
|
||||
self._send_bad_attempts('test1', FLAGS.lockout_attempts)
|
||||
self.assertTrue(self._is_locked_out('test1'))
|
||||
self.assertFalse(self._is_locked_out('test2'))
|
||||
utils.advance_time_seconds(FLAGS.lockout_minutes * 60)
|
||||
self.assertFalse(self._is_locked_out('test1'))
|
||||
self.assertFalse(self._is_locked_out('test2'))
|
||||
|
||||
def test_window_timeout(self):
|
||||
self._send_bad_attempts('test', FLAGS.lockout_attempts - 1)
|
||||
self.assertFalse(self._is_locked_out('test'))
|
||||
utils.advance_time_seconds(FLAGS.lockout_window * 60)
|
||||
self._send_bad_attempts('test', FLAGS.lockout_attempts - 1)
|
||||
self.assertFalse(self._is_locked_out('test'))
|
||||
@@ -26,6 +26,7 @@ from nova import context
|
||||
from nova import db
|
||||
from nova import exception
|
||||
from nova import flags
|
||||
from nova import service
|
||||
from nova import test
|
||||
from nova import utils
|
||||
from nova.auth import manager
|
||||
@@ -40,6 +41,7 @@ class NetworkTestCase(test.TestCase):
|
||||
# NOTE(vish): if you change these flags, make sure to change the
|
||||
# flags in the corresponding section in nova-dhcpbridge
|
||||
self.flags(connection_type='fake',
|
||||
fake_call=True,
|
||||
fake_network=True,
|
||||
network_size=16,
|
||||
num_networks=5)
|
||||
@@ -56,16 +58,13 @@ class NetworkTestCase(test.TestCase):
|
||||
# create the necessary network data for the project
|
||||
user_context = context.RequestContext(project=self.projects[i],
|
||||
user=self.user)
|
||||
network_ref = self.network.get_network(user_context)
|
||||
self.network.set_network_host(context.get_admin_context(),
|
||||
network_ref['id'])
|
||||
host = self.network.get_network_host(user_context.elevated())
|
||||
instance_ref = self._create_instance(0)
|
||||
self.instance_id = instance_ref['id']
|
||||
instance_ref = self._create_instance(1)
|
||||
self.instance2_id = instance_ref['id']
|
||||
|
||||
def tearDown(self):
|
||||
super(NetworkTestCase, self).tearDown()
|
||||
# TODO(termie): this should really be instantiating clean datastores
|
||||
# in between runs, one failure kills all the tests
|
||||
db.instance_destroy(context.get_admin_context(), self.instance_id)
|
||||
@@ -73,6 +72,7 @@ class NetworkTestCase(test.TestCase):
|
||||
for project in self.projects:
|
||||
self.manager.delete_project(project)
|
||||
self.manager.delete_user(self.user)
|
||||
super(NetworkTestCase, self).tearDown()
|
||||
|
||||
def _create_instance(self, project_num, mac=None):
|
||||
if not mac:
|
||||
|
||||
@@ -33,7 +33,7 @@ class RpcTestCase(test.TestCase):
|
||||
"""Test cases for rpc"""
|
||||
def setUp(self):
|
||||
super(RpcTestCase, self).setUp()
|
||||
self.conn = rpc.Connection.instance()
|
||||
self.conn = rpc.Connection.instance(True)
|
||||
self.receiver = TestReceiver()
|
||||
self.consumer = rpc.AdapterConsumer(connection=self.conn,
|
||||
topic='test',
|
||||
@@ -79,6 +79,33 @@ class RpcTestCase(test.TestCase):
|
||||
except rpc.RemoteError as exc:
|
||||
self.assertEqual(int(exc.value), value)
|
||||
|
||||
def test_nested_calls(self):
|
||||
"""Test that we can do an rpc.call inside another call"""
|
||||
class Nested(object):
|
||||
@staticmethod
|
||||
def echo(context, queue, value):
|
||||
"""Calls echo in the passed queue"""
|
||||
logging.debug("Nested received %s, %s", queue, value)
|
||||
ret = rpc.call(context,
|
||||
queue,
|
||||
{"method": "echo",
|
||||
"args": {"value": value}})
|
||||
logging.debug("Nested return %s", ret)
|
||||
return value
|
||||
|
||||
nested = Nested()
|
||||
conn = rpc.Connection.instance(True)
|
||||
consumer = rpc.AdapterConsumer(connection=conn,
|
||||
topic='nested',
|
||||
proxy=nested)
|
||||
consumer.attach_to_eventlet()
|
||||
value = 42
|
||||
result = rpc.call(self.context,
|
||||
'nested', {"method": "echo",
|
||||
"args": {"queue": "test",
|
||||
"value": value}})
|
||||
self.assertEqual(value, result)
|
||||
|
||||
|
||||
class TestReceiver(object):
|
||||
"""Simple Proxy class so the consumer has methods to call
|
||||
|
||||
@@ -78,6 +78,7 @@ class SimpleDriverTestCase(test.TestCase):
|
||||
def setUp(self):
|
||||
super(SimpleDriverTestCase, self).setUp()
|
||||
self.flags(connection_type='fake',
|
||||
stub_network=True,
|
||||
max_cores=4,
|
||||
max_gigabytes=4,
|
||||
network_manager='nova.network.manager.FlatManager',
|
||||
|
||||
@@ -33,6 +33,7 @@ flags.DECLARE('instances_path', 'nova.compute.manager')
|
||||
class LibvirtConnTestCase(test.TestCase):
|
||||
def setUp(self):
|
||||
super(LibvirtConnTestCase, self).setUp()
|
||||
self.flags(fake_call=True)
|
||||
self.manager = manager.AuthManager()
|
||||
self.user = self.manager.create_user('fake', 'fake', 'fake',
|
||||
admin=True)
|
||||
@@ -88,9 +89,9 @@ class LibvirtConnTestCase(test.TestCase):
|
||||
user_context = context.RequestContext(project=self.project,
|
||||
user=self.user)
|
||||
instance_ref = db.instance_create(user_context, instance)
|
||||
network_ref = self.network.get_network(user_context)
|
||||
self.network.set_network_host(context.get_admin_context(),
|
||||
network_ref['id'])
|
||||
host = self.network.get_network_host(user_context.elevated())
|
||||
network_ref = db.project_get_network(context.get_admin_context(),
|
||||
self.project.id)
|
||||
|
||||
fixed_ip = {'address': self.test_ip,
|
||||
'network_id': network_ref['id']}
|
||||
@@ -338,7 +339,7 @@ class NWFilterTestCase(test.TestCase):
|
||||
self.security_group.id)
|
||||
instance = db.instance_get(self.context, inst_id)
|
||||
|
||||
d = self.fw.setup_nwfilters_for_instance(instance)
|
||||
self.fw.setup_base_nwfilters()
|
||||
self.fw.setup_nwfilters_for_instance(instance)
|
||||
_ensure_all_called()
|
||||
self.teardown_security_group()
|
||||
return d
|
||||
|
||||
@@ -51,6 +51,8 @@ class FakeSessionForVMTests(fake.SessionBase):
|
||||
raise fake.Failure(['VM_BAD_POWER_STATE', ref, 'Halted',
|
||||
vm['power_state']])
|
||||
vm['power_state'] = 'Running'
|
||||
vm['is_a_template'] = False
|
||||
vm['is_control_domain'] = False
|
||||
|
||||
|
||||
class FakeSessionForVolumeTests(fake.SessionBase):
|
||||
|
||||
@@ -49,7 +49,7 @@ class XenAPIVolumeTestCase(test.TestCase):
|
||||
FLAGS.xenapi_connection_password = 'test_pass'
|
||||
fakes.stub_out_db_instance_api(self.stubs)
|
||||
fake.reset()
|
||||
self.values = {'name': 1,
|
||||
self.values = {'name': 1, 'id': 1,
|
||||
'project_id': 'fake',
|
||||
'user_id': 'fake',
|
||||
'image_id': 1,
|
||||
@@ -167,7 +167,7 @@ class XenAPIVMTestCase(test.TestCase):
|
||||
|
||||
def test_spawn(self):
|
||||
stubs.stubout_session(self.stubs, stubs.FakeSessionForVMTests)
|
||||
values = {'name': 1,
|
||||
values = {'name': 1, 'id': 1,
|
||||
'project_id': self.project.id,
|
||||
'user_id': self.user.id,
|
||||
'image_id': 1,
|
||||
|
||||
@@ -60,6 +60,7 @@ from nova.tests.auth_unittest import *
|
||||
from nova.tests.cloud_unittest import *
|
||||
from nova.tests.compute_unittest import *
|
||||
from nova.tests.flags_unittest import *
|
||||
from nova.tests.middleware_unittest import *
|
||||
from nova.tests.misc_unittest import *
|
||||
from nova.tests.network_unittest import *
|
||||
#from nova.tests.objectstore_unittest import *
|
||||
|
||||
Reference in New Issue
Block a user