Merge from trunk

This commit is contained in:
Ryan Lane
2011-01-27 12:17:43 +00:00
43 changed files with 714 additions and 326 deletions

View File

@@ -8,6 +8,7 @@ Chmouel Boudjnah <chmouel@chmouel.com>
Chris Behrens <cbehrens@codestud.com>
Cory Wright <corywright@gmail.com>
David Pravec <David.Pravec@danix.org>
Dan Prince <dan.prince@rackspace.com>
Dean Troyer <dtroyer@gmail.com>
Devin Carlen <devin.carlen@gmail.com>
Ed Leafe <ed@leafe.com>
@@ -23,6 +24,7 @@ Joe Heck <heckj@mac.com>
Joel Moore <joelbm24@gmail.com>
John Dewey <john@dewey.ws>
Jonathan Bryce <jbryce@jbryce.com>
Jordan Rinke <jordan@openstack.org>
Josh Durgin <joshd@hq.newdream.net>
Josh Kearney <josh.kearney@rackspace.com>
Joshua McKenty <jmckenty@gmail.com>
@@ -50,6 +52,7 @@ Soren Hansen <soren.hansen@rackspace.com>
Thierry Carrez <thierry@openstack.org>
Todd Willey <todd@ansolabs.com>
Trey Morris <trey.morris@rackspace.com>
Tushar Patil <tushar.vitthal.patil@gmail.com> <tpatil@vertex.co.in>
Vishvananda Ishaya <vishvananda@gmail.com>
Youcef Laribi <Youcef.Laribi@eu.citrix.com>
Zhixue Wu <Zhixue.Wu@citrix.com>

View File

@@ -267,6 +267,14 @@ class RoleCommands(object):
self.manager.remove_role(user, role, project)
def _db_error(caught_exception):
print caught_exception
print _("The above error may show that the database has not "
"been created.\nPlease create a database using "
"nova-manage sync db before running this command.")
exit(1)
class UserCommands(object):
"""Class for managing users."""
@@ -282,13 +290,19 @@ class UserCommands(object):
def admin(self, name, access=None, secret=None):
"""creates a new admin and prints exports
arguments: name [access] [secret]"""
user = self.manager.create_user(name, access, secret, True)
try:
user = self.manager.create_user(name, access, secret, True)
except exception.DBError, e:
_db_error(e)
self._print_export(user)
def create(self, name, access=None, secret=None):
"""creates a new user and prints exports
arguments: name [access] [secret]"""
user = self.manager.create_user(name, access, secret, False)
try:
user = self.manager.create_user(name, access, secret, False)
except exception.DBError, e:
_db_error(e)
self._print_export(user)
def delete(self, name):
@@ -409,9 +423,14 @@ class ProjectCommands(object):
with open(filename, 'w') as f:
f.write(zip_file)
except db.api.NoMoreNetworks:
print ('No more networks available. If this is a new '
'installation, you need\nto call something like this:\n\n'
' nova-manage network create 10.0.0.0/8 10 64\n\n')
print _('No more networks available. If this is a new '
'installation, you need\nto call something like this:\n\n'
' nova-manage network create 10.0.0.0/8 10 64\n\n')
except exception.ProcessExecutionError, e:
print e
print _("The above error may show that the certificate db has not "
"been created.\nPlease create a database by running a "
"nova-api server on this host.")
class FloatingIpCommands(object):
@@ -476,9 +495,9 @@ class NetworkCommands(object):
cidr=fixed_range,
num_networks=int(num_networks),
network_size=int(network_size),
cidr_v6=fixed_range_v6,
vlan_start=int(vlan_start),
vpn_start=int(vpn_start),
cidr_v6=fixed_range_v6)
vpn_start=int(vpn_start))
class ServiceCommands(object):

View File

@@ -1,15 +1,14 @@
#!/usr/bin/env bash
DIR=`pwd`
CMD=$1
SOURCE_BRANCH=lp:nova
if [ -n "$2" ]; then
SOURCE_BRANCH=$2
if [ "$CMD" = "branch" ]; then
SOURCE_BRANCH=${2:-lp:nova}
DIRNAME=${3:-nova}
else
DIRNAME=${2:-nova}
fi
DIRNAME=nova
NOVA_DIR=$DIR/$DIRNAME
if [ -n "$3" ]; then
NOVA_DIR=$DIR/$3
fi
if [ ! -n "$HOST_IP" ]; then
# NOTE(vish): This will just get the first ip in the list, so if you
@@ -24,6 +23,8 @@ TEST=${TEST:-0}
USE_LDAP=${USE_LDAP:-0}
# Use OpenDJ instead of OpenLDAP when using LDAP
USE_OPENDJ=${USE_OPENDJ:-0}
# Use IPv6
USE_IPV6=${USE_IPV6:-0}
LIBVIRT_TYPE=${LIBVIRT_TYPE:-qemu}
NET_MAN=${NET_MAN:-VlanManager}
# NOTE(vish): If you are using FlatDHCP on multiple hosts, set the interface
@@ -43,8 +44,69 @@ else
AUTH=dbdriver.DbDriver
fi
mkdir -p /etc/nova
cat >$NOVA_DIR/bin/nova.conf << NOVA_CONF_EOF
if [ "$CMD" == "branch" ]; then
sudo apt-get install -y bzr
if [ ! -e "$DIR/.bzr" ]; then
bzr init-repo $DIR
fi
rm -rf $NOVA_DIR
bzr branch $SOURCE_BRANCH $NOVA_DIR
cd $NOVA_DIR
mkdir -p $NOVA_DIR/instances
mkdir -p $NOVA_DIR/networks
exit
fi
# You should only have to run this once
if [ "$CMD" == "install" ]; then
sudo apt-get install -y python-software-properties
sudo add-apt-repository ppa:nova-core/trunk
sudo apt-get update
sudo apt-get install -y dnsmasq-base kpartx kvm gawk iptables ebtables
sudo apt-get install -y user-mode-linux kvm libvirt-bin
sudo apt-get install -y screen euca2ools vlan curl rabbitmq-server
sudo apt-get install -y lvm2 iscsitarget open-iscsi
sudo apt-get install -y socat
echo "ISCSITARGET_ENABLE=true" | sudo tee /etc/default/iscsitarget
sudo /etc/init.d/iscsitarget restart
sudo modprobe kvm
sudo /etc/init.d/libvirt-bin restart
sudo modprobe nbd
sudo apt-get install -y python-twisted python-sqlalchemy python-mox python-greenlet python-carrot
sudo apt-get install -y python-migrate python-eventlet python-gflags python-ipy python-tempita
sudo apt-get install -y python-libvirt python-libxml2 python-routes python-cheetah
sudo apt-get install -y python-netaddr python-paste python-pastedeploy python-glance
if [ "$USE_IPV6" == 1 ]; then
sudo apt-get install -y radvd
sudo bash -c "echo 1 > /proc/sys/net/ipv6/conf/all/forwarding"
sudo bash -c "echo 0 > /proc/sys/net/ipv6/conf/all/accept_ra"
fi
if [ "$USE_MYSQL" == 1 ]; then
cat <<MYSQL_PRESEED | debconf-set-selections
mysql-server-5.1 mysql-server/root_password password $MYSQL_PASS
mysql-server-5.1 mysql-server/root_password_again password $MYSQL_PASS
mysql-server-5.1 mysql-server/start_on_boot boolean true
MYSQL_PRESEED
apt-get install -y mysql-server python-mysqldb
fi
mkdir -p $DIR/images
wget -c http://images.ansolabs.com/tty.tgz
tar -C $DIR/images -zxf tty.tgz
exit
fi
NL=`echo -ne '\015'`
function screen_it {
screen -S nova -X screen -t $1
screen -S nova -p $1 -X stuff "$2$NL"
}
if [ "$CMD" == "run" ]; then
cat >$NOVA_DIR/bin/nova.conf << NOVA_CONF_EOF
--verbose
--nodaemon
--dhcpbridge_flagfile=$NOVA_DIR/bin/nova.conf
@@ -56,68 +118,18 @@ cat >$NOVA_DIR/bin/nova.conf << NOVA_CONF_EOF
--libvirt_type=$LIBVIRT_TYPE
NOVA_CONF_EOF
if [ -n "$FLAT_INTERFACE" ]; then
echo "--flat_interface=$FLAT_INTERFACE" >>$NOVA_DIR/bin/nova.conf
fi
if [ "$CMD" == "branch" ]; then
sudo apt-get install -y bzr
rm -rf $NOVA_DIR
bzr branch $SOURCE_BRANCH $NOVA_DIR
cd $NOVA_DIR
mkdir -p $NOVA_DIR/instances
mkdir -p $NOVA_DIR/networks
fi
# You should only have to run this once
if [ "$CMD" == "install" ]; then
sudo apt-get install -y python-software-properties
sudo add-apt-repository ppa:nova-core/trunk
sudo apt-get update
sudo apt-get install -y dnsmasq kpartx kvm gawk iptables ebtables
sudo apt-get install -y user-mode-linux kvm libvirt-bin
sudo apt-get install -y screen euca2ools vlan curl rabbitmq-server
sudo apt-get install -y lvm2 iscsitarget open-iscsi
sudo apt-get install -y socat
echo "ISCSITARGET_ENABLE=true" | sudo tee /etc/default/iscsitarget
sudo /etc/init.d/iscsitarget restart
sudo modprobe kvm
sudo /etc/init.d/libvirt-bin restart
sudo modprobe nbd
sudo apt-get install -y python-twisted python-sqlalchemy python-mox python-greenlet python-carrot
sudo apt-get install -y python-daemon python-eventlet python-gflags python-ipy
sudo apt-get install -y python-libvirt python-libxml2 python-routes python-cheetah
sudo apt-get install -y python-paste python-pastedeploy
#For IPV6
sudo apt-get install -y python-netaddr
sudo apt-get install -y radvd
#(Nati) Note that this configuration is only needed for nova-network node.
sudo bash -c "echo 1 > /proc/sys/net/ipv6/conf/all/forwarding"
sudo bash -c "echo 0 > /proc/sys/net/ipv6/conf/all/accept_ra"
if [ "$USE_MYSQL" == 1 ]; then
cat <<MYSQL_PRESEED | debconf-set-selections
mysql-server-5.1 mysql-server/root_password password $MYSQL_PASS
mysql-server-5.1 mysql-server/root_password_again password $MYSQL_PASS
mysql-server-5.1 mysql-server/start_on_boot boolean true
MYSQL_PRESEED
apt-get install -y mysql-server python-mysqldb
if [ -n "$FLAT_INTERFACE" ]; then
echo "--flat_interface=$FLAT_INTERFACE" >>$NOVA_DIR/bin/nova.conf
fi
wget http://c2477062.cdn.cloudfiles.rackspacecloud.com/images.tgz
tar -C $DIR -zxf images.tgz
fi
NL=`echo -ne '\015'`
if [ "$USE_IPV6" == 1 ]; then
echo "--use_ipv6" >>$NOVA_DIR/bin/nova.conf
fi
function screen_it {
screen -S nova -X screen -t $1
screen -S nova -p $1 -X stuff "$2$NL"
}
if [ "$CMD" == "run" ]; then
killall dnsmasq
#For IPv6
killall radvd
if [ "$USE_IPV6" == 1 ]; then
killall radvd
fi
screen -d -m -S nova -t nova
sleep 1
if [ "$USE_MYSQL" == 1 ]; then
@@ -150,6 +162,8 @@ if [ "$CMD" == "run" ]; then
cd $DIR
fi
# create the database
$NOVA_DIR/bin/nova-manage db sync
# create an admin user called 'admin'
$NOVA_DIR/bin/nova-manage user admin admin admin admin
# create a project called 'admin' with project manager of 'admin'
@@ -178,6 +192,7 @@ if [ "$CMD" == "run" ] || [ "$CMD" == "terminate" ]; then
sleep 2
# delete volumes
. $NOVA_DIR/novarc; euca-describe-volumes | grep vol- | cut -f2 | xargs -n1 euca-delete-volume
sleep 2
fi
if [ "$CMD" == "run" ] || [ "$CMD" == "clean" ]; then
@@ -192,5 +207,4 @@ if [ "$CMD" == "scrub" ]; then
else
virsh list | grep i- | awk '{print \$1}' | xargs -n1 virsh destroy
fi
vblade-persist ls | grep vol- | awk '{print \$1\" \"\$2}' | xargs -n2 vblade-persist destroy
fi

View File

@@ -26,6 +26,7 @@ Assumptions
* Networking is configured between/through the physical machines on a single subnet.
* Installation and execution are both performed by ROOT user.
Scripted Installation
---------------------
A script available to get your OpenStack cloud running quickly. You can copy the file to the server where you want to install OpenStack Compute services - typically you would install a compute node and a cloud controller node.

View File

@@ -42,6 +42,17 @@ You can also run with a category argument such as user to see a list of all comm
These sections describe the available categories and arguments for nova-manage.
Nova Db
~~~~~~~
``nova-manage db version``
Print the current database version.
``nova-manage db sync``
Sync the database up to the most recent version. This is the standard way to create the db as well.
Nova User
~~~~~~~~~

View File

@@ -52,7 +52,13 @@ When the installation is complete, you'll see the following lines:
Finished processing dependencies for nova==2010.1
Step 4: Create a Nova administrator
Step 4: Create the Nova Database
--------------------------------
Type or copy/paste in the following line to create your nova db::
sudo nova-manage db sync
Step 5: Create a Nova administrator
-----------------------------------
Type or copy/paste in the following line to create a user named "anne."::
@@ -63,7 +69,7 @@ You see an access key and a secret key export, such as these made-up ones:::
export EC2_ACCESS_KEY=4e6498a2-blah-blah-blah-17d1333t97fd
export EC2_SECRET_KEY=0a520304-blah-blah-blah-340sp34k05bbe9a7
Step 5: Create the network
Step 6: Create the network
--------------------------
Type or copy/paste in the following line to create a network prior to creating a project.
@@ -76,7 +82,7 @@ For this command, the IP address is the cidr notation for your netmask, such as
After running this command, entries are made in the 'networks' and 'fixed_ips' table in the database.
Step 6: Create a project with the user you created
Step 7: Create a project with the user you created
--------------------------------------------------
Type or copy/paste in the following line to create a project named IRT (for Ice Road Truckers, of course) with the newly-created user named anne.
@@ -106,7 +112,7 @@ Type or copy/paste in the following line to create a project named IRT (for Ice
Data Base Updated
Step 7: Unzip the nova.zip
Step 8: Unzip the nova.zip
--------------------------
You should have a nova.zip file in your current working directory. Unzip it with this command:
@@ -128,7 +134,7 @@ You'll see these files extract.
extracting: cacert.pem
Step 8: Source the rc file
Step 9: Source the rc file
--------------------------
Type or copy/paste the following to source the novarc file in your current working directory.
@@ -137,14 +143,14 @@ Type or copy/paste the following to source the novarc file in your current worki
. novarc
Step 9: Pat yourself on the back :)
Step 10: Pat yourself on the back :)
-----------------------------------
Congratulations, your cloud is up and running, youve created an admin user, created a network, retrieved the user's credentials and put them in your environment.
Now you need an image.
Step 9: Get an image
Step 11: Get an image
--------------------
To make things easier, we've provided a small image on the Rackspace CDN. Use this command to get it on your server.
@@ -168,7 +174,7 @@ To make things easier, we've provided a small image on the Rackspace CDN. Use th
Step 10: Decompress the image file
Step 12: Decompress the image file
----------------------------------
Use this command to extract the image files:::
@@ -187,7 +193,7 @@ You get a directory listing like so:::
|-- image
`-- info.json
Step 11: Send commands to upload sample image to the cloud
Step 13: Send commands to upload sample image to the cloud
----------------------------------------------------------
Type or copy/paste the following commands to create a manifest for the kernel.::

View File

@@ -42,6 +42,17 @@ You can also run with a category argument such as user to see a list of all comm
These sections describe the available categories and arguments for nova-manage.
Nova Db
~~~~~~~
``nova-manage db version``
Print the current database version.
``nova-manage db sync``
Sync the database up to the most recent version. This is the standard way to create the db as well.
Nova User
~~~~~~~~~

View File

@@ -1,3 +0,0 @@
{
"machine" : ["kernel", "ramdisk"]
}

View File

@@ -190,6 +190,45 @@ class HostInfo(object):
setattr(self, name, value)
class InstanceType(object):
"""
Information about a Nova instance type, as parsed through SAX.
**Fields include**
* name
* vcpus
* disk_gb
* memory_mb
* flavor_id
"""
def __init__(self, connection=None):
self.connection = connection
self.name = None
self.vcpus = None
self.disk_gb = None
self.memory_mb = None
self.flavor_id = None
def __repr__(self):
return 'InstanceType:%s' % self.name
def startElement(self, name, attrs, connection):
return None
def endElement(self, name, value, connection):
if name == "memoryMb":
self.memory_mb = str(value)
elif name == "flavorId":
self.flavor_id = str(value)
elif name == "diskGb":
self.disk_gb = str(value)
else:
setattr(self, name, str(value))
class NovaAdminClient(object):
def __init__(
@@ -373,3 +412,8 @@ class NovaAdminClient(object):
def get_hosts(self):
return self.apiconn.get_list('DescribeHosts', {}, [('item', HostInfo)])
def get_instance_types(self):
"""Grabs the list of all users."""
return self.apiconn.get_list('DescribeInstanceTypes', {},
[('item', InstanceType)])

View File

@@ -33,6 +33,7 @@ from nova import log as logging
from nova import utils
from nova import wsgi
from nova.api.ec2 import apirequest
from nova.api.ec2 import cloud
from nova.auth import manager
@@ -170,7 +171,7 @@ class Authenticate(wsgi.Middleware):
req.path)
# Be explicit for what exceptions are 403, the rest bubble as 500
except (exception.NotFound, exception.NotAuthorized) as ex:
LOG.audit(_("Authentication Failure: %s"), str(ex))
LOG.audit(_("Authentication Failure: %s"), ex.args[0])
raise webob.exc.HTTPForbidden()
# Authenticated!
@@ -213,7 +214,8 @@ class Requestify(wsgi.Middleware):
LOG.debug(_('arg: %(key)s\t\tval: %(value)s') % locals())
# Success!
api_request = apirequest.APIRequest(self.controller, action, args)
api_request = apirequest.APIRequest(self.controller, action,
req.params['Version'], args)
req.environ['ec2.request'] = api_request
req.environ['ec2.action_args'] = args
return self.application
@@ -313,18 +315,31 @@ class Executor(wsgi.Application):
result = None
try:
result = api_request.invoke(context)
except exception.InstanceNotFound as ex:
LOG.info(_('InstanceNotFound raised: %s'), ex.args[0],
context=context)
ec2_id = cloud.id_to_ec2_id(ex.instance_id)
message = _('Instance %s not found') % ec2_id
return self._error(req, context, type(ex).__name__, message)
except exception.VolumeNotFound as ex:
LOG.info(_('VolumeNotFound raised: %s'), ex.args[0],
context=context)
ec2_id = cloud.id_to_ec2_id(ex.volume_id, 'vol-%08x')
message = _('Volume %s not found') % ec2_id
return self._error(req, context, type(ex).__name__, message)
except exception.NotFound as ex:
LOG.info(_('NotFound raised: %s'), str(ex), context=context)
return self._error(req, context, type(ex).__name__, str(ex))
LOG.info(_('NotFound raised: %s'), ex.args[0], context=context)
return self._error(req, context, type(ex).__name__, ex.args[0])
except exception.ApiError as ex:
LOG.exception(_('ApiError raised: %s'), str(ex), context=context)
LOG.exception(_('ApiError raised: %s'), ex.args[0],
context=context)
if ex.code:
return self._error(req, context, ex.code, str(ex))
return self._error(req, context, ex.code, ex.args[0])
else:
return self._error(req, context, type(ex).__name__, str(ex))
return self._error(req, context, type(ex).__name__, ex.args[0])
except Exception as ex:
extra = {'environment': req.environ}
LOG.exception(_('Unexpected error raised: %s'), str(ex),
LOG.exception(_('Unexpected error raised: %s'), ex.args[0],
extra=extra, context=context)
return self._error(req,
context,
@@ -347,7 +362,8 @@ class Executor(wsgi.Application):
'<Response><Errors><Error><Code>%s</Code>'
'<Message>%s</Message></Error></Errors>'
'<RequestID>%s</RequestID></Response>' %
(code, message, context.request_id))
(utils.utf8(code), utils.utf8(message),
utils.utf8(context.request_id)))
return resp

View File

@@ -26,6 +26,7 @@ from nova import db
from nova import exception
from nova import log as logging
from nova.auth import manager
from nova.compute import instance_types
LOG = logging.getLogger('nova.api.ec2.admin')
@@ -62,6 +63,14 @@ def host_dict(host):
return {}
def instance_dict(name, inst):
return {'name': name,
'memory_mb': inst['memory_mb'],
'vcpus': inst['vcpus'],
'disk_gb': inst['local_gb'],
'flavor_id': inst['flavorid']}
class AdminController(object):
"""
API Controller for users, hosts, nodes, and workers.
@@ -70,6 +79,10 @@ class AdminController(object):
def __str__(self):
return 'AdminController'
def describe_instance_types(self, _context, **_kwargs):
return {'instanceTypeSet': [instance_dict(n, v) for n, v in
instance_types.INSTANCE_TYPES.iteritems()]}
def describe_user(self, _context, name, **_kwargs):
"""Returns user data, including access and secret keys."""
return user_dict(manager.AuthManager().get_user(name))

View File

@@ -83,9 +83,10 @@ def _try_convert(value):
class APIRequest(object):
def __init__(self, controller, action, args):
def __init__(self, controller, action, version, args):
self.controller = controller
self.action = action
self.version = version
self.args = args
def invoke(self, context):
@@ -132,7 +133,7 @@ class APIRequest(object):
response_el = xml.createElement(self.action + 'Response')
response_el.setAttribute('xmlns',
'http://ec2.amazonaws.com/doc/2009-11-30/')
'http://ec2.amazonaws.com/doc/%s/' % self.version)
request_id_el = xml.createElement('requestId')
request_id_el.appendChild(xml.createTextNode(request_id))
response_el.appendChild(request_id_el)

View File

@@ -529,11 +529,14 @@ class CloudController(object):
def describe_volumes(self, context, volume_id=None, **kwargs):
if volume_id:
volume_id = [ec2_id_to_id(x) for x in volume_id]
volumes = self.volume_api.get_all(context)
# NOTE(vish): volume_id is an optional list of volume ids to filter by.
volumes = [self._format_volume(context, v) for v in volumes
if volume_id is None or v['id'] in volume_id]
volumes = []
for ec2_id in volume_id:
internal_id = ec2_id_to_id(ec2_id)
volume = self.volume_api.get(context, internal_id)
volumes.append(volume)
else:
volumes = self.volume_api.get_all(context)
volumes = [self._format_volume(context, v) for v in volumes]
return {'volumeSet': volumes}
def _format_volume(self, context, volume):
@@ -658,8 +661,11 @@ class CloudController(object):
reservations = {}
# NOTE(vish): instance_id is an optional list of ids to filter by
if instance_id:
instance_id = [ec2_id_to_id(x) for x in instance_id]
instances = [self.compute_api.get(context, x) for x in instance_id]
instances = []
for ec2_id in instance_id:
internal_id = ec2_id_to_id(ec2_id)
instance = self.compute_api.get(context, internal_id)
instances.append(instance)
else:
instances = self.compute_api.get_all(context, **kwargs)
for instance in instances:

View File

@@ -38,9 +38,6 @@ from nova.api.openstack import shared_ip_groups
LOG = logging.getLogger('nova.api.openstack')
FLAGS = flags.FLAGS
flags.DEFINE_string('os_krm_mapping_file',
'krm_mapping.json',
'Location of OpenStack Flavor/OS:EC2 Kernel/Ramdisk/Machine JSON file.')
flags.DEFINE_bool('allow_admin_api',
False,
'When True, this API service will accept admin operations.')

View File

@@ -54,7 +54,7 @@ def get_image_id_from_image_hash(image_service, context, image_hash):
except NotImplementedError:
items = image_service.index(context)
for image in items:
image_id = image['imageId']
image_id = image['id']
if abs(hash(image_id)) == int(image_hash):
return image_id
raise exception.NotFound(image_hash)

View File

@@ -124,17 +124,23 @@ class Controller(wsgi.Controller):
return faults.Fault(exc.HTTPNotFound())
return exc.HTTPAccepted()
def _get_kernel_ramdisk_from_image(self, image_id):
mapping_filename = FLAGS.os_krm_mapping_file
def _get_kernel_ramdisk_from_image(self, req, image_id):
"""
Machine images are associated with Kernels and Ramdisk images via
metadata stored in Glance as 'image_properties'
"""
def lookup(param):
_image_id = image_id
try:
return image['properties'][param]
except KeyError:
raise exception.NotFound(
_("%(param)s property not found for image %(_image_id)s") %
locals())
with open(mapping_filename) as f:
mapping = json.load(f)
if image_id in mapping:
return mapping[image_id]
msg = _("No entry for image '%(image_id)s'"
" in mapping file '%(mapping_filename)s'") % locals()
raise exception.NotFound(msg)
image_id = str(image_id)
image = self._image_service.show(req.environ['nova.context'], image_id)
return lookup('kernel_id'), lookup('ramdisk_id')
def create(self, req):
""" Creates a new server for a given user """
@@ -146,7 +152,8 @@ class Controller(wsgi.Controller):
req.environ['nova.context'])[0]
image_id = common.get_image_id_from_image_hash(self._image_service,
req.environ['nova.context'], env['server']['imageId'])
kernel_id, ramdisk_id = self._get_kernel_ramdisk_from_image(image_id)
kernel_id, ramdisk_id = self._get_kernel_ramdisk_from_image(
req, image_id)
instances = self.compute_api.create(
req.environ['nova.context'],
instance_types.get_by_flavor_id(env['server']['flavorId']),

View File

@@ -318,7 +318,7 @@ class API(base.Base):
def get(self, context, instance_id):
"""Get a single instance with the given ID."""
rv = self.db.instance_get_by_id(context, instance_id)
rv = self.db.instance_get(context, instance_id)
return dict(rv.iteritems())
def get_all(self, context, project_id=None, reservation_id=None,

View File

@@ -118,7 +118,7 @@ class ComputeManager(manager.Manager):
"""Do any initialization that needs to be run if this is a
standalone service.
"""
self.driver.init_host()
self.driver.init_host(host=self.host)
def _update_state(self, context, instance_id):
"""Update the state of an instance from the driver info."""

View File

@@ -71,7 +71,6 @@ class NoMoreTargets(exception.Error):
"""No more available blades"""
pass
###################
@@ -351,6 +350,11 @@ def instance_get_all_by_project(context, project_id):
return IMPL.instance_get_all_by_project(context, project_id)
def instance_get_all_by_host(context, host):
"""Get all instance belonging to a host."""
return IMPL.instance_get_all_by_host(context, host)
def instance_get_all_by_reservation(context, reservation_id):
"""Get all instance belonging to a reservation."""
return IMPL.instance_get_all_by_reservation(context, reservation_id)
@@ -375,11 +379,6 @@ def instance_get_project_vpn(context, project_id):
return IMPL.instance_get_project_vpn(context, project_id)
def instance_get_by_id(context, instance_id):
"""Get an instance by id."""
return IMPL.instance_get_by_id(context, instance_id)
def instance_is_vpn(context, instance_id):
"""True if instance is a vpn."""
return IMPL.instance_is_vpn(context, instance_id)

View File

@@ -685,6 +685,7 @@ def instance_get(context, instance_id, session=None):
options(joinedload_all('fixed_ip.floating_ips')).\
options(joinedload_all('security_groups.rules')).\
options(joinedload('volumes')).\
options(joinedload_all('fixed_ip.network')).\
filter_by(id=instance_id).\
filter_by(deleted=can_read_deleted(context)).\
first()
@@ -698,7 +699,9 @@ def instance_get(context, instance_id, session=None):
filter_by(deleted=False).\
first()
if not result:
raise exception.NotFound(_('No instance for id %s') % instance_id)
raise exception.InstanceNotFound(_('Instance %s not found')
% instance_id,
instance_id)
return result
@@ -724,6 +727,17 @@ def instance_get_all_by_user(context, user_id):
all()
@require_admin_context
def instance_get_all_by_host(context, host):
session = get_session()
return session.query(models.Instance).\
options(joinedload_all('fixed_ip.floating_ips')).\
options(joinedload('security_groups')).\
filter_by(host=host).\
filter_by(deleted=can_read_deleted(context)).\
all()
@require_context
def instance_get_all_by_project(context, project_id):
authorize_project_context(context, project_id)
@@ -770,33 +784,6 @@ def instance_get_project_vpn(context, project_id):
first()
@require_context
def instance_get_by_id(context, instance_id):
session = get_session()
if is_admin_context(context):
result = session.query(models.Instance).\
options(joinedload_all('fixed_ip.floating_ips')).\
options(joinedload('security_groups')).\
options(joinedload_all('fixed_ip.network')).\
filter_by(id=instance_id).\
filter_by(deleted=can_read_deleted(context)).\
first()
elif is_user_context(context):
result = session.query(models.Instance).\
options(joinedload('security_groups')).\
options(joinedload_all('fixed_ip.floating_ips')).\
options(joinedload_all('fixed_ip.network')).\
filter_by(project_id=context.project_id).\
filter_by(id=instance_id).\
filter_by(deleted=False).\
first()
if not result:
raise exception.NotFound(_('Instance %s not found') % (instance_id))
return result
@require_context
def instance_get_fixed_address(context, instance_id):
session = get_session()
@@ -1396,17 +1383,20 @@ def volume_get(context, volume_id, session=None):
if is_admin_context(context):
result = session.query(models.Volume).\
options(joinedload('instance')).\
filter_by(id=volume_id).\
filter_by(deleted=can_read_deleted(context)).\
first()
elif is_user_context(context):
result = session.query(models.Volume).\
options(joinedload('instance')).\
filter_by(project_id=context.project_id).\
filter_by(id=volume_id).\
filter_by(deleted=False).\
first()
if not result:
raise exception.NotFound(_('No volume for id %s') % volume_id)
raise exception.VolumeNotFound(_('Volume %s not found') % volume_id,
volume_id)
return result
@@ -1451,7 +1441,8 @@ def volume_get_instance(context, volume_id):
options(joinedload('instance')).\
first()
if not result:
raise exception.NotFound(_('Volume %s not found') % ec2_id)
raise exception.VolumeNotFound(_('Volume %s not found') % volume_id,
volume_id)
return result.instance

View File

@@ -22,6 +22,7 @@ Session Handling for SQLAlchemy backend
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from nova import exception
from nova import flags
FLAGS = flags.FLAGS
@@ -43,4 +44,6 @@ def get_session(autocommit=True, expire_on_commit=False):
autocommit=autocommit,
expire_on_commit=expire_on_commit))
session = _MAKER()
session.query = exception.wrap_db_error(session.query)
session.flush = exception.wrap_db_error(session.flush)
return session

View File

@@ -46,7 +46,6 @@ class Error(Exception):
class ApiError(Error):
def __init__(self, message='Unknown', code='Unknown'):
self.message = message
self.code = code
@@ -57,6 +56,18 @@ class NotFound(Error):
pass
class InstanceNotFound(NotFound):
def __init__(self, message, instance_id):
self.instance_id = instance_id
super(InstanceNotFound, self).__init__(message)
class VolumeNotFound(NotFound):
def __init__(self, message, volume_id):
self.volume_id = volume_id
super(VolumeNotFound, self).__init__(message)
class Duplicate(Error):
pass
@@ -81,6 +92,24 @@ class TimeoutException(Error):
pass
class DBError(Error):
"""Wraps an implementation specific exception"""
def __init__(self, inner_exception):
self.inner_exception = inner_exception
super(DBError, self).__init__(str(inner_exception))
def wrap_db_error(f):
def _wrap(*args, **kwargs):
try:
return f(*args, **kwargs)
except Exception, e:
LOG.exception(_('DB exception wrapped'))
raise DBError(e)
return _wrap
_wrap.func_name = f.func_name
def wrap_exception(f):
def _wrap(*args, **kw):
try:

View File

@@ -18,6 +18,7 @@
import cPickle as pickle
import os.path
import random
import tempfile
from nova import exception
from nova.image import service
@@ -26,15 +27,12 @@ from nova.image import service
class LocalImageService(service.BaseImageService):
"""Image service storing images to local disk.
It assumes that image_ids are integers.
It assumes that image_ids are integers."""
"""
def __init__(self):
self._path = "/tmp/nova/images"
try:
os.makedirs(self._path)
except OSError: # Exists
pass
self._path = tempfile.mkdtemp()
def _path_to(self, image_id):
return os.path.join(self._path, str(image_id))
@@ -56,9 +54,7 @@ class LocalImageService(service.BaseImageService):
raise exception.NotFound
def create(self, context, data):
"""
Store the image data and return the new image id.
"""
"""Store the image data and return the new image id."""
id = random.randint(0, 2 ** 31 - 1)
data['id'] = id
self.update(context, id, data)
@@ -72,8 +68,9 @@ class LocalImageService(service.BaseImageService):
raise exception.NotFound
def delete(self, context, image_id):
"""
Delete the given image. Raises OSError if the image does not exist.
"""Delete the given image.
Raises OSError if the image does not exist.
"""
try:
os.unlink(self._path_to(image_id))
@@ -81,8 +78,13 @@ class LocalImageService(service.BaseImageService):
raise exception.NotFound
def delete_all(self):
"""
Clears out all images in local directory
"""
"""Clears out all images in local directory."""
for id in self._ids():
os.unlink(self._path_to(id))
def delete_imagedir(self):
"""Deletes the local directory.
Raises OSError if directory is not empty.
"""
os.rmdir(self._path)

View File

@@ -65,12 +65,19 @@ class S3ImageService(service.BaseImageService):
'image_id': image_id}))
return image_id
def _fix_image_id(self, images):
"""S3 has imageId but OpenStack wants id"""
for image in images:
if 'imageId' in image:
image['id'] = image['imageId']
return images
def index(self, context):
"""Return a list of all images that a user can see."""
response = self._conn(context).make_request(
method='GET',
bucket='_images')
return json.loads(response.read())
return self._fix_image_id(json.loads(response.read()))
def show(self, context, image_id):
"""return a image object if the context has permissions"""

View File

@@ -198,9 +198,9 @@ def ensure_bridge(bridge, interface, net_attrs=None):
net_attrs['broadcast'],
net_attrs['netmask']))
if(FLAGS.use_ipv6):
_execute("sudo ifconfig %s add %s up" % \
(bridge,
net_attrs['cidr_v6']))
_execute("sudo ip -f inet6 addr change %s dev %s" %
(net_attrs['cidr_v6'], bridge))
_execute("sudo ifconfig %s up" % bridge)
else:
_execute("sudo ifconfig %s up" % bridge)
if FLAGS.use_nova_chains:
@@ -298,10 +298,9 @@ interface %s
% pid, check_exit_code=False)
if conffile in out:
try:
_execute('sudo kill -HUP %d' % pid)
return
_execute('sudo kill %d' % pid)
except Exception as exc: # pylint: disable-msg=W0703
LOG.debug(_("Hupping radvd threw %s"), exc)
LOG.debug(_("killing radvd threw %s"), exc)
else:
LOG.debug(_("Pid %d is stale, relaunching radvd"), pid)
command = _ra_cmd(network_ref)

View File

@@ -395,6 +395,7 @@ class FlatDHCPManager(FlatManager):
standalone service.
"""
super(FlatDHCPManager, self).init_host()
self.driver.init_host()
self.driver.metadata_forward()
def setup_compute_network(self, context, instance_id):
@@ -427,6 +428,10 @@ class FlatDHCPManager(FlatManager):
self.driver.ensure_bridge(network_ref['bridge'],
FLAGS.flat_interface,
network_ref)
if not FLAGS.fake_network:
self.driver.update_dhcp(context, network_id)
if(FLAGS.use_ipv6):
self.driver.update_ra(context, network_id)
class VlanManager(NetworkManager):
@@ -460,8 +465,8 @@ class VlanManager(NetworkManager):
standalone service.
"""
super(VlanManager, self).init_host()
self.driver.metadata_forward()
self.driver.init_host()
self.driver.metadata_forward()
def allocate_fixed_ip(self, context, instance_id, *args, **kwargs):
"""Gets a fixed ip from the pool."""
@@ -496,7 +501,7 @@ class VlanManager(NetworkManager):
network_ref['bridge'])
def create_networks(self, context, cidr, num_networks, network_size,
vlan_start, vpn_start, cidr_v6):
cidr_v6, vlan_start, vpn_start):
"""Create networks based on parameters."""
fixed_net = IPy.IP(cidr)
fixed_net_v6 = IPy.IP(cidr_v6)

View File

@@ -157,8 +157,9 @@ class Service(object):
report_interval = FLAGS.report_interval
if not periodic_interval:
periodic_interval = FLAGS.periodic_interval
logging.audit(_("Starting %s node (version %s)"), topic,
version.version_string_with_vcs())
vcs_string = version.version_string_with_vcs()
logging.audit(_("Starting %(topic)s node (version %(vcs_string)s)")
% locals())
service_obj = cls(host, binary, topic, manager,
report_interval, periodic_interval)

View File

@@ -69,9 +69,10 @@ class TestCase(unittest.TestCase):
network_manager.VlanManager().create_networks(ctxt,
FLAGS.fixed_range,
5, 16,
FLAGS.fixed_range_v6,
FLAGS.vlan_start,
FLAGS.vpn_start,
FLAGS.fixed_range_v6)
)
# emulate some of the mox stuff, we can't use the metaclass
# because it screws with our generators

View File

@@ -143,6 +143,7 @@ class LocalImageServiceTest(unittest.TestCase,
def tearDown(self):
self.service.delete_all()
self.service.delete_imagedir()
self.stubs.UnsetAll()

View File

@@ -76,7 +76,7 @@ class ServersTest(unittest.TestCase):
fakes.stub_out_key_pair_funcs(self.stubs)
fakes.stub_out_image_service(self.stubs)
self.stubs.Set(nova.db.api, 'instance_get_all', return_servers)
self.stubs.Set(nova.db.api, 'instance_get_by_id', return_server)
self.stubs.Set(nova.db.api, 'instance_get', return_server)
self.stubs.Set(nova.db.api, 'instance_get_all_by_user',
return_servers)
self.stubs.Set(nova.db.api, 'instance_add_security_group',

View File

@@ -36,6 +36,7 @@ from nova.auth import manager
class FakeHttplibSocket(object):
"""a fake socket implementation for httplib.HTTPResponse, trivial"""
def __init__(self, response_string):
self.response_string = response_string
self._buffer = StringIO.StringIO(response_string)
def makefile(self, _mode, _other):
@@ -66,13 +67,16 @@ class FakeHttplibConnection(object):
# For some reason, the response doesn't have "HTTP/1.0 " prepended; I
# guess that's a function the web server usually provides.
resp = "HTTP/1.0 %s" % resp
sock = FakeHttplibSocket(resp)
self.http_response = httplib.HTTPResponse(sock)
self.sock = FakeHttplibSocket(resp)
self.http_response = httplib.HTTPResponse(self.sock)
self.http_response.begin()
def getresponse(self):
return self.http_response
def getresponsebody(self):
return self.sock.response_string
def close(self):
"""Required for compatibility with boto/tornado"""
pass
@@ -104,7 +108,7 @@ class ApiEc2TestCase(test.TestCase):
self.app = ec2.Authenticate(ec2.Requestify(ec2.Executor(),
'nova.api.ec2.cloud.CloudController'))
def expect_http(self, host=None, is_secure=False):
def expect_http(self, host=None, is_secure=False, api_version=None):
"""Returns a new EC2 connection"""
self.ec2 = boto.connect_ec2(
aws_access_key_id='fake',
@@ -113,13 +117,31 @@ class ApiEc2TestCase(test.TestCase):
region=regioninfo.RegionInfo(None, 'test', self.host),
port=8773,
path='/services/Cloud')
if api_version:
self.ec2.APIVersion = api_version
self.mox.StubOutWithMock(self.ec2, 'new_http_connection')
http = FakeHttplibConnection(
self.http = FakeHttplibConnection(
self.app, '%s:8773' % (self.host), False)
# pylint: disable-msg=E1103
self.ec2.new_http_connection(host, is_secure).AndReturn(http)
return http
self.ec2.new_http_connection(host, is_secure).AndReturn(self.http)
return self.http
def test_xmlns_version_matches_request_version(self):
self.expect_http(api_version='2010-10-30')
self.mox.ReplayAll()
user = self.manager.create_user('fake', 'fake', 'fake')
project = self.manager.create_project('fake', 'fake', 'fake')
# Any request should be fine
self.ec2.get_all_instances()
self.assertTrue(self.ec2.APIVersion in self.http.getresponsebody(),
'The version in the xmlns of the response does '
'not match the API version given in the request.')
self.manager.delete_project(project)
self.manager.delete_user(user)
def test_describe_instances(self):
"""Test that, after creating a user and a project, the describe

View File

@@ -0,0 +1,100 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
#
# Copyright 2011 OpenStack LLC
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import glob
import logging
import os
import re
import sys
import unittest
import nova
class LocalizationTestCase(unittest.TestCase):
def test_multiple_positional_format_placeholders(self):
pat = re.compile("\W_\(")
single_pat = re.compile("\W%\W")
root_path = os.path.dirname(nova.__file__)
problems = {}
for root, dirs, files in os.walk(root_path):
for fname in files:
if not fname.endswith(".py"):
continue
pth = os.path.join(root, fname)
txt = fulltext = file(pth).read()
txt_lines = fulltext.splitlines()
if not pat.search(txt):
continue
problems[pth] = []
pos = txt.find("_(")
while pos > -1:
# Make sure that this isn't part of a dunder;
# e.g., __init__(...
# or something like 'self.assert_(...'
test_txt = txt[pos - 1: pos + 10]
if not (pat.search(test_txt)):
txt = txt[pos + 2:]
pos = txt.find("_(")
continue
pos += 2
txt = txt[pos:]
innerChars = []
# Count pairs of open/close parens until _() closing
# paren is found.
parenCount = 1
pos = 0
while parenCount > 0:
char = txt[pos]
if char == "(":
parenCount += 1
elif char == ")":
parenCount -= 1
innerChars.append(char)
pos += 1
inner_all = "".join(innerChars)
# Filter out '%%' and '%('
inner = inner_all.replace("%%", "").replace("%(", "")
# Filter out the single '%' operators
inner = single_pat.sub("", inner)
# Within the remaining content, count %
fmtCount = inner.count("%")
if fmtCount > 1:
inner_first = inner_all.splitlines()[0]
lns = ["%s" % (p + 1)
for p, t in enumerate(txt_lines)
if inner_first in t]
lnums = ", ".join(lns)
# Using ugly string concatenation to avoid having
# this test fail itself.
inner_all = "_" + "(" + "%s" % inner_all
problems[pth].append("Line: %s Text: %s" %
(lnums, inner_all))
# Look for more
pos = txt.find("_(")
if not problems[pth]:
del problems[pth]
if problems:
out = ["Problem(s) found in localized string formatting",
"(see http://www.gnu.org/software/hello/manual/"
"gettext/Python.html for more information)",
"",
" ------------ Files to fix ------------"]
for pth in problems:
out.append(" %s:" % pth)
for val in set(problems[pth]):
out.append(" %s" % val)
raise AssertionError("\n".join(out))

View File

@@ -221,7 +221,12 @@ class IptablesFirewallTestCase(test.TestCase):
self.project = self.manager.create_project('fake', 'fake', 'fake')
self.context = context.RequestContext('fake', 'fake')
self.network = utils.import_object(FLAGS.network_manager)
self.fw = libvirt_conn.IptablesFirewallDriver()
class FakeLibvirtConnection(object):
pass
self.fake_libvirt_connection = FakeLibvirtConnection()
self.fw = libvirt_conn.IptablesFirewallDriver(
get_connection=lambda: self.fake_libvirt_connection)
def tearDown(self):
self.manager.delete_project(self.project)
@@ -474,6 +479,19 @@ class NWFilterTestCase(test.TestCase):
'project_id': 'fake'})
inst_id = instance_ref['id']
ip = '10.11.12.13'
network_ref = db.project_get_network(self.context,
'fake')
fixed_ip = {'address': ip,
'network_id': network_ref['id']}
admin_ctxt = context.get_admin_context()
db.fixed_ip_create(admin_ctxt, fixed_ip)
db.fixed_ip_update(admin_ctxt, ip, {'allocated': True,
'instance_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']

View File

@@ -206,21 +206,17 @@ def last_octet(address):
def get_my_linklocal(interface):
try:
if_str = execute("ip -f inet6 -o addr show %s" % interface)
condition = "\s+inet6\s+([0-9a-f:]+/\d+)\s+scope\s+link"
condition = "\s+inet6\s+([0-9a-f:]+)/\d+\s+scope\s+link"
links = [re.search(condition, x) for x in if_str[0].split('\n')]
address = [w.group(1) for w in links if w is not None]
if address[0] is not None:
return address[0]
else:
return 'fe00::'
except IndexError as ex:
LOG.warn(_("Couldn't get Link Local IP of %(interface)s :%(ex)s")
% locals())
except ProcessExecutionError as ex:
LOG.warn(_("Couldn't get Link Local IP of %(interface)s :%(ex)s")
% locals())
except:
return 'fe00::'
raise exception.Error(_("Link Local address is not found.:%s")
% if_str)
except Exception as ex:
raise exception.Error(_("Couldn't get Link Local IP of %(interface)s"
" :%(ex)s") % locals())
def to_global_ipv6(prefix, mac):

View File

@@ -76,9 +76,10 @@ class FakeConnection(object):
cls._instance = cls()
return cls._instance
def init_host(self):
def init_host(self, host):
"""
Initialize anything that is necessary for the driver to function
Initialize anything that is necessary for the driver to function,
including catching up with currently running VM's on the given host.
"""
return

View File

@@ -113,7 +113,7 @@ class HyperVConnection(object):
self._conn = wmi.WMI(moniker='//./root/virtualization')
self._cim_conn = wmi.WMI(moniker='//./root/cimv2')
def init_host(self):
def init_host(self, host):
#FIXME(chiradeep): implement this
LOG.debug(_('In init host'))
pass
@@ -191,7 +191,7 @@ class HyperVConnection(object):
vcpus = long(instance['vcpus'])
procsetting.VirtualQuantity = vcpus
procsetting.Reservation = vcpus
procsetting.Limit = vcpus
procsetting.Limit = 100000 # static assignment to 100%
(job, ret_val) = vs_man_svc.ModifyVirtualSystemResources(
vm.path_(), [procsetting.GetText_(1)])

View File

@@ -111,5 +111,8 @@ def _image_path(path):
def image_url(image):
if FLAGS.image_service == "nova.image.glance.GlanceImageService":
return "http://%s:%s/images/%s" % (FLAGS.glance_host,
FLAGS.glance_port, image)
return "http://%s:%s/_images/%s/image" % (FLAGS.s3_host, FLAGS.s3_port,
image)

View File

@@ -76,9 +76,11 @@
<filterref filter="nova-instance-${name}">
<parameter name="IP" value="${ip_address}" />
<parameter name="DHCPSERVER" value="${dhcp_server}" />
<parameter name="RASERVER" value="${ra_server}" />
#if $getVar('extra_params', False)
${extra_params}
#end if
#if $getVar('ra_server', False)
<parameter name="RASERVER" value="${ra_server}" />
#end if
</filterref>
</interface>

View File

@@ -149,16 +149,34 @@ class LibvirtConnection(object):
self._wrapped_conn = None
self.read_only = read_only
self.nwfilter = NWFilterFirewall(self._get_connection)
fw_class = utils.import_class(FLAGS.firewall_driver)
self.firewall_driver = fw_class(get_connection=self._get_connection)
if not FLAGS.firewall_driver:
self.firewall_driver = self.nwfilter
self.nwfilter.handle_security_groups = True
else:
self.firewall_driver = utils.import_object(FLAGS.firewall_driver)
def init_host(self, host):
# Adopt existing VM's running here
ctxt = context.get_admin_context()
for instance in db.instance_get_all_by_host(ctxt, host):
try:
LOG.debug(_('Checking state of %s'), instance['name'])
state = self.get_info(instance['name'])['state']
except exception.NotFound:
state = power_state.SHUTOFF
def init_host(self):
pass
LOG.debug(_('Current state of %(name)s was %(state)s.'),
{'name': instance['name'], 'state': state})
db.instance_set_state(ctxt, instance['id'], state)
if state == power_state.SHUTOFF:
# TODO(soren): This is what the compute manager does when you
# terminate # an instance. At some point I figure we'll have a
# "terminated" state and some sort of cleanup job that runs
# occasionally, cleaning them out.
db.instance_destroy(ctxt, instance['id'])
if state != power_state.RUNNING:
continue
self.firewall_driver.prepare_instance_filter(instance)
self.firewall_driver.apply_instance_filter(instance)
def _get_connection(self):
if not self._wrapped_conn or not self._test_connection():
@@ -386,7 +404,7 @@ class LibvirtConnection(object):
instance['id'],
power_state.NOSTATE,
'launching')
self.nwfilter.setup_basic_filtering(instance)
self.firewall_driver.setup_basic_filtering(instance)
self.firewall_driver.prepare_instance_filter(instance)
self._create_image(instance, xml)
self._conn.createXML(xml, 0)
@@ -655,8 +673,7 @@ class LibvirtConnection(object):
# Assume that the gateway also acts as the dhcp server.
dhcp_server = network['gateway']
ra_server = network['ra_server']
if not ra_server:
ra_server = 'fd00::'
if FLAGS.allow_project_net_traffic:
if FLAGS.use_ipv6:
net, mask = _get_net_and_mask(network['cidr'])
@@ -695,11 +712,13 @@ class LibvirtConnection(object):
'mac_address': instance['mac_address'],
'ip_address': ip_address,
'dhcp_server': dhcp_server,
'ra_server': ra_server,
'extra_params': extra_params,
'rescue': rescue,
'local': instance_type['local_gb'],
'driver_type': driver_type}
if ra_server:
xml_info['ra_server'] = ra_server + "/128"
if not rescue:
if instance['kernel_id']:
xml_info['kernel'] = xml_info['basepath'] + "/kernel"
@@ -882,6 +901,20 @@ class FirewallDriver(object):
the security group."""
raise NotImplementedError()
def setup_basic_filtering(self, instance):
"""Create rules to block spoofing and allow dhcp.
This gets called when spawning an instance, before
:method:`prepare_instance_filter`.
"""
raise NotImplementedError()
def _ra_server_for_instance(self, instance):
network = db.network_get_by_instance(context.get_admin_context(),
instance['id'])
return network['ra_server']
class NWFilterFirewall(FirewallDriver):
"""
@@ -929,11 +962,15 @@ class NWFilterFirewall(FirewallDriver):
"""
def __init__(self, get_connection):
def __init__(self, get_connection, **kwargs):
self._libvirt_get_connection = get_connection
self.static_filters_configured = False
self.handle_security_groups = False
def apply_instance_filter(self, instance):
"""No-op. Everything is done in prepare_instance_filter"""
pass
def _get_connection(self):
return self._libvirt_get_connection()
_conn = property(_get_connection)
@@ -1092,7 +1129,9 @@ class NWFilterFirewall(FirewallDriver):
'nova-base-ipv6',
'nova-allow-dhcp-server']
if FLAGS.use_ipv6:
instance_secgroup_filter_children += ['nova-allow-ra-server']
ra_server = self._ra_server_for_instance(instance)
if ra_server:
instance_secgroup_filter_children += ['nova-allow-ra-server']
ctxt = context.get_admin_context()
@@ -1119,10 +1158,6 @@ class NWFilterFirewall(FirewallDriver):
return
def apply_instance_filter(self, instance):
"""No-op. Everything is done in prepare_instance_filter"""
pass
def refresh_security_group_rules(self, security_group_id):
return self._define_filter(
self.security_group_to_nwfilter_xml(security_group_id))
@@ -1170,9 +1205,14 @@ class NWFilterFirewall(FirewallDriver):
class IptablesFirewallDriver(FirewallDriver):
def __init__(self, execute=None):
def __init__(self, execute=None, **kwargs):
self.execute = execute or utils.execute
self.instances = {}
self.nwfilter = NWFilterFirewall(kwargs['get_connection'])
def setup_basic_filtering(self, instance):
"""Use NWFilter from libvirt for this."""
return self.nwfilter.setup_basic_filtering(instance)
def apply_instance_filter(self, instance):
"""No-op. Everything is done in prepare_instance_filter"""
@@ -1228,6 +1268,7 @@ class IptablesFirewallDriver(FirewallDriver):
our_chains += [':nova-local - [0:0]']
our_rules += ['-A FORWARD -j nova-local']
our_rules += ['-A OUTPUT -j nova-local']
security_groups = {}
# Add our chains
@@ -1268,13 +1309,23 @@ class IptablesFirewallDriver(FirewallDriver):
if(ip_version == 4):
# Allow DHCP responses
dhcp_server = self._dhcp_server_for_instance(instance)
our_rules += ['-A %s -s %s -p udp --sport 67 --dport 68' %
(chain_name, dhcp_server)]
our_rules += ['-A %s -s %s -p udp --sport 67 --dport 68 '
'-j ACCEPT ' % (chain_name, dhcp_server)]
#Allow project network traffic
if (FLAGS.allow_project_net_traffic):
cidr = self._project_cidr_for_instance(instance)
our_rules += ['-A %s -s %s -j ACCEPT' % (chain_name, cidr)]
elif(ip_version == 6):
# Allow RA responses
ra_server = self._ra_server_for_instance(instance)
our_rules += ['-A %s -s %s -p icmpv6' %
(chain_name, ra_server)]
if ra_server:
our_rules += ['-A %s -s %s -p icmpv6 -j ACCEPT' %
(chain_name, ra_server + "/128")]
#Allow project network traffic
if (FLAGS.allow_project_net_traffic):
cidrv6 = self._project_cidrv6_for_instance(instance)
our_rules += ['-A %s -s %s -j ACCEPT' %
(chain_name, cidrv6)]
# If nothing matches, jump to the fallback chain
our_rules += ['-A %s -j nova-fallback' % (chain_name,)]
@@ -1369,3 +1420,13 @@ class IptablesFirewallDriver(FirewallDriver):
network = db.network_get_by_instance(context.get_admin_context(),
instance['id'])
return network['ra_server']
def _project_cidr_for_instance(self, instance):
network = db.network_get_by_instance(context.get_admin_context(),
instance['id'])
return network['cidr']
def _project_cidrv6_for_instance(self, instance):
network = db.network_get_by_instance(context.get_admin_context(),
instance['id'])
return network['cidr_v6']

View File

@@ -640,7 +640,7 @@ def with_vdi_attached_here(session, vdi, read_only, f):
session.get_xenapi().VBD.plug(vbd)
LOG.debug(_('Plugging VBD %s done.'), vbd)
orig_dev = session.get_xenapi().VBD.get_device(vbd)
LOG.debug(_('VBD %s plugged as %s'), vbd, orig_dev)
LOG.debug(_('VBD %(vbd)s plugged as %(orig_dev)s') % locals())
dev = remap_vbd_dev(orig_dev)
if dev != orig_dev:
LOG.debug(_('VBD %(vbd)s plugged into wrong dev, '

View File

@@ -149,7 +149,7 @@ class VMOps(object):
if isinstance(instance_or_vm, (int, long)):
ctx = context.get_admin_context()
try:
instance_obj = db.instance_get_by_id(ctx, instance_or_vm)
instance_obj = db.instance_get(ctx, instance_or_vm)
instance_name = instance_obj.name
except exception.NotFound:
# The unit tests screw this up, as they use an integer for

View File

@@ -141,7 +141,7 @@ class XenAPIConnection(object):
self._vmops = VMOps(session)
self._volumeops = VolumeOps(session)
def init_host(self):
def init_host(self, host):
#FIXME(armando): implement this
#NOTE(armando): would we need a method
#to call when shutting down the host?

View File

@@ -26,6 +26,7 @@ import logging
import logging.handlers
import re
import time
import XenAPI
##### Logging setup