merged trunk
This commit is contained in:
@@ -52,6 +52,7 @@
|
||||
CLI interface for nova management.
|
||||
"""
|
||||
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
@@ -72,6 +73,7 @@ from nova import flags
|
||||
from nova import quota
|
||||
from nova import utils
|
||||
from nova.auth import manager
|
||||
from nova.network import manager as network_manager
|
||||
from nova.cloudpipe import pipelib
|
||||
|
||||
|
||||
@@ -88,11 +90,16 @@ class VpnCommands(object):
|
||||
def list(self):
|
||||
"""Print a listing of the VPNs for all projects."""
|
||||
print "%-12s\t" % 'project',
|
||||
print "%-12s\t" % 'ip:port',
|
||||
print "%-20s\t" % 'ip:port',
|
||||
print "%s" % 'state'
|
||||
for project in self.manager.get_projects():
|
||||
print "%-12s\t" % project.name,
|
||||
print "%s:%s\t" % (project.vpn_ip, project.vpn_port),
|
||||
|
||||
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:
|
||||
@@ -114,7 +121,7 @@ class VpnCommands(object):
|
||||
|
||||
def _vpn_for(self, project_id):
|
||||
"""Get the VPN instance for a project ID."""
|
||||
for instance in db.instance_get_all():
|
||||
for instance in db.instance_get_all(None):
|
||||
if (instance['image_id'] == FLAGS.vpn_image_id
|
||||
and not instance['state_description'] in
|
||||
['shutting_down', 'shutdown']
|
||||
@@ -371,6 +378,29 @@ class FloatingIpCommands(object):
|
||||
floating_ip['address'],
|
||||
instance)
|
||||
|
||||
class NetworkCommands(object):
|
||||
"""Class for managing networks."""
|
||||
|
||||
def create(self, fixed_range=None, num_networks=None,
|
||||
network_size=None, vlan_start=None, vpn_start=None):
|
||||
"""Creates fixed ips for host by range
|
||||
arguments: [fixed_range=FLAG], [num_networks=FLAG],
|
||||
[network_size=FLAG], [vlan_start=FLAG],
|
||||
[vpn_start=FLAG]"""
|
||||
if not fixed_range:
|
||||
fixed_range = FLAGS.fixed_range
|
||||
if not num_networks:
|
||||
num_networks = FLAGS.num_networks
|
||||
if not network_size:
|
||||
network_size = FLAGS.network_size
|
||||
if not vlan_start:
|
||||
vlan_start = FLAGS.vlan_start
|
||||
if not vpn_start:
|
||||
vpn_start = FLAGS.vpn_start
|
||||
net_manager = utils.import_object(FLAGS.network_manager)
|
||||
net_manager.create_networks(None, fixed_range, int(num_networks),
|
||||
int(network_size), int(vlan_start),
|
||||
int(vpn_start))
|
||||
|
||||
CATEGORIES = [
|
||||
('user', UserCommands),
|
||||
@@ -378,7 +408,8 @@ CATEGORIES = [
|
||||
('role', RoleCommands),
|
||||
('shell', ShellCommands),
|
||||
('vpn', VpnCommands),
|
||||
('floating', FloatingIpCommands)
|
||||
('floating', FloatingIpCommands),
|
||||
('network', NetworkCommands)
|
||||
]
|
||||
|
||||
|
||||
@@ -417,6 +448,10 @@ def main():
|
||||
"""Parse options and call the appropriate class/method."""
|
||||
utils.default_flagfile('/etc/nova/nova-manage.conf')
|
||||
argv = FLAGS(sys.argv)
|
||||
|
||||
if FLAGS.verbose:
|
||||
logging.getLogger().setLevel(logging.DEBUG)
|
||||
|
||||
script_name = argv.pop(0)
|
||||
if len(argv) < 1:
|
||||
print script_name + " category action [<args>]"
|
||||
@@ -444,9 +479,9 @@ def main():
|
||||
fn(*argv)
|
||||
sys.exit(0)
|
||||
except TypeError:
|
||||
print "Wrong number of arguments supplied"
|
||||
print "Possible wrong number of arguments supplied"
|
||||
print "%s %s: %s" % (category, action, fn.__doc__)
|
||||
sys.exit(2)
|
||||
raise
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
236
nova/auth/dbdriver.py
Normal file
236
nova/auth/dbdriver.py
Normal file
@@ -0,0 +1,236 @@
|
||||
# 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.
|
||||
|
||||
"""
|
||||
Auth driver using the DB as its backend.
|
||||
"""
|
||||
|
||||
import logging
|
||||
import sys
|
||||
|
||||
from nova import exception
|
||||
from nova import db
|
||||
|
||||
|
||||
class DbDriver(object):
|
||||
"""DB Auth driver
|
||||
|
||||
Defines enter and exit and therefore supports the with/as syntax.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
"""Imports the LDAP module"""
|
||||
pass
|
||||
db
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc_value, traceback):
|
||||
pass
|
||||
|
||||
def get_user(self, uid):
|
||||
"""Retrieve user by id"""
|
||||
return self._db_user_to_auth_user(db.user_get({}, uid))
|
||||
|
||||
def get_user_from_access_key(self, access):
|
||||
"""Retrieve user by access key"""
|
||||
return self._db_user_to_auth_user(db.user_get_by_access_key({}, access))
|
||||
|
||||
def get_project(self, pid):
|
||||
"""Retrieve project by id"""
|
||||
return self._db_project_to_auth_projectuser(db.project_get({}, pid))
|
||||
|
||||
def get_users(self):
|
||||
"""Retrieve list of users"""
|
||||
return [self._db_user_to_auth_user(user) for user in db.user_get_all({})]
|
||||
|
||||
def get_projects(self, uid=None):
|
||||
"""Retrieve list of projects"""
|
||||
if uid:
|
||||
result = db.project_get_by_user({}, uid)
|
||||
else:
|
||||
result = db.project_get_all({})
|
||||
return [self._db_project_to_auth_projectuser(proj) for proj in result]
|
||||
|
||||
def create_user(self, name, access_key, secret_key, is_admin):
|
||||
"""Create a user"""
|
||||
values = { 'id' : name,
|
||||
'access_key' : access_key,
|
||||
'secret_key' : secret_key,
|
||||
'is_admin' : is_admin
|
||||
}
|
||||
try:
|
||||
user_ref = db.user_create({}, values)
|
||||
return self._db_user_to_auth_user(user_ref)
|
||||
except exception.Duplicate, e:
|
||||
raise exception.Duplicate('User %s already exists' % name)
|
||||
|
||||
def _db_user_to_auth_user(self, user_ref):
|
||||
return { 'id' : user_ref['id'],
|
||||
'name' : user_ref['id'],
|
||||
'access' : user_ref['access_key'],
|
||||
'secret' : user_ref['secret_key'],
|
||||
'admin' : user_ref['is_admin'] }
|
||||
|
||||
def _db_project_to_auth_projectuser(self, project_ref):
|
||||
return { 'id' : project_ref['id'],
|
||||
'name' : project_ref['name'],
|
||||
'project_manager_id' : project_ref['project_manager'],
|
||||
'description' : project_ref['description'],
|
||||
'member_ids' : [member['id'] for member in project_ref['members']] }
|
||||
|
||||
def create_project(self, name, manager_uid,
|
||||
description=None, member_uids=None):
|
||||
"""Create a project"""
|
||||
manager = db.user_get({}, manager_uid)
|
||||
if not manager:
|
||||
raise exception.NotFound("Project can't be created because "
|
||||
"manager %s doesn't exist" % manager_uid)
|
||||
|
||||
# description is a required attribute
|
||||
if description is None:
|
||||
description = name
|
||||
|
||||
# First, we ensure that all the given users exist before we go
|
||||
# on to create the project. This way we won't have to destroy
|
||||
# the project again because a user turns out to be invalid.
|
||||
members = set([manager])
|
||||
if member_uids != None:
|
||||
for member_uid in member_uids:
|
||||
member = db.user_get({}, member_uid)
|
||||
if not member:
|
||||
raise exception.NotFound("Project can't be created "
|
||||
"because user %s doesn't exist"
|
||||
% member_uid)
|
||||
members.add(member)
|
||||
|
||||
values = { 'id' : name,
|
||||
'name' : name,
|
||||
'project_manager' : manager['id'],
|
||||
'description': description }
|
||||
|
||||
try:
|
||||
project = db.project_create({}, values)
|
||||
except exception.Duplicate:
|
||||
raise exception.Duplicate("Project can't be created because "
|
||||
"project %s already exists" % name)
|
||||
|
||||
for member in members:
|
||||
db.project_add_member({}, project['id'], member['id'])
|
||||
|
||||
# This looks silly, but ensures that the members element has been
|
||||
# correctly populated
|
||||
project_ref = db.project_get({}, project['id'])
|
||||
return self._db_project_to_auth_projectuser(project_ref)
|
||||
|
||||
def modify_project(self, project_id, manager_uid=None, description=None):
|
||||
"""Modify an existing project"""
|
||||
if not manager_uid and not description:
|
||||
return
|
||||
values = {}
|
||||
if manager_uid:
|
||||
manager = db.user_get({}, manager_uid)
|
||||
if not manager:
|
||||
raise exception.NotFound("Project can't be modified because "
|
||||
"manager %s doesn't exist" %
|
||||
manager_uid)
|
||||
values['project_manager'] = manager['id']
|
||||
if description:
|
||||
values['description'] = description
|
||||
|
||||
db.project_update({}, project_id, values)
|
||||
|
||||
def add_to_project(self, uid, project_id):
|
||||
"""Add user to project"""
|
||||
user, project = self._validate_user_and_project(uid, project_id)
|
||||
db.project_add_member({}, project['id'], user['id'])
|
||||
|
||||
def remove_from_project(self, uid, project_id):
|
||||
"""Remove user from project"""
|
||||
user, project = self._validate_user_and_project(uid, project_id)
|
||||
db.project_remove_member({}, project['id'], user['id'])
|
||||
|
||||
def is_in_project(self, uid, project_id):
|
||||
"""Check if user is in project"""
|
||||
user, project = self._validate_user_and_project(uid, project_id)
|
||||
return user in project.members
|
||||
|
||||
def has_role(self, uid, role, project_id=None):
|
||||
"""Check if user has role
|
||||
|
||||
If project is specified, it checks for local role, otherwise it
|
||||
checks for global role
|
||||
"""
|
||||
|
||||
return role in self.get_user_roles(uid, project_id)
|
||||
|
||||
def add_role(self, uid, role, project_id=None):
|
||||
"""Add role for user (or user and project)"""
|
||||
if not project_id:
|
||||
db.user_add_role({}, uid, role)
|
||||
return
|
||||
db.user_add_project_role({}, uid, project_id, role)
|
||||
|
||||
def remove_role(self, uid, role, project_id=None):
|
||||
"""Remove role for user (or user and project)"""
|
||||
if not project_id:
|
||||
db.user_remove_role({}, uid, role)
|
||||
return
|
||||
db.user_remove_project_role({}, uid, project_id, role)
|
||||
|
||||
def get_user_roles(self, uid, project_id=None):
|
||||
"""Retrieve list of roles for user (or user and project)"""
|
||||
if project_id is None:
|
||||
roles = db.user_get_roles({}, uid)
|
||||
return roles
|
||||
else:
|
||||
roles = db.user_get_roles_for_project({}, uid, project_id)
|
||||
return roles
|
||||
|
||||
def delete_user(self, id):
|
||||
"""Delete a user"""
|
||||
user = db.user_get({}, id)
|
||||
db.user_delete({}, user['id'])
|
||||
|
||||
def delete_project(self, project_id):
|
||||
"""Delete a project"""
|
||||
db.project_delete({}, project_id)
|
||||
|
||||
def modify_user(self, uid, access_key=None, secret_key=None, admin=None):
|
||||
"""Modify an existing user"""
|
||||
if not access_key and not secret_key and admin is None:
|
||||
return
|
||||
values = {}
|
||||
if access_key:
|
||||
values['access_key'] = access_key
|
||||
if secret_key:
|
||||
values['secret_key'] = secret_key
|
||||
if admin is not None:
|
||||
values['is_admin'] = admin
|
||||
db.user_update({}, uid, values)
|
||||
|
||||
def _validate_user_and_project(self, user_id, project_id):
|
||||
user = db.user_get({}, user_id)
|
||||
if not user:
|
||||
raise exception.NotFound('User "%s" not found' % user_id)
|
||||
project = db.project_get({}, project_id)
|
||||
if not project:
|
||||
raise exception.NotFound('Project "%s" not found' % project_id)
|
||||
return user, project
|
||||
|
@@ -70,7 +70,7 @@ 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('auth_driver', 'nova.auth.ldapdriver.FakeLdapDriver',
|
||||
flags.DEFINE_string('auth_driver', 'nova.auth.dbdriver.DbDriver',
|
||||
'Driver that auth manager uses')
|
||||
|
||||
|
||||
@@ -485,13 +485,6 @@ class AuthManager(object):
|
||||
member_users)
|
||||
if project_dict:
|
||||
project = Project(**project_dict)
|
||||
try:
|
||||
ctxt = context.get_admin_context()
|
||||
self.network_manager.allocate_network(ctxt,
|
||||
project.id)
|
||||
except:
|
||||
drv.delete_project(project.id)
|
||||
raise
|
||||
return project
|
||||
|
||||
def modify_project(self, project, manager_user=None, description=None):
|
||||
@@ -560,14 +553,6 @@ class AuthManager(object):
|
||||
|
||||
def delete_project(self, project):
|
||||
"""Deletes a project"""
|
||||
try:
|
||||
ctxt = context.get_admin_context()
|
||||
network_ref = db.project_get_network(ctxt,
|
||||
Project.safe_id(project))
|
||||
db.network_destroy(ctxt, network_ref['id'])
|
||||
except:
|
||||
logging.exception('Could not destroy network for %s',
|
||||
project)
|
||||
with self.driver() as drv:
|
||||
drv.delete_project(Project.safe_id(project))
|
||||
|
||||
@@ -657,7 +642,10 @@ class AuthManager(object):
|
||||
zippy.writestr(FLAGS.credential_key_file, private_key)
|
||||
zippy.writestr(FLAGS.credential_cert_file, signed_cert)
|
||||
|
||||
(vpn_ip, vpn_port) = self.get_project_vpn_data(project)
|
||||
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())
|
||||
|
@@ -22,6 +22,7 @@ import logging
|
||||
import Queue as queue
|
||||
|
||||
from carrot.backends import base
|
||||
from eventlet import greenthread
|
||||
|
||||
|
||||
class Message(base.BaseMessage):
|
||||
@@ -38,6 +39,7 @@ class Exchange(object):
|
||||
def publish(self, message, routing_key=None):
|
||||
logging.debug('(%s) publish (key: %s) %s',
|
||||
self.name, routing_key, message)
|
||||
routing_key = routing_key.split('.')[0]
|
||||
if routing_key in self._routes:
|
||||
for f in self._routes[routing_key]:
|
||||
logging.debug('Publishing to route %s', f)
|
||||
@@ -94,6 +96,18 @@ class Backend(object):
|
||||
self._exchanges[exchange].bind(self._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):
|
||||
while True:
|
||||
item = self.get(self.current_queue)
|
||||
if item:
|
||||
self.current_callback(item)
|
||||
raise StopIteration()
|
||||
greenthread.sleep(0)
|
||||
|
||||
def get(self, queue, no_ack=False):
|
||||
if not queue in self._queues or not self._queues[queue].size():
|
||||
return None
|
||||
@@ -102,6 +116,7 @@ class Backend(object):
|
||||
message = Message(backend=self, body=message_data,
|
||||
content_type=content_type,
|
||||
content_encoding=content_encoding)
|
||||
message.result = True
|
||||
logging.debug('Getting from %s: %s', queue, message)
|
||||
return message
|
||||
|
||||
|
@@ -222,6 +222,10 @@ DEFINE_string('volume_manager', 'nova.volume.manager.AOEManager',
|
||||
DEFINE_string('scheduler_manager', 'nova.scheduler.manager.SchedulerManager',
|
||||
'Manager for scheduler')
|
||||
|
||||
# The service to use for image search and retrieval
|
||||
DEFINE_string('image_service', 'nova.image.service.LocalImageService',
|
||||
'The service to use for retrieving and searching for images.')
|
||||
|
||||
DEFINE_string('host', socket.gethostname(),
|
||||
'name of this node')
|
||||
|
||||
|
@@ -113,7 +113,7 @@ class BackRelayWithInput(protocol.ProcessProtocol):
|
||||
if self.started_deferred:
|
||||
self.started_deferred.callback(self)
|
||||
if self.process_input:
|
||||
self.transport.write(self.process_input)
|
||||
self.transport.write(str(self.process_input))
|
||||
self.transport.closeStdin()
|
||||
|
||||
def get_process_output(executable, args=None, env=None, path=None,
|
||||
|
@@ -28,6 +28,7 @@ import uuid
|
||||
|
||||
from carrot import connection as carrot_connection
|
||||
from carrot import messaging
|
||||
from eventlet import greenthread
|
||||
from twisted.internet import defer
|
||||
from twisted.internet import task
|
||||
|
||||
@@ -107,6 +108,14 @@ class Consumer(messaging.Consumer):
|
||||
logging.exception("Failed to fetch message from queue")
|
||||
self.failed_connection = True
|
||||
|
||||
def attach_to_eventlet(self):
|
||||
"""Only needed for unit tests!"""
|
||||
def fetch_repeatedly():
|
||||
while True:
|
||||
self.fetch(enable_callbacks=True)
|
||||
greenthread.sleep(0.1)
|
||||
greenthread.spawn(fetch_repeatedly)
|
||||
|
||||
def attach_to_twisted(self):
|
||||
"""Attach a callback to twisted that fires 10 times a second"""
|
||||
loop = task.LoopingCall(self.fetch, enable_callbacks=True)
|
||||
|
@@ -106,6 +106,7 @@ def serve(name, main):
|
||||
def daemonize(args, name, main):
|
||||
"""Does the work of daemonizing the process"""
|
||||
logging.getLogger('amqplib').setLevel(logging.WARN)
|
||||
files_to_keep = []
|
||||
if FLAGS.daemonize:
|
||||
logger = logging.getLogger()
|
||||
formatter = logging.Formatter(
|
||||
@@ -114,12 +115,14 @@ def daemonize(args, name, main):
|
||||
syslog = logging.handlers.SysLogHandler(address='/dev/log')
|
||||
syslog.setFormatter(formatter)
|
||||
logger.addHandler(syslog)
|
||||
files_to_keep.append(syslog.socket)
|
||||
else:
|
||||
if not FLAGS.logfile:
|
||||
FLAGS.logfile = '%s.log' % name
|
||||
logfile = logging.FileHandler(FLAGS.logfile)
|
||||
logfile.setFormatter(formatter)
|
||||
logger.addHandler(logfile)
|
||||
files_to_keep.append(logfile.stream)
|
||||
stdin, stdout, stderr = None, None, None
|
||||
else:
|
||||
stdin, stdout, stderr = sys.stdin, sys.stdout, sys.stderr
|
||||
@@ -139,6 +142,7 @@ def daemonize(args, name, main):
|
||||
stdout=stdout,
|
||||
stderr=stderr,
|
||||
uid=FLAGS.uid,
|
||||
gid=FLAGS.gid
|
||||
gid=FLAGS.gid,
|
||||
files_preserve=files_to_keep
|
||||
):
|
||||
main(args)
|
||||
|
@@ -92,6 +92,9 @@ class ApiEc2TestCase(test.BaseTestCase):
|
||||
self.host = '127.0.0.1'
|
||||
|
||||
self.app = api.API()
|
||||
|
||||
def expect_http(self, host=None, is_secure=False):
|
||||
"""Returns a new EC2 connection"""
|
||||
self.ec2 = boto.connect_ec2(
|
||||
aws_access_key_id='fake',
|
||||
aws_secret_access_key='fake',
|
||||
@@ -101,9 +104,6 @@ class ApiEc2TestCase(test.BaseTestCase):
|
||||
path='/services/Cloud')
|
||||
|
||||
self.mox.StubOutWithMock(self.ec2, 'new_http_connection')
|
||||
|
||||
def expect_http(self, host=None, is_secure=False):
|
||||
"""Returns a new EC2 connection"""
|
||||
http = FakeHttplibConnection(
|
||||
self.app, '%s:8773' % (self.host), False)
|
||||
# pylint: disable-msg=E1103
|
||||
@@ -139,3 +139,185 @@ class ApiEc2TestCase(test.BaseTestCase):
|
||||
self.assertEquals(len(results), 1)
|
||||
self.manager.delete_project(project)
|
||||
self.manager.delete_user(user)
|
||||
|
||||
def test_get_all_security_groups(self):
|
||||
"""Test that we can retrieve security groups"""
|
||||
self.expect_http()
|
||||
self.mox.ReplayAll()
|
||||
user = self.manager.create_user('fake', 'fake', 'fake', admin=True)
|
||||
project = self.manager.create_project('fake', 'fake', 'fake')
|
||||
|
||||
rv = self.ec2.get_all_security_groups()
|
||||
|
||||
self.assertEquals(len(rv), 1)
|
||||
self.assertEquals(rv[0].name, 'default')
|
||||
|
||||
self.manager.delete_project(project)
|
||||
self.manager.delete_user(user)
|
||||
|
||||
def test_create_delete_security_group(self):
|
||||
"""Test that we can create a security group"""
|
||||
self.expect_http()
|
||||
self.mox.ReplayAll()
|
||||
user = self.manager.create_user('fake', 'fake', 'fake', admin=True)
|
||||
project = self.manager.create_project('fake', 'fake', 'fake')
|
||||
|
||||
# At the moment, you need both of these to actually be netadmin
|
||||
self.manager.add_role('fake', 'netadmin')
|
||||
project.add_role('fake', 'netadmin')
|
||||
|
||||
security_group_name = "".join(random.choice("sdiuisudfsdcnpaqwertasd") \
|
||||
for x in range(random.randint(4, 8)))
|
||||
|
||||
self.ec2.create_security_group(security_group_name, 'test group')
|
||||
|
||||
self.expect_http()
|
||||
self.mox.ReplayAll()
|
||||
|
||||
rv = self.ec2.get_all_security_groups()
|
||||
self.assertEquals(len(rv), 2)
|
||||
self.assertTrue(security_group_name in [group.name for group in rv])
|
||||
|
||||
self.expect_http()
|
||||
self.mox.ReplayAll()
|
||||
|
||||
self.ec2.delete_security_group(security_group_name)
|
||||
|
||||
self.manager.delete_project(project)
|
||||
self.manager.delete_user(user)
|
||||
|
||||
def test_authorize_revoke_security_group_cidr(self):
|
||||
"""
|
||||
Test that we can add and remove CIDR based rules
|
||||
to a security group
|
||||
"""
|
||||
self.expect_http()
|
||||
self.mox.ReplayAll()
|
||||
user = self.manager.create_user('fake', 'fake', 'fake')
|
||||
project = self.manager.create_project('fake', 'fake', 'fake')
|
||||
|
||||
# At the moment, you need both of these to actually be netadmin
|
||||
self.manager.add_role('fake', 'netadmin')
|
||||
project.add_role('fake', 'netadmin')
|
||||
|
||||
security_group_name = "".join(random.choice("sdiuisudfsdcnpaqwertasd") \
|
||||
for x in range(random.randint(4, 8)))
|
||||
|
||||
group = self.ec2.create_security_group(security_group_name, 'test group')
|
||||
|
||||
self.expect_http()
|
||||
self.mox.ReplayAll()
|
||||
group.connection = self.ec2
|
||||
|
||||
group.authorize('tcp', 80, 81, '0.0.0.0/0')
|
||||
|
||||
self.expect_http()
|
||||
self.mox.ReplayAll()
|
||||
|
||||
rv = self.ec2.get_all_security_groups()
|
||||
# I don't bother checkng that we actually find it here,
|
||||
# because the create/delete unit test further up should
|
||||
# be good enough for that.
|
||||
for group in rv:
|
||||
if group.name == security_group_name:
|
||||
self.assertEquals(len(group.rules), 1)
|
||||
self.assertEquals(int(group.rules[0].from_port), 80)
|
||||
self.assertEquals(int(group.rules[0].to_port), 81)
|
||||
self.assertEquals(len(group.rules[0].grants), 1)
|
||||
self.assertEquals(str(group.rules[0].grants[0]), '0.0.0.0/0')
|
||||
|
||||
self.expect_http()
|
||||
self.mox.ReplayAll()
|
||||
group.connection = self.ec2
|
||||
|
||||
group.revoke('tcp', 80, 81, '0.0.0.0/0')
|
||||
|
||||
self.expect_http()
|
||||
self.mox.ReplayAll()
|
||||
|
||||
self.ec2.delete_security_group(security_group_name)
|
||||
|
||||
self.expect_http()
|
||||
self.mox.ReplayAll()
|
||||
group.connection = self.ec2
|
||||
|
||||
rv = self.ec2.get_all_security_groups()
|
||||
|
||||
self.assertEqual(len(rv), 1)
|
||||
self.assertEqual(rv[0].name, 'default')
|
||||
|
||||
self.manager.delete_project(project)
|
||||
self.manager.delete_user(user)
|
||||
|
||||
return
|
||||
|
||||
def test_authorize_revoke_security_group_foreign_group(self):
|
||||
"""
|
||||
Test that we can grant and revoke another security group access
|
||||
to a security group
|
||||
"""
|
||||
self.expect_http()
|
||||
self.mox.ReplayAll()
|
||||
user = self.manager.create_user('fake', 'fake', 'fake', admin=True)
|
||||
project = self.manager.create_project('fake', 'fake', 'fake')
|
||||
|
||||
# At the moment, you need both of these to actually be netadmin
|
||||
self.manager.add_role('fake', 'netadmin')
|
||||
project.add_role('fake', 'netadmin')
|
||||
|
||||
security_group_name = "".join(random.choice("sdiuisudfsdcnpaqwertasd") \
|
||||
for x in range(random.randint(4, 8)))
|
||||
other_security_group_name = "".join(random.choice("sdiuisudfsdcnpaqwertasd") \
|
||||
for x in range(random.randint(4, 8)))
|
||||
|
||||
group = self.ec2.create_security_group(security_group_name, 'test group')
|
||||
|
||||
self.expect_http()
|
||||
self.mox.ReplayAll()
|
||||
|
||||
other_group = self.ec2.create_security_group(other_security_group_name,
|
||||
'some other group')
|
||||
|
||||
self.expect_http()
|
||||
self.mox.ReplayAll()
|
||||
group.connection = self.ec2
|
||||
|
||||
group.authorize(src_group=other_group)
|
||||
|
||||
self.expect_http()
|
||||
self.mox.ReplayAll()
|
||||
|
||||
rv = self.ec2.get_all_security_groups()
|
||||
|
||||
# I don't bother checkng that we actually find it here,
|
||||
# because the create/delete unit test further up should
|
||||
# be good enough for that.
|
||||
for group in rv:
|
||||
if group.name == security_group_name:
|
||||
self.assertEquals(len(group.rules), 1)
|
||||
self.assertEquals(len(group.rules[0].grants), 1)
|
||||
self.assertEquals(str(group.rules[0].grants[0]),
|
||||
'%s-%s' % (other_security_group_name, 'fake'))
|
||||
|
||||
|
||||
self.expect_http()
|
||||
self.mox.ReplayAll()
|
||||
|
||||
rv = self.ec2.get_all_security_groups()
|
||||
|
||||
for group in rv:
|
||||
if group.name == security_group_name:
|
||||
self.expect_http()
|
||||
self.mox.ReplayAll()
|
||||
group.connection = self.ec2
|
||||
group.revoke(src_group=other_group)
|
||||
|
||||
self.expect_http()
|
||||
self.mox.ReplayAll()
|
||||
|
||||
self.ec2.delete_security_group(security_group_name)
|
||||
|
||||
self.manager.delete_project(project)
|
||||
self.manager.delete_user(user)
|
||||
|
||||
return
|
||||
|
@@ -75,8 +75,9 @@ class user_and_project_generator(object):
|
||||
self.manager.delete_user(self.user)
|
||||
self.manager.delete_project(self.project)
|
||||
|
||||
class AuthManagerTestCase(test.TrialTestCase):
|
||||
class AuthManagerTestCase(object):
|
||||
def setUp(self):
|
||||
FLAGS.auth_driver = self.auth_driver
|
||||
super(AuthManagerTestCase, self).setUp()
|
||||
self.flags(connection_type='fake')
|
||||
self.manager = manager.AuthManager()
|
||||
@@ -320,6 +321,12 @@ class AuthManagerTestCase(test.TrialTestCase):
|
||||
self.assertEqual('secret', user.secret)
|
||||
self.assertTrue(user.is_admin())
|
||||
|
||||
class AuthManagerLdapTestCase(AuthManagerTestCase, test.TrialTestCase):
|
||||
auth_driver = 'nova.auth.ldapdriver.FakeLdapDriver'
|
||||
|
||||
class AuthManagerDbTestCase(AuthManagerTestCase, test.TrialTestCase):
|
||||
auth_driver = 'nova.auth.dbdriver.DbDriver'
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# TODO: Implement use_fake as an option
|
||||
|
@@ -16,6 +16,7 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from base64 import b64decode
|
||||
import json
|
||||
import logging
|
||||
from M2Crypto import BIO
|
||||
@@ -63,11 +64,16 @@ class CloudTestCase(test.TrialTestCase):
|
||||
self.cloud = cloud.CloudController()
|
||||
|
||||
# set up a service
|
||||
self.compute = utils.import_class(FLAGS.compute_manager)
|
||||
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_twisted()
|
||||
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.user = self.manager.create_user('admin', 'admin', 'admin', True)
|
||||
@@ -85,15 +91,17 @@ class CloudTestCase(test.TrialTestCase):
|
||||
return cloud._gen_key(self.context, self.context.user.id, name)
|
||||
|
||||
def test_console_output(self):
|
||||
if FLAGS.connection_type == 'fake':
|
||||
logging.debug("Can't test instances without a real virtual env.")
|
||||
return
|
||||
instance_id = 'foo'
|
||||
inst = yield self.compute.run_instance(instance_id)
|
||||
output = yield self.cloud.get_console_output(self.context, [instance_id])
|
||||
logging.debug(output)
|
||||
self.assert_(output)
|
||||
rv = yield self.compute.terminate_instance(instance_id)
|
||||
image_id = FLAGS.default_image
|
||||
instance_type = FLAGS.default_instance_type
|
||||
max_count = 1
|
||||
kwargs = {'image_id': image_id,
|
||||
'instance_type': instance_type,
|
||||
'max_count': max_count }
|
||||
rv = yield self.cloud.run_instances(self.context, **kwargs)
|
||||
instance_id = rv['instancesSet'][0]['instanceId']
|
||||
output = yield self.cloud.get_console_output(context=self.context, instance_id=[instance_id])
|
||||
self.assertEquals(b64decode(output['output']), 'FAKE CONSOLE OUTPUT')
|
||||
rv = yield self.cloud.terminate_instances(self.context, [instance_id])
|
||||
|
||||
|
||||
def test_key_generation(self):
|
||||
@@ -236,7 +244,8 @@ class CloudTestCase(test.TrialTestCase):
|
||||
|
||||
def test_update_of_instance_display_fields(self):
|
||||
inst = db.instance_create(self.context, {})
|
||||
self.cloud.update_instance(self.context, inst['ec2_id'],
|
||||
ec2_id = cloud.internal_id_to_ec2_id(inst['internal_id'])
|
||||
self.cloud.update_instance(self.context, ec2_id,
|
||||
display_name='c00l 1m4g3')
|
||||
inst = db.instance_get(self.context, inst['id'])
|
||||
self.assertEqual('c00l 1m4g3', inst['display_name'])
|
||||
|
@@ -40,7 +40,8 @@ class ComputeTestCase(test.TrialTestCase):
|
||||
def setUp(self): # pylint: disable-msg=C0103
|
||||
logging.getLogger().setLevel(logging.DEBUG)
|
||||
super(ComputeTestCase, self).setUp()
|
||||
self.flags(connection_type='fake')
|
||||
self.flags(connection_type='fake',
|
||||
network_manager='nova.network.manager.FlatManager')
|
||||
self.compute = utils.import_object(FLAGS.compute_manager)
|
||||
self.manager = manager.AuthManager()
|
||||
self.user = self.manager.create_user('fake', 'fake', 'fake')
|
||||
|
@@ -24,7 +24,7 @@ flags.DECLARE('volume_driver', 'nova.volume.manager')
|
||||
FLAGS.volume_driver = 'nova.volume.driver.FakeAOEDriver'
|
||||
FLAGS.connection_type = 'fake'
|
||||
FLAGS.fake_rabbit = True
|
||||
FLAGS.auth_driver = 'nova.auth.ldapdriver.FakeLdapDriver'
|
||||
FLAGS.auth_driver = 'nova.auth.dbdriver.DbDriver'
|
||||
flags.DECLARE('network_size', 'nova.network.manager')
|
||||
flags.DECLARE('num_networks', 'nova.network.manager')
|
||||
flags.DECLARE('fake_network', 'nova.network.manager')
|
||||
|
@@ -52,11 +52,14 @@ class NetworkTestCase(test.TrialTestCase):
|
||||
self.context = context.RequestContext(project=None, user=self.user)
|
||||
for i in range(5):
|
||||
name = 'project%s' % i
|
||||
self.projects.append(self.manager.create_project(name,
|
||||
'netuser',
|
||||
name))
|
||||
project = self.manager.create_project(name, 'netuser', name)
|
||||
self.projects.append(project)
|
||||
# create the necessary network data for the project
|
||||
self.network.set_network_host(context.get_admin_context(), self.projects[i].id)
|
||||
user_context = context.APIRequestContext(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'])
|
||||
instance_ref = self._create_instance(0)
|
||||
self.instance_id = instance_ref['id']
|
||||
instance_ref = self._create_instance(1)
|
||||
@@ -97,7 +100,7 @@ class NetworkTestCase(test.TrialTestCase):
|
||||
"""Makes sure that we can allocaate a public ip"""
|
||||
# TODO(vish): better way of adding floating ips
|
||||
self.context._project = self.projects[0]
|
||||
pubnet = IPy.IP(flags.FLAGS.public_range)
|
||||
pubnet = IPy.IP(flags.FLAGS.floating_range)
|
||||
address = str(pubnet[0])
|
||||
try:
|
||||
db.floating_ip_get_by_address(context.get_admin_context(), address)
|
||||
@@ -107,6 +110,7 @@ class NetworkTestCase(test.TrialTestCase):
|
||||
float_addr = self.network.allocate_floating_ip(self.context,
|
||||
self.projects[0].id)
|
||||
fix_addr = self._create_address(0)
|
||||
lease_ip(fix_addr)
|
||||
self.assertEqual(float_addr, str(pubnet[0]))
|
||||
self.network.associate_floating_ip(self.context, float_addr, fix_addr)
|
||||
address = db.instance_get_floating_address(context.get_admin_context(), self.instance_id)
|
||||
@@ -116,6 +120,7 @@ class NetworkTestCase(test.TrialTestCase):
|
||||
self.assertEqual(address, None)
|
||||
self.network.deallocate_floating_ip(self.context, float_addr)
|
||||
self.network.deallocate_fixed_ip(self.context, fix_addr)
|
||||
release_ip(fix_addr)
|
||||
|
||||
def test_allocate_deallocate_fixed_ip(self):
|
||||
"""Makes sure that we can allocate and deallocate a fixed ip"""
|
||||
@@ -188,8 +193,10 @@ class NetworkTestCase(test.TrialTestCase):
|
||||
release_ip(address3)
|
||||
for instance_id in instance_ids:
|
||||
db.instance_destroy(context.get_admin_context(), instance_id)
|
||||
release_ip(first)
|
||||
self.context._project = self.projects[0]
|
||||
self.network.deallocate_fixed_ip(self.context, first)
|
||||
self._deallocate_address(0, first)
|
||||
release_ip(first)
|
||||
|
||||
def test_vpn_ip_and_port_looks_valid(self):
|
||||
"""Ensure the vpn ip and port are reasonable"""
|
||||
@@ -205,10 +212,13 @@ class NetworkTestCase(test.TrialTestCase):
|
||||
for i in range(networks_left):
|
||||
project = self.manager.create_project('many%s' % i, self.user)
|
||||
projects.append(project)
|
||||
db.project_get_network(None, project.id)
|
||||
project = self.manager.create_project('last', self.user)
|
||||
projects.append(project)
|
||||
self.assertRaises(db.NoMoreNetworks,
|
||||
self.manager.create_project,
|
||||
'boom',
|
||||
self.user)
|
||||
db.project_get_network,
|
||||
None,
|
||||
project.id)
|
||||
for project in projects:
|
||||
self.manager.delete_project(project)
|
||||
|
||||
@@ -221,7 +231,9 @@ class NetworkTestCase(test.TrialTestCase):
|
||||
|
||||
address2 = self._create_address(0)
|
||||
self.assertEqual(address, address2)
|
||||
lease_ip(address)
|
||||
self.network.deallocate_fixed_ip(self.context, address2)
|
||||
release_ip(address)
|
||||
|
||||
def test_available_ips(self):
|
||||
"""Make sure the number of available ips for the network is correct
|
||||
|
@@ -133,13 +133,22 @@ class ObjectStoreTestCase(test.TrialTestCase):
|
||||
self.assertRaises(NotFound, objectstore.bucket.Bucket, 'new_bucket')
|
||||
|
||||
def test_images(self):
|
||||
self.do_test_images('1mb.manifest.xml', True,
|
||||
'image_bucket1', 'i-testing1')
|
||||
|
||||
def test_images_no_kernel_or_ramdisk(self):
|
||||
self.do_test_images('1mb.no_kernel_or_ramdisk.manifest.xml',
|
||||
False, 'image_bucket2', 'i-testing2')
|
||||
|
||||
def do_test_images(self, manifest_file, expect_kernel_and_ramdisk,
|
||||
image_bucket, image_name):
|
||||
"Test the image API."
|
||||
self.context.user = self.auth_manager.get_user('user1')
|
||||
self.context.project = self.auth_manager.get_project('proj1')
|
||||
|
||||
# create a bucket for our bundle
|
||||
objectstore.bucket.Bucket.create('image_bucket', self.context)
|
||||
bucket = objectstore.bucket.Bucket('image_bucket')
|
||||
objectstore.bucket.Bucket.create(image_bucket, self.context)
|
||||
bucket = objectstore.bucket.Bucket(image_bucket)
|
||||
|
||||
# upload an image manifest/parts
|
||||
bundle_path = os.path.join(os.path.dirname(__file__), 'bundle')
|
||||
@@ -147,18 +156,28 @@ class ObjectStoreTestCase(test.TrialTestCase):
|
||||
bucket[os.path.basename(path)] = open(path, 'rb').read()
|
||||
|
||||
# register an image
|
||||
image.Image.register_aws_image('i-testing',
|
||||
'image_bucket/1mb.manifest.xml',
|
||||
image.Image.register_aws_image(image_name,
|
||||
'%s/%s' % (image_bucket, manifest_file),
|
||||
self.context)
|
||||
|
||||
# verify image
|
||||
my_img = image.Image('i-testing')
|
||||
my_img = image.Image(image_name)
|
||||
result_image_file = os.path.join(my_img.path, 'image')
|
||||
self.assertEqual(os.stat(result_image_file).st_size, 1048576)
|
||||
|
||||
sha = hashlib.sha1(open(result_image_file).read()).hexdigest()
|
||||
self.assertEqual(sha, '3b71f43ff30f4b15b5cd85dd9e95ebc7e84eb5a3')
|
||||
|
||||
if expect_kernel_and_ramdisk:
|
||||
# Verify the default kernel and ramdisk are set
|
||||
self.assertEqual(my_img.metadata['kernelId'], 'aki-test')
|
||||
self.assertEqual(my_img.metadata['ramdiskId'], 'ari-test')
|
||||
else:
|
||||
# Verify that the default kernel and ramdisk (the one from FLAGS)
|
||||
# doesn't get embedded in the metadata
|
||||
self.assertFalse('kernelId' in my_img.metadata)
|
||||
self.assertFalse('ramdiskId' in my_img.metadata)
|
||||
|
||||
# verify image permissions
|
||||
self.context.user = self.auth_manager.get_user('user2')
|
||||
self.context.project = self.auth_manager.get_project('proj2')
|
||||
@@ -191,7 +210,7 @@ class S3APITestCase(test.TrialTestCase):
|
||||
"""Setup users, projects, and start a test server."""
|
||||
super(S3APITestCase, self).setUp()
|
||||
|
||||
FLAGS.auth_driver = 'nova.auth.ldapdriver.FakeLdapDriver',
|
||||
FLAGS.auth_driver = 'nova.auth.ldapdriver.FakeLdapDriver'
|
||||
FLAGS.buckets_path = os.path.join(OSS_TEMPDIR, 'buckets')
|
||||
|
||||
self.auth_manager = manager.AuthManager()
|
||||
|
@@ -78,6 +78,7 @@ class SimpleDriverTestCase(test.TrialTestCase):
|
||||
self.flags(connection_type='fake',
|
||||
max_cores=4,
|
||||
max_gigabytes=4,
|
||||
network_manager='nova.network.manager.FlatManager',
|
||||
volume_driver='nova.volume.driver.FakeAOEDriver',
|
||||
scheduler_driver='nova.scheduler.simple.SimpleScheduler')
|
||||
self.scheduler = manager.SchedulerManager()
|
||||
@@ -119,10 +120,12 @@ class SimpleDriverTestCase(test.TrialTestCase):
|
||||
'nova-compute',
|
||||
'compute',
|
||||
FLAGS.compute_manager)
|
||||
compute1.startService()
|
||||
compute2 = service.Service('host2',
|
||||
'nova-compute',
|
||||
'compute',
|
||||
FLAGS.compute_manager)
|
||||
compute2.startService()
|
||||
hosts = self.scheduler.driver.hosts_up(self.context, 'compute')
|
||||
self.assertEqual(len(hosts), 2)
|
||||
compute1.kill()
|
||||
@@ -134,10 +137,12 @@ class SimpleDriverTestCase(test.TrialTestCase):
|
||||
'nova-compute',
|
||||
'compute',
|
||||
FLAGS.compute_manager)
|
||||
compute1.startService()
|
||||
compute2 = service.Service('host2',
|
||||
'nova-compute',
|
||||
'compute',
|
||||
FLAGS.compute_manager)
|
||||
compute2.startService()
|
||||
instance_id1 = self._create_instance()
|
||||
compute1.run_instance(self.context, instance_id1)
|
||||
instance_id2 = self._create_instance()
|
||||
@@ -155,10 +160,12 @@ class SimpleDriverTestCase(test.TrialTestCase):
|
||||
'nova-compute',
|
||||
'compute',
|
||||
FLAGS.compute_manager)
|
||||
compute1.startService()
|
||||
compute2 = service.Service('host2',
|
||||
'nova-compute',
|
||||
'compute',
|
||||
FLAGS.compute_manager)
|
||||
compute2.startService()
|
||||
instance_ids1 = []
|
||||
instance_ids2 = []
|
||||
for index in xrange(FLAGS.max_cores):
|
||||
@@ -186,10 +193,12 @@ class SimpleDriverTestCase(test.TrialTestCase):
|
||||
'nova-volume',
|
||||
'volume',
|
||||
FLAGS.volume_manager)
|
||||
volume1.startService()
|
||||
volume2 = service.Service('host2',
|
||||
'nova-volume',
|
||||
'volume',
|
||||
FLAGS.volume_manager)
|
||||
volume2.startService()
|
||||
volume_id1 = self._create_volume()
|
||||
volume1.create_volume(self.context, volume_id1)
|
||||
volume_id2 = self._create_volume()
|
||||
@@ -207,10 +216,12 @@ class SimpleDriverTestCase(test.TrialTestCase):
|
||||
'nova-volume',
|
||||
'volume',
|
||||
FLAGS.volume_manager)
|
||||
volume1.startService()
|
||||
volume2 = service.Service('host2',
|
||||
'nova-volume',
|
||||
'volume',
|
||||
FLAGS.volume_manager)
|
||||
volume2.startService()
|
||||
volume_ids1 = []
|
||||
volume_ids2 = []
|
||||
for index in xrange(FLAGS.max_gigabytes):
|
||||
|
@@ -22,6 +22,8 @@ Unit Tests for remote procedure calls using queue
|
||||
|
||||
import mox
|
||||
|
||||
from twisted.application.app import startApplication
|
||||
|
||||
from nova import context
|
||||
from nova import exception
|
||||
from nova import flags
|
||||
@@ -98,6 +100,7 @@ class ServiceTestCase(test.BaseTestCase):
|
||||
self.mox.ReplayAll()
|
||||
|
||||
app = service.Service.create(host=host, binary=binary)
|
||||
startApplication(app, False)
|
||||
self.assert_(app)
|
||||
|
||||
# We're testing sort of weird behavior in how report_state decides
|
||||
|
@@ -14,36 +14,77 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from xml.etree.ElementTree import fromstring as xml_to_tree
|
||||
from xml.dom.minidom import parseString as xml_to_dom
|
||||
|
||||
from nova import db
|
||||
from nova import flags
|
||||
from nova import test
|
||||
from nova import utils
|
||||
from nova.api import context
|
||||
from nova.api.ec2 import cloud
|
||||
from nova.auth import manager
|
||||
from nova.virt import libvirt_conn
|
||||
|
||||
FLAGS = flags.FLAGS
|
||||
|
||||
flags.DECLARE('instances_path', 'nova.compute.manager')
|
||||
|
||||
class LibvirtConnTestCase(test.TrialTestCase):
|
||||
def setUp(self):
|
||||
super(LibvirtConnTestCase, self).setUp()
|
||||
self.manager = manager.AuthManager()
|
||||
self.user = self.manager.create_user('fake', 'fake', 'fake', admin=True)
|
||||
self.project = self.manager.create_project('fake', 'fake', 'fake')
|
||||
self.network = utils.import_object(FLAGS.network_manager)
|
||||
FLAGS.instances_path = ''
|
||||
|
||||
def test_get_uri_and_template(self):
|
||||
class MockDataModel(object):
|
||||
def __init__(self):
|
||||
self.datamodel = { 'name' : 'i-cafebabe',
|
||||
'memory_kb' : '1024000',
|
||||
'basepath' : '/some/path',
|
||||
'bridge_name' : 'br100',
|
||||
'mac_address' : '02:12:34:46:56:67',
|
||||
'vcpus' : 2 }
|
||||
ip = '10.11.12.13'
|
||||
|
||||
instance = { 'internal_id' : 1,
|
||||
'memory_kb' : '1024000',
|
||||
'basepath' : '/some/path',
|
||||
'bridge_name' : 'br100',
|
||||
'mac_address' : '02:12:34:46:56:67',
|
||||
'vcpus' : 2,
|
||||
'project_id' : 'fake',
|
||||
'bridge' : 'br101',
|
||||
'instance_type' : 'm1.small'}
|
||||
|
||||
instance_ref = db.instance_create(None, instance)
|
||||
user_context = context.APIRequestContext(project=self.project,
|
||||
user=self.user)
|
||||
network_ref = self.network.get_network(user_context)
|
||||
self.network.set_network_host(context.get_admin_context(),
|
||||
network_ref['id'])
|
||||
|
||||
fixed_ip = { 'address' : ip,
|
||||
'network_id' : network_ref['id'] }
|
||||
|
||||
fixed_ip_ref = db.fixed_ip_create(None, fixed_ip)
|
||||
db.fixed_ip_update(None, ip, { 'allocated' : True,
|
||||
'instance_id' : instance_ref['id'] })
|
||||
|
||||
type_uri_map = { 'qemu' : ('qemu:///system',
|
||||
[lambda s: '<domain type=\'qemu\'>' in s,
|
||||
lambda s: 'type>hvm</type' in s,
|
||||
lambda s: 'emulator>/usr/bin/kvm' not in s]),
|
||||
[(lambda t: t.find('.').get('type'), 'qemu'),
|
||||
(lambda t: t.find('./os/type').text, 'hvm'),
|
||||
(lambda t: t.find('./devices/emulator'), None)]),
|
||||
'kvm' : ('qemu:///system',
|
||||
[lambda s: '<domain type=\'kvm\'>' in s,
|
||||
lambda s: 'type>hvm</type' in s,
|
||||
lambda s: 'emulator>/usr/bin/qemu<' not in s]),
|
||||
[(lambda t: t.find('.').get('type'), 'kvm'),
|
||||
(lambda t: t.find('./os/type').text, 'hvm'),
|
||||
(lambda t: t.find('./devices/emulator'), None)]),
|
||||
'uml' : ('uml:///system',
|
||||
[lambda s: '<domain type=\'uml\'>' in s,
|
||||
lambda s: 'type>uml</type' in s]),
|
||||
}
|
||||
[(lambda t: t.find('.').get('type'), 'uml'),
|
||||
(lambda t: t.find('./os/type').text, 'uml')]),
|
||||
}
|
||||
|
||||
common_checks = [(lambda t: t.find('.').tag, 'domain'),
|
||||
(lambda t: \
|
||||
t.find('./devices/interface/filterref/parameter') \
|
||||
.get('name'), 'IP'),
|
||||
(lambda t: \
|
||||
t.find('./devices/interface/filterref/parameter') \
|
||||
.get('value'), '10.11.12.13')]
|
||||
|
||||
for (libvirt_type,(expected_uri, checks)) in type_uri_map.iteritems():
|
||||
FLAGS.libvirt_type = libvirt_type
|
||||
@@ -52,9 +93,17 @@ class LibvirtConnTestCase(test.TrialTestCase):
|
||||
uri, template = conn.get_uri_and_template()
|
||||
self.assertEquals(uri, expected_uri)
|
||||
|
||||
for i, check in enumerate(checks):
|
||||
xml = conn.toXml(MockDataModel())
|
||||
self.assertTrue(check(xml), '%s failed check %d' % (xml, i))
|
||||
xml = conn.to_xml(instance_ref)
|
||||
tree = xml_to_tree(xml)
|
||||
for i, (check, expected_result) in enumerate(checks):
|
||||
self.assertEqual(check(tree),
|
||||
expected_result,
|
||||
'%s failed check %d' % (xml, i))
|
||||
|
||||
for i, (check, expected_result) in enumerate(common_checks):
|
||||
self.assertEqual(check(tree),
|
||||
expected_result,
|
||||
'%s failed common check %d' % (xml, i))
|
||||
|
||||
# Deliberately not just assigning this string to FLAGS.libvirt_uri and
|
||||
# checking against that later on. This way we make sure the
|
||||
@@ -67,3 +116,143 @@ class LibvirtConnTestCase(test.TrialTestCase):
|
||||
uri, template = conn.get_uri_and_template()
|
||||
self.assertEquals(uri, testuri)
|
||||
|
||||
|
||||
def tearDown(self):
|
||||
super(LibvirtConnTestCase, self).tearDown()
|
||||
self.manager.delete_project(self.project)
|
||||
self.manager.delete_user(self.user)
|
||||
|
||||
class NWFilterTestCase(test.TrialTestCase):
|
||||
def setUp(self):
|
||||
super(NWFilterTestCase, self).setUp()
|
||||
|
||||
class Mock(object):
|
||||
pass
|
||||
|
||||
self.manager = manager.AuthManager()
|
||||
self.user = self.manager.create_user('fake', 'fake', 'fake', admin=True)
|
||||
self.project = self.manager.create_project('fake', 'fake', 'fake')
|
||||
self.context = context.APIRequestContext(self.user, self.project)
|
||||
|
||||
self.fake_libvirt_connection = Mock()
|
||||
|
||||
self.fw = libvirt_conn.NWFilterFirewall(self.fake_libvirt_connection)
|
||||
|
||||
def tearDown(self):
|
||||
self.manager.delete_project(self.project)
|
||||
self.manager.delete_user(self.user)
|
||||
|
||||
|
||||
def test_cidr_rule_nwfilter_xml(self):
|
||||
cloud_controller = cloud.CloudController()
|
||||
cloud_controller.create_security_group(self.context,
|
||||
'testgroup',
|
||||
'test group description')
|
||||
cloud_controller.authorize_security_group_ingress(self.context,
|
||||
'testgroup',
|
||||
from_port='80',
|
||||
to_port='81',
|
||||
ip_protocol='tcp',
|
||||
cidr_ip='0.0.0.0/0')
|
||||
|
||||
|
||||
security_group = db.security_group_get_by_name(self.context,
|
||||
'fake',
|
||||
'testgroup')
|
||||
|
||||
xml = self.fw.security_group_to_nwfilter_xml(security_group.id)
|
||||
|
||||
dom = xml_to_dom(xml)
|
||||
self.assertEqual(dom.firstChild.tagName, 'filter')
|
||||
|
||||
rules = dom.getElementsByTagName('rule')
|
||||
self.assertEqual(len(rules), 1)
|
||||
|
||||
# It's supposed to allow inbound traffic.
|
||||
self.assertEqual(rules[0].getAttribute('action'), 'accept')
|
||||
self.assertEqual(rules[0].getAttribute('direction'), 'in')
|
||||
|
||||
# Must be lower priority than the base filter (which blocks everything)
|
||||
self.assertTrue(int(rules[0].getAttribute('priority')) < 1000)
|
||||
|
||||
ip_conditions = rules[0].getElementsByTagName('tcp')
|
||||
self.assertEqual(len(ip_conditions), 1)
|
||||
self.assertEqual(ip_conditions[0].getAttribute('srcipaddr'), '0.0.0.0')
|
||||
self.assertEqual(ip_conditions[0].getAttribute('srcipmask'), '0.0.0.0')
|
||||
self.assertEqual(ip_conditions[0].getAttribute('dstportstart'), '80')
|
||||
self.assertEqual(ip_conditions[0].getAttribute('dstportend'), '81')
|
||||
|
||||
|
||||
self.teardown_security_group()
|
||||
|
||||
def teardown_security_group(self):
|
||||
cloud_controller = cloud.CloudController()
|
||||
cloud_controller.delete_security_group(self.context, 'testgroup')
|
||||
|
||||
|
||||
def setup_and_return_security_group(self):
|
||||
cloud_controller = cloud.CloudController()
|
||||
cloud_controller.create_security_group(self.context,
|
||||
'testgroup',
|
||||
'test group description')
|
||||
cloud_controller.authorize_security_group_ingress(self.context,
|
||||
'testgroup',
|
||||
from_port='80',
|
||||
to_port='81',
|
||||
ip_protocol='tcp',
|
||||
cidr_ip='0.0.0.0/0')
|
||||
|
||||
return db.security_group_get_by_name(self.context, 'fake', 'testgroup')
|
||||
|
||||
def test_creates_base_rule_first(self):
|
||||
# These come pre-defined by libvirt
|
||||
self.defined_filters = ['no-mac-spoofing',
|
||||
'no-ip-spoofing',
|
||||
'no-arp-spoofing',
|
||||
'allow-dhcp-server']
|
||||
|
||||
self.recursive_depends = {}
|
||||
for f in self.defined_filters:
|
||||
self.recursive_depends[f] = []
|
||||
|
||||
def _filterDefineXMLMock(xml):
|
||||
dom = xml_to_dom(xml)
|
||||
name = dom.firstChild.getAttribute('name')
|
||||
self.recursive_depends[name] = []
|
||||
for f in dom.getElementsByTagName('filterref'):
|
||||
ref = f.getAttribute('filter')
|
||||
self.assertTrue(ref in self.defined_filters,
|
||||
('%s referenced filter that does ' +
|
||||
'not yet exist: %s') % (name, ref))
|
||||
dependencies = [ref] + self.recursive_depends[ref]
|
||||
self.recursive_depends[name] += dependencies
|
||||
|
||||
self.defined_filters.append(name)
|
||||
return True
|
||||
|
||||
self.fake_libvirt_connection.nwfilterDefineXML = _filterDefineXMLMock
|
||||
|
||||
instance_ref = db.instance_create(self.context,
|
||||
{'user_id': 'fake',
|
||||
'project_id': 'fake'})
|
||||
inst_id = instance_ref['id']
|
||||
|
||||
def _ensure_all_called(_):
|
||||
instance_filter = 'nova-instance-%s' % instance_ref['name']
|
||||
secgroup_filter = 'nova-secgroup-%s' % self.security_group['id']
|
||||
for required in [secgroup_filter, 'allow-dhcp-server',
|
||||
'no-arp-spoofing', 'no-ip-spoofing',
|
||||
'no-mac-spoofing']:
|
||||
self.assertTrue(required in self.recursive_depends[instance_filter],
|
||||
"Instance's filter does not include %s" % required)
|
||||
|
||||
self.security_group = self.setup_and_return_security_group()
|
||||
|
||||
db.instance_add_security_group(self.context, inst_id, self.security_group.id)
|
||||
instance = db.instance_get(self.context, inst_id)
|
||||
|
||||
d = self.fw.setup_nwfilters_for_instance(instance)
|
||||
d.addCallback(_ensure_all_called)
|
||||
d.addCallback(lambda _:self.teardown_security_group())
|
||||
|
||||
return d
|
||||
|
@@ -63,7 +63,9 @@ from nova.tests.rpc_unittest import *
|
||||
from nova.tests.scheduler_unittest import *
|
||||
from nova.tests.service_unittest import *
|
||||
from nova.tests.validator_unittest import *
|
||||
from nova.tests.virt_unittest import *
|
||||
from nova.tests.volume_unittest import *
|
||||
from nova.tests.virt_unittest import *
|
||||
|
||||
|
||||
FLAGS = flags.FLAGS
|
||||
|
Reference in New Issue
Block a user