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>
|
Ryan Lucio <rlucio@internap.com>
|
||||||
Sandy Walsh <sandy.walsh@rackspace.com>
|
Sandy Walsh <sandy.walsh@rackspace.com>
|
||||||
Soren Hansen <soren.hansen@rackspace.com>
|
Soren Hansen <soren.hansen@rackspace.com>
|
||||||
|
Thierry Carrez <thierry@openstack.org>
|
||||||
Todd Willey <todd@ansolabs.com>
|
Todd Willey <todd@ansolabs.com>
|
||||||
Trey Morris <trey.morris@rackspace.com>
|
Trey Morris <trey.morris@rackspace.com>
|
||||||
Vishvananda Ishaya <vishvananda@gmail.com>
|
Vishvananda Ishaya <vishvananda@gmail.com>
|
||||||
|
|||||||
@@ -16,16 +16,24 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
# ARG is the id of the user
|
# $1 is the id of the project and $2 is the subject of the cert
|
||||||
export SUBJ="/C=US/ST=California/L=MountainView/O=AnsoLabs/OU=NovaDev/CN=customer-intCA-$1"
|
NAME=$1
|
||||||
mkdir INTER/$1
|
SUBJ=$2
|
||||||
cd INTER/$1
|
mkdir -p projects/$NAME
|
||||||
|
cd projects/$NAME
|
||||||
cp ../../openssl.cnf.tmpl openssl.cnf
|
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
|
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
|
echo "10" > serial
|
||||||
touch index.txt
|
touch index.txt
|
||||||
openssl genrsa -out private/cakey.pem 1024 -config ./openssl.cnf -batch -nodes
|
# NOTE(vish): Disabling intermediate ca's because we don't actually need them.
|
||||||
openssl req -new -sha2 -key private/cakey.pem -out ../../reqs/inter$1.csr -batch -subj "$SUBJ"
|
# It makes more sense to have each project have its own root ca.
|
||||||
cd ../../
|
# openssl genrsa -out private/cakey.pem 1024 -config ./openssl.cnf -batch -nodes
|
||||||
openssl ca -extensions v3_ca -days 365 -out INTER/$1/cacert.pem -in reqs/inter$1.csr -config openssl.cnf -batch
|
# 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
|
openssl req -new -x509 -extensions v3_ca -keyout private/cakey.pem -out cacert.pem -days 365 -config ./openssl.cnf -batch -nodes
|
||||||
touch index.txt
|
touch index.txt
|
||||||
echo "10" > serial
|
echo "10" > serial
|
||||||
|
openssl ca -gencrl -config ./openssl.cnf -out crl.pem
|
||||||
fi
|
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 ]
|
[ ca ]
|
||||||
default_ca = CA_default
|
default_ca = CA_default
|
||||||
unique_subject = no
|
|
||||||
|
|
||||||
[ CA_default ]
|
[ CA_default ]
|
||||||
serial = $dir/serial
|
serial = $dir/serial
|
||||||
@@ -32,6 +31,8 @@ database = $dir/index.txt
|
|||||||
new_certs_dir = $dir/newcerts
|
new_certs_dir = $dir/newcerts
|
||||||
certificate = $dir/cacert.pem
|
certificate = $dir/cacert.pem
|
||||||
private_key = $dir/private/cakey.pem
|
private_key = $dir/private/cakey.pem
|
||||||
|
unique_subject = no
|
||||||
|
default_crl_days = 365
|
||||||
default_days = 365
|
default_days = 365
|
||||||
default_md = md5
|
default_md = md5
|
||||||
preserve = no
|
preserve = no
|
||||||
|
|||||||
@@ -72,6 +72,7 @@ if os.path.exists(os.path.join(possible_topdir, 'nova', '__init__.py')):
|
|||||||
gettext.install('nova', unicode=1)
|
gettext.install('nova', unicode=1)
|
||||||
|
|
||||||
from nova import context
|
from nova import context
|
||||||
|
from nova import crypto
|
||||||
from nova import db
|
from nova import db
|
||||||
from nova import exception
|
from nova import exception
|
||||||
from nova import flags
|
from nova import flags
|
||||||
@@ -96,47 +97,43 @@ class VpnCommands(object):
|
|||||||
self.manager = manager.AuthManager()
|
self.manager = manager.AuthManager()
|
||||||
self.pipe = pipelib.CloudPipe()
|
self.pipe = pipelib.CloudPipe()
|
||||||
|
|
||||||
def list(self):
|
def list(self, project=None):
|
||||||
"""Print a listing of the VPNs for all projects."""
|
"""Print a listing of the VPN data for one or all projects.
|
||||||
|
|
||||||
|
args: [project=all]"""
|
||||||
print "%-12s\t" % 'project',
|
print "%-12s\t" % 'project',
|
||||||
print "%-20s\t" % 'ip:port',
|
print "%-20s\t" % 'ip:port',
|
||||||
|
print "%-20s\t" % 'private_ip',
|
||||||
print "%s" % 'state'
|
print "%s" % 'state'
|
||||||
for project in self.manager.get_projects():
|
if project:
|
||||||
print "%-12s\t" % project.name,
|
projects = [self.manager.get_project(project)]
|
||||||
|
|
||||||
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'
|
|
||||||
else:
|
else:
|
||||||
net = 'down'
|
projects = self.manager.get_projects()
|
||||||
print vpn['private_dns_name'],
|
# NOTE(vish): This hits the database a lot. We could optimize
|
||||||
print vpn['node_name'],
|
# by getting all networks in one query and all vpns
|
||||||
print vpn['instance_id'],
|
# 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 vpn['state_description'],
|
||||||
print net
|
print state
|
||||||
|
|
||||||
else:
|
else:
|
||||||
print None
|
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):
|
def spawn(self):
|
||||||
"""Run all VPNs."""
|
"""Run all VPNs."""
|
||||||
for p in reversed(self.manager.get_projects()):
|
for p in reversed(self.manager.get_projects()):
|
||||||
@@ -149,6 +146,21 @@ class VpnCommands(object):
|
|||||||
"""Start the VPN for a given project."""
|
"""Start the VPN for a given project."""
|
||||||
self.pipe.launch_vpn_instance(project_id)
|
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):
|
class ShellCommands(object):
|
||||||
def bpython(self):
|
def bpython(self):
|
||||||
@@ -295,6 +307,14 @@ class UserCommands(object):
|
|||||||
is_admin = False
|
is_admin = False
|
||||||
self.manager.modify_user(name, access_key, secret_key, is_admin)
|
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 ProjectCommands(object):
|
||||||
"""Class for managing projects."""
|
"""Class for managing projects."""
|
||||||
|
|||||||
@@ -64,12 +64,9 @@ flags.DEFINE_string('credential_key_file', 'pk.pem',
|
|||||||
'Filename of private key in credentials zip')
|
'Filename of private key in credentials zip')
|
||||||
flags.DEFINE_string('credential_cert_file', 'cert.pem',
|
flags.DEFINE_string('credential_cert_file', 'cert.pem',
|
||||||
'Filename of certificate in credentials zip')
|
'Filename of certificate in credentials zip')
|
||||||
flags.DEFINE_string('credential_rc_file', 'novarc',
|
flags.DEFINE_string('credential_rc_file', '%src',
|
||||||
'Filename of rc in credentials zip')
|
'Filename of rc in credentials zip, %s will be '
|
||||||
flags.DEFINE_string('credential_cert_subject',
|
'replaced by name of the region (nova by default)')
|
||||||
'/C=US/ST=California/L=MountainView/O=AnsoLabs/'
|
|
||||||
'OU=NovaDev/CN=%s-%s',
|
|
||||||
'Subject for certificate for users')
|
|
||||||
flags.DEFINE_string('auth_driver', 'nova.auth.dbdriver.DbDriver',
|
flags.DEFINE_string('auth_driver', 'nova.auth.dbdriver.DbDriver',
|
||||||
'Driver that auth manager uses')
|
'Driver that auth manager uses')
|
||||||
|
|
||||||
@@ -543,11 +540,10 @@ class AuthManager(object):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
network_ref = db.project_get_network(context.get_admin_context(),
|
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']:
|
if not network_ref:
|
||||||
raise exception.NotFound(_('project network data has not '
|
return (None, None)
|
||||||
'been set'))
|
|
||||||
return (network_ref['vpn_public_address'],
|
return (network_ref['vpn_public_address'],
|
||||||
network_ref['vpn_public_port'])
|
network_ref['vpn_public_port'])
|
||||||
|
|
||||||
@@ -629,27 +625,37 @@ class AuthManager(object):
|
|||||||
def get_key_pairs(context):
|
def get_key_pairs(context):
|
||||||
return db.key_pair_get_all_by_user(context.elevated(), context.user_id)
|
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"""
|
"""Get credential zip for user in project"""
|
||||||
if not isinstance(user, User):
|
if not isinstance(user, User):
|
||||||
user = self.get_user(user)
|
user = self.get_user(user)
|
||||||
if project is None:
|
if project is None:
|
||||||
project = user.id
|
project = user.id
|
||||||
pid = Project.safe_id(project)
|
pid = Project.safe_id(project)
|
||||||
rc = self.__generate_rc(user.access, user.secret, pid)
|
private_key, signed_cert = crypto.generate_x509_cert(user.id, pid)
|
||||||
private_key, signed_cert = self._generate_x509_cert(user.id, pid)
|
|
||||||
|
|
||||||
tmpdir = tempfile.mkdtemp()
|
tmpdir = tempfile.mkdtemp()
|
||||||
zf = os.path.join(tmpdir, "temp.zip")
|
zf = os.path.join(tmpdir, "temp.zip")
|
||||||
zippy = zipfile.ZipFile(zf, 'w')
|
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_key_file, private_key)
|
||||||
zippy.writestr(FLAGS.credential_cert_file, signed_cert)
|
zippy.writestr(FLAGS.credential_cert_file, signed_cert)
|
||||||
|
|
||||||
try:
|
|
||||||
(vpn_ip, vpn_port) = self.get_project_vpn_data(project)
|
(vpn_ip, vpn_port) = self.get_project_vpn_data(project)
|
||||||
except exception.NotFound:
|
|
||||||
vpn_ip = None
|
|
||||||
if vpn_ip:
|
if vpn_ip:
|
||||||
configfile = open(FLAGS.vpn_client_template, "r")
|
configfile = open(FLAGS.vpn_client_template, "r")
|
||||||
s = string.Template(configfile.read())
|
s = string.Template(configfile.read())
|
||||||
@@ -662,7 +668,7 @@ class AuthManager(object):
|
|||||||
else:
|
else:
|
||||||
logging.warn(_("No vpn data for project %s"), pid)
|
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()
|
zippy.close()
|
||||||
with open(zf, 'rb') as f:
|
with open(zf, 'rb') as f:
|
||||||
read_buffer = f.read()
|
read_buffer = f.read()
|
||||||
@@ -670,38 +676,38 @@ class AuthManager(object):
|
|||||||
shutil.rmtree(tmpdir)
|
shutil.rmtree(tmpdir)
|
||||||
return read_buffer
|
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"""
|
"""Get credential zip for user in project"""
|
||||||
if not isinstance(user, User):
|
if not isinstance(user, User):
|
||||||
user = self.get_user(user)
|
user = self.get_user(user)
|
||||||
if project is None:
|
if project is None:
|
||||||
project = user.id
|
project = user.id
|
||||||
pid = Project.safe_id(project)
|
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
|
@staticmethod
|
||||||
def __generate_rc(access, secret, pid):
|
def __generate_rc(access, secret, pid, use_dmz=True, host=None):
|
||||||
"""Generate rc file for user"""
|
"""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 = open(FLAGS.credentials_template).read()
|
||||||
rc = rc % {'access': access,
|
rc = rc % {'access': access,
|
||||||
'project': pid,
|
'project': pid,
|
||||||
'secret': secret,
|
'secret': secret,
|
||||||
'ec2': FLAGS.ec2_url,
|
'ec2': '%s://%s:%s%s' % (FLAGS.ec2_prefix,
|
||||||
's3': 'http://%s:%s' % (FLAGS.s3_host, FLAGS.s3_port),
|
cc_host,
|
||||||
|
FLAGS.cc_port,
|
||||||
|
FLAGS.ec2_suffix),
|
||||||
|
's3': 'http://%s:%s' % (s3_host, FLAGS.s3_port),
|
||||||
'nova': FLAGS.ca_file,
|
'nova': FLAGS.ca_file,
|
||||||
'cert': FLAGS.credential_cert_file,
|
'cert': FLAGS.credential_cert_file,
|
||||||
'key': FLAGS.credential_key_file}
|
'key': FLAGS.credential_key_file}
|
||||||
return rc
|
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
|
from eventlet import greenthread
|
||||||
|
|
||||||
|
|
||||||
|
EXCHANGES = {}
|
||||||
|
QUEUES = {}
|
||||||
|
|
||||||
|
|
||||||
class Message(base.BaseMessage):
|
class Message(base.BaseMessage):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -68,39 +72,31 @@ class Queue(object):
|
|||||||
return self._queue.get()
|
return self._queue.get()
|
||||||
|
|
||||||
|
|
||||||
class Backend(object):
|
class Backend(base.BaseBackend):
|
||||||
""" 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 = {}
|
|
||||||
|
|
||||||
def queue_declare(self, queue, **kwargs):
|
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)
|
logging.debug(_('Declaring queue %s'), queue)
|
||||||
self._queues[queue] = Queue(queue)
|
QUEUES[queue] = Queue(queue)
|
||||||
|
|
||||||
def exchange_declare(self, exchange, type, *args, **kwargs):
|
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)
|
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):
|
def queue_bind(self, queue, exchange, routing_key, **kwargs):
|
||||||
|
global EXCHANGES
|
||||||
|
global QUEUES
|
||||||
logging.debug(_('Binding %s to %s with key %s'),
|
logging.debug(_('Binding %s to %s with key %s'),
|
||||||
queue, exchange, routing_key)
|
queue, exchange, routing_key)
|
||||||
self._exchanges[exchange].bind(self._queues[queue].push,
|
EXCHANGES[exchange].bind(QUEUES[queue].push, routing_key)
|
||||||
routing_key)
|
|
||||||
|
|
||||||
def declare_consumer(self, queue, callback, *args, **kwargs):
|
def declare_consumer(self, queue, callback, *args, **kwargs):
|
||||||
self.current_queue = queue
|
self.current_queue = queue
|
||||||
self.current_callback = callback
|
self.current_callback = callback
|
||||||
|
|
||||||
def consume(self, *args, **kwargs):
|
def consume(self, limit=None):
|
||||||
while True:
|
while True:
|
||||||
item = self.get(self.current_queue)
|
item = self.get(self.current_queue)
|
||||||
if item:
|
if item:
|
||||||
@@ -109,10 +105,10 @@ class Backend(object):
|
|||||||
greenthread.sleep(0)
|
greenthread.sleep(0)
|
||||||
|
|
||||||
def get(self, queue, no_ack=False):
|
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
|
return None
|
||||||
(message_data, content_type, content_encoding) = \
|
(message_data, content_type, content_encoding) = QUEUES[queue].pop()
|
||||||
self._queues[queue].pop()
|
|
||||||
message = Message(backend=self, body=message_data,
|
message = Message(backend=self, body=message_data,
|
||||||
content_type=content_type,
|
content_type=content_type,
|
||||||
content_encoding=content_encoding)
|
content_encoding=content_encoding)
|
||||||
@@ -126,23 +122,13 @@ class Backend(object):
|
|||||||
return (message_data, content_type, content_encoding)
|
return (message_data, content_type, content_encoding)
|
||||||
|
|
||||||
def publish(self, message, exchange, routing_key, **kwargs):
|
def publish(self, message, exchange, routing_key, **kwargs):
|
||||||
if exchange in self._exchanges:
|
global EXCHANGES
|
||||||
self._exchanges[exchange].publish(
|
if exchange in EXCHANGES:
|
||||||
message, routing_key=routing_key)
|
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)
|
|
||||||
|
|
||||||
|
|
||||||
def reset_all():
|
def reset_all():
|
||||||
Backend()._reset_all()
|
global EXCHANGES
|
||||||
|
global QUEUES
|
||||||
|
EXCHANGES = {}
|
||||||
|
QUEUES = {}
|
||||||
|
|||||||
@@ -29,6 +29,8 @@ import sys
|
|||||||
|
|
||||||
import gflags
|
import gflags
|
||||||
|
|
||||||
|
from nova import utils
|
||||||
|
|
||||||
|
|
||||||
class FlagValues(gflags.FlagValues):
|
class FlagValues(gflags.FlagValues):
|
||||||
"""Extension of gflags.FlagValues that allows undefined and runtime flags.
|
"""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_access_key_id', 'admin', 'AWS Access ID')
|
||||||
DEFINE_string('aws_secret_access_key', 'admin', 'AWS Access Key')
|
DEFINE_string('aws_secret_access_key', 'admin', 'AWS Access Key')
|
||||||
DEFINE_integer('s3_port', 3333, 's3 port')
|
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('compute_topic', 'compute', 'the topic compute nodes listen on')
|
||||||
DEFINE_string('scheduler_topic', 'scheduler',
|
DEFINE_string('scheduler_topic', 'scheduler',
|
||||||
'the topic scheduler nodes listen on')
|
'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_retry_interval', 10, 'rabbit connection retry interval')
|
||||||
DEFINE_integer('rabbit_max_retries', 12, 'rabbit connection attempts')
|
DEFINE_integer('rabbit_max_retries', 12, 'rabbit connection attempts')
|
||||||
DEFINE_string('control_exchange', 'nova', 'the main exchange to connect to')
|
DEFINE_string('control_exchange', 'nova', 'the main exchange to connect to')
|
||||||
DEFINE_string('ec2_url', 'http://127.0.0.1:8773/services/Cloud',
|
DEFINE_string('ec2_prefix', 'http', 'prefix for ec2')
|
||||||
'Url to ec2 api server')
|
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',
|
DEFINE_string('default_image', 'ami-11111',
|
||||||
'default image to use, testing only')
|
'default image to use, testing only')
|
||||||
@@ -241,10 +247,10 @@ DEFINE_string('null_kernel', 'nokernel',
|
|||||||
'kernel image that indicates not to use a kernel,'
|
'kernel image that indicates not to use a kernel,'
|
||||||
' but to use a raw disk image instead')
|
' 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',
|
DEFINE_string('vpn_key_suffix',
|
||||||
'-key',
|
'-vpn',
|
||||||
'Suffix to add to project name for vpn key')
|
'Suffix to add to project name for vpn key and secgroups')
|
||||||
|
|
||||||
DEFINE_integer('auth_token_ttl', 3600, 'Seconds for auth tokens to linger')
|
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(_("Returning exception %s to caller"), message)
|
||||||
logging.error(tb)
|
logging.error(tb)
|
||||||
failure = (failure[0].__name__, str(failure[1]), tb)
|
failure = (failure[0].__name__, str(failure[1]), tb)
|
||||||
conn = Connection.instance()
|
conn = Connection.instance(True)
|
||||||
publisher = DirectPublisher(connection=conn, msg_id=msg_id)
|
publisher = DirectPublisher(connection=conn, msg_id=msg_id)
|
||||||
try:
|
try:
|
||||||
publisher.send({'result': reply, 'failure': failure})
|
publisher.send({'result': reply, 'failure': failure})
|
||||||
|
|||||||
@@ -208,17 +208,13 @@ class AuthManagerTestCase(object):
|
|||||||
# so it probably belongs in crypto_unittest
|
# so it probably belongs in crypto_unittest
|
||||||
# but I'm leaving it where I found it.
|
# but I'm leaving it where I found it.
|
||||||
with user_and_project_generator(self.manager) as (user, project):
|
with user_and_project_generator(self.manager) as (user, project):
|
||||||
# NOTE(todd): Should mention why we must setup controller first
|
# NOTE(vish): Setup runs genroot.sh if it hasn't been run
|
||||||
# (somebody please clue me in)
|
cloud.CloudController().setup()
|
||||||
cloud_controller = cloud.CloudController()
|
_key, cert_str = crypto.generate_x509_cert(user.id, project.id)
|
||||||
cloud_controller.setup()
|
|
||||||
_key, cert_str = self.manager._generate_x509_cert('test1',
|
|
||||||
'testproj')
|
|
||||||
logging.debug(cert_str)
|
logging.debug(cert_str)
|
||||||
|
|
||||||
# Need to verify that it's signed by the right intermediate CA
|
full_chain = crypto.fetch_ca(project_id=project.id, chain=True)
|
||||||
full_chain = crypto.fetch_ca(project_id='testproj', chain=True)
|
int_cert = crypto.fetch_ca(project_id=project.id, chain=False)
|
||||||
int_cert = crypto.fetch_ca(project_id='testproj', chain=False)
|
|
||||||
cloud_cert = crypto.fetch_ca()
|
cloud_cert = crypto.fetch_ca()
|
||||||
logging.debug("CA chain:\n\n =====\n%s\n\n=====" % full_chain)
|
logging.debug("CA chain:\n\n =====\n%s\n\n=====" % full_chain)
|
||||||
signed_cert = X509.load_cert_string(cert_str)
|
signed_cert = X509.load_cert_string(cert_str)
|
||||||
@@ -227,7 +223,8 @@ class AuthManagerTestCase(object):
|
|||||||
cloud_cert = X509.load_cert_string(cloud_cert)
|
cloud_cert = X509.load_cert_string(cloud_cert)
|
||||||
self.assertTrue(signed_cert.verify(chain_cert.get_pubkey()))
|
self.assertTrue(signed_cert.verify(chain_cert.get_pubkey()))
|
||||||
self.assertTrue(signed_cert.verify(int_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()))
|
self.assertTrue(signed_cert.verify(cloud_cert.get_pubkey()))
|
||||||
else:
|
else:
|
||||||
self.assertFalse(signed_cert.verify(cloud_cert.get_pubkey()))
|
self.assertFalse(signed_cert.verify(cloud_cert.get_pubkey()))
|
||||||
|
|||||||
@@ -22,20 +22,18 @@ import logging
|
|||||||
from M2Crypto import BIO
|
from M2Crypto import BIO
|
||||||
from M2Crypto import RSA
|
from M2Crypto import RSA
|
||||||
import os
|
import os
|
||||||
import StringIO
|
|
||||||
import tempfile
|
import tempfile
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from eventlet import greenthread
|
from eventlet import greenthread
|
||||||
from xml.etree import ElementTree
|
|
||||||
|
|
||||||
from nova import context
|
from nova import context
|
||||||
from nova import crypto
|
from nova import crypto
|
||||||
from nova import db
|
from nova import db
|
||||||
from nova import flags
|
from nova import flags
|
||||||
from nova import rpc
|
from nova import rpc
|
||||||
|
from nova import service
|
||||||
from nova import test
|
from nova import test
|
||||||
from nova import utils
|
|
||||||
from nova.auth import manager
|
from nova.auth import manager
|
||||||
from nova.compute import power_state
|
from nova.compute import power_state
|
||||||
from nova.api.ec2 import cloud
|
from nova.api.ec2 import cloud
|
||||||
@@ -54,7 +52,8 @@ os.makedirs(IMAGES_PATH)
|
|||||||
class CloudTestCase(test.TestCase):
|
class CloudTestCase(test.TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(CloudTestCase, self).setUp()
|
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()
|
self.conn = rpc.Connection.instance()
|
||||||
logging.getLogger().setLevel(logging.DEBUG)
|
logging.getLogger().setLevel(logging.DEBUG)
|
||||||
@@ -62,17 +61,11 @@ class CloudTestCase(test.TestCase):
|
|||||||
# set up our cloud
|
# set up our cloud
|
||||||
self.cloud = cloud.CloudController()
|
self.cloud = cloud.CloudController()
|
||||||
|
|
||||||
# set up a service
|
# set up services
|
||||||
self.compute = utils.import_object(FLAGS.compute_manager)
|
self.compute = service.Service.create(binary='nova-compute')
|
||||||
self.compute_consumer = rpc.AdapterConsumer(connection=self.conn,
|
self.compute.start()
|
||||||
topic=FLAGS.compute_topic,
|
self.network = service.Service.create(binary='nova-network')
|
||||||
proxy=self.compute)
|
self.network.start()
|
||||||
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()
|
|
||||||
|
|
||||||
self.manager = manager.AuthManager()
|
self.manager = manager.AuthManager()
|
||||||
self.user = self.manager.create_user('admin', 'admin', 'admin', True)
|
self.user = self.manager.create_user('admin', 'admin', 'admin', True)
|
||||||
@@ -83,6 +76,8 @@ class CloudTestCase(test.TestCase):
|
|||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
self.manager.delete_project(self.project)
|
self.manager.delete_project(self.project)
|
||||||
self.manager.delete_user(self.user)
|
self.manager.delete_user(self.user)
|
||||||
|
self.compute.kill()
|
||||||
|
self.network.kill()
|
||||||
super(CloudTestCase, self).tearDown()
|
super(CloudTestCase, self).tearDown()
|
||||||
|
|
||||||
def _create_key(self, name):
|
def _create_key(self, name):
|
||||||
@@ -109,12 +104,13 @@ class CloudTestCase(test.TestCase):
|
|||||||
{'address': address,
|
{'address': address,
|
||||||
'host': FLAGS.host})
|
'host': FLAGS.host})
|
||||||
self.cloud.allocate_address(self.context)
|
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'])
|
fixed = self.network.allocate_fixed_ip(self.context, inst['id'])
|
||||||
ec2_id = cloud.internal_id_to_ec2_id(inst['internal_id'])
|
ec2_id = cloud.internal_id_to_ec2_id(inst['internal_id'])
|
||||||
self.cloud.associate_address(self.context,
|
self.cloud.associate_address(self.context,
|
||||||
instance_id=ec2_id,
|
instance_id=ec2_id,
|
||||||
public_ip=address)
|
public_ip=address)
|
||||||
|
greenthread.sleep(0.3)
|
||||||
self.cloud.disassociate_address(self.context,
|
self.cloud.disassociate_address(self.context,
|
||||||
public_ip=address)
|
public_ip=address)
|
||||||
self.cloud.release_address(self.context,
|
self.cloud.release_address(self.context,
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ class ComputeTestCase(test.TestCase):
|
|||||||
logging.getLogger().setLevel(logging.DEBUG)
|
logging.getLogger().setLevel(logging.DEBUG)
|
||||||
super(ComputeTestCase, self).setUp()
|
super(ComputeTestCase, self).setUp()
|
||||||
self.flags(connection_type='fake',
|
self.flags(connection_type='fake',
|
||||||
|
stub_network=True,
|
||||||
network_manager='nova.network.manager.FlatManager')
|
network_manager='nova.network.manager.FlatManager')
|
||||||
self.compute = utils.import_object(FLAGS.compute_manager)
|
self.compute = utils.import_object(FLAGS.compute_manager)
|
||||||
self.compute_api = compute_api.ComputeAPI()
|
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 db
|
||||||
from nova import exception
|
from nova import exception
|
||||||
from nova import flags
|
from nova import flags
|
||||||
|
from nova import service
|
||||||
from nova import test
|
from nova import test
|
||||||
from nova import utils
|
from nova import utils
|
||||||
from nova.auth import manager
|
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
|
# NOTE(vish): if you change these flags, make sure to change the
|
||||||
# flags in the corresponding section in nova-dhcpbridge
|
# flags in the corresponding section in nova-dhcpbridge
|
||||||
self.flags(connection_type='fake',
|
self.flags(connection_type='fake',
|
||||||
|
fake_call=True,
|
||||||
fake_network=True,
|
fake_network=True,
|
||||||
network_size=16,
|
network_size=16,
|
||||||
num_networks=5)
|
num_networks=5)
|
||||||
@@ -56,16 +58,13 @@ class NetworkTestCase(test.TestCase):
|
|||||||
# create the necessary network data for the project
|
# create the necessary network data for the project
|
||||||
user_context = context.RequestContext(project=self.projects[i],
|
user_context = context.RequestContext(project=self.projects[i],
|
||||||
user=self.user)
|
user=self.user)
|
||||||
network_ref = self.network.get_network(user_context)
|
host = self.network.get_network_host(user_context.elevated())
|
||||||
self.network.set_network_host(context.get_admin_context(),
|
|
||||||
network_ref['id'])
|
|
||||||
instance_ref = self._create_instance(0)
|
instance_ref = self._create_instance(0)
|
||||||
self.instance_id = instance_ref['id']
|
self.instance_id = instance_ref['id']
|
||||||
instance_ref = self._create_instance(1)
|
instance_ref = self._create_instance(1)
|
||||||
self.instance2_id = instance_ref['id']
|
self.instance2_id = instance_ref['id']
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
super(NetworkTestCase, self).tearDown()
|
|
||||||
# TODO(termie): this should really be instantiating clean datastores
|
# TODO(termie): this should really be instantiating clean datastores
|
||||||
# in between runs, one failure kills all the tests
|
# in between runs, one failure kills all the tests
|
||||||
db.instance_destroy(context.get_admin_context(), self.instance_id)
|
db.instance_destroy(context.get_admin_context(), self.instance_id)
|
||||||
@@ -73,6 +72,7 @@ class NetworkTestCase(test.TestCase):
|
|||||||
for project in self.projects:
|
for project in self.projects:
|
||||||
self.manager.delete_project(project)
|
self.manager.delete_project(project)
|
||||||
self.manager.delete_user(self.user)
|
self.manager.delete_user(self.user)
|
||||||
|
super(NetworkTestCase, self).tearDown()
|
||||||
|
|
||||||
def _create_instance(self, project_num, mac=None):
|
def _create_instance(self, project_num, mac=None):
|
||||||
if not mac:
|
if not mac:
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ class RpcTestCase(test.TestCase):
|
|||||||
"""Test cases for rpc"""
|
"""Test cases for rpc"""
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(RpcTestCase, self).setUp()
|
super(RpcTestCase, self).setUp()
|
||||||
self.conn = rpc.Connection.instance()
|
self.conn = rpc.Connection.instance(True)
|
||||||
self.receiver = TestReceiver()
|
self.receiver = TestReceiver()
|
||||||
self.consumer = rpc.AdapterConsumer(connection=self.conn,
|
self.consumer = rpc.AdapterConsumer(connection=self.conn,
|
||||||
topic='test',
|
topic='test',
|
||||||
@@ -79,6 +79,33 @@ class RpcTestCase(test.TestCase):
|
|||||||
except rpc.RemoteError as exc:
|
except rpc.RemoteError as exc:
|
||||||
self.assertEqual(int(exc.value), value)
|
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):
|
class TestReceiver(object):
|
||||||
"""Simple Proxy class so the consumer has methods to call
|
"""Simple Proxy class so the consumer has methods to call
|
||||||
|
|||||||
@@ -78,6 +78,7 @@ class SimpleDriverTestCase(test.TestCase):
|
|||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(SimpleDriverTestCase, self).setUp()
|
super(SimpleDriverTestCase, self).setUp()
|
||||||
self.flags(connection_type='fake',
|
self.flags(connection_type='fake',
|
||||||
|
stub_network=True,
|
||||||
max_cores=4,
|
max_cores=4,
|
||||||
max_gigabytes=4,
|
max_gigabytes=4,
|
||||||
network_manager='nova.network.manager.FlatManager',
|
network_manager='nova.network.manager.FlatManager',
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ flags.DECLARE('instances_path', 'nova.compute.manager')
|
|||||||
class LibvirtConnTestCase(test.TestCase):
|
class LibvirtConnTestCase(test.TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(LibvirtConnTestCase, self).setUp()
|
super(LibvirtConnTestCase, self).setUp()
|
||||||
|
self.flags(fake_call=True)
|
||||||
self.manager = manager.AuthManager()
|
self.manager = manager.AuthManager()
|
||||||
self.user = self.manager.create_user('fake', 'fake', 'fake',
|
self.user = self.manager.create_user('fake', 'fake', 'fake',
|
||||||
admin=True)
|
admin=True)
|
||||||
@@ -88,9 +89,9 @@ class LibvirtConnTestCase(test.TestCase):
|
|||||||
user_context = context.RequestContext(project=self.project,
|
user_context = context.RequestContext(project=self.project,
|
||||||
user=self.user)
|
user=self.user)
|
||||||
instance_ref = db.instance_create(user_context, instance)
|
instance_ref = db.instance_create(user_context, instance)
|
||||||
network_ref = self.network.get_network(user_context)
|
host = self.network.get_network_host(user_context.elevated())
|
||||||
self.network.set_network_host(context.get_admin_context(),
|
network_ref = db.project_get_network(context.get_admin_context(),
|
||||||
network_ref['id'])
|
self.project.id)
|
||||||
|
|
||||||
fixed_ip = {'address': self.test_ip,
|
fixed_ip = {'address': self.test_ip,
|
||||||
'network_id': network_ref['id']}
|
'network_id': network_ref['id']}
|
||||||
@@ -338,7 +339,7 @@ class NWFilterTestCase(test.TestCase):
|
|||||||
self.security_group.id)
|
self.security_group.id)
|
||||||
instance = db.instance_get(self.context, inst_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()
|
_ensure_all_called()
|
||||||
self.teardown_security_group()
|
self.teardown_security_group()
|
||||||
return d
|
|
||||||
|
|||||||
@@ -51,6 +51,8 @@ class FakeSessionForVMTests(fake.SessionBase):
|
|||||||
raise fake.Failure(['VM_BAD_POWER_STATE', ref, 'Halted',
|
raise fake.Failure(['VM_BAD_POWER_STATE', ref, 'Halted',
|
||||||
vm['power_state']])
|
vm['power_state']])
|
||||||
vm['power_state'] = 'Running'
|
vm['power_state'] = 'Running'
|
||||||
|
vm['is_a_template'] = False
|
||||||
|
vm['is_control_domain'] = False
|
||||||
|
|
||||||
|
|
||||||
class FakeSessionForVolumeTests(fake.SessionBase):
|
class FakeSessionForVolumeTests(fake.SessionBase):
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ class XenAPIVolumeTestCase(test.TestCase):
|
|||||||
FLAGS.xenapi_connection_password = 'test_pass'
|
FLAGS.xenapi_connection_password = 'test_pass'
|
||||||
fakes.stub_out_db_instance_api(self.stubs)
|
fakes.stub_out_db_instance_api(self.stubs)
|
||||||
fake.reset()
|
fake.reset()
|
||||||
self.values = {'name': 1,
|
self.values = {'name': 1, 'id': 1,
|
||||||
'project_id': 'fake',
|
'project_id': 'fake',
|
||||||
'user_id': 'fake',
|
'user_id': 'fake',
|
||||||
'image_id': 1,
|
'image_id': 1,
|
||||||
@@ -167,7 +167,7 @@ class XenAPIVMTestCase(test.TestCase):
|
|||||||
|
|
||||||
def test_spawn(self):
|
def test_spawn(self):
|
||||||
stubs.stubout_session(self.stubs, stubs.FakeSessionForVMTests)
|
stubs.stubout_session(self.stubs, stubs.FakeSessionForVMTests)
|
||||||
values = {'name': 1,
|
values = {'name': 1, 'id': 1,
|
||||||
'project_id': self.project.id,
|
'project_id': self.project.id,
|
||||||
'user_id': self.user.id,
|
'user_id': self.user.id,
|
||||||
'image_id': 1,
|
'image_id': 1,
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ from nova.tests.auth_unittest import *
|
|||||||
from nova.tests.cloud_unittest import *
|
from nova.tests.cloud_unittest import *
|
||||||
from nova.tests.compute_unittest import *
|
from nova.tests.compute_unittest import *
|
||||||
from nova.tests.flags_unittest import *
|
from nova.tests.flags_unittest import *
|
||||||
|
from nova.tests.middleware_unittest import *
|
||||||
from nova.tests.misc_unittest import *
|
from nova.tests.misc_unittest import *
|
||||||
from nova.tests.network_unittest import *
|
from nova.tests.network_unittest import *
|
||||||
#from nova.tests.objectstore_unittest import *
|
#from nova.tests.objectstore_unittest import *
|
||||||
|
|||||||
Reference in New Issue
Block a user