merge recent revision(version of 2010/12/28)
Change: 
   1. Use greenthread instead of defer at nova.virt.libvirt_conn.live_migration.
   2. Move nova.scheduler.manager.live_migration to nova.scheduler.driver
   3. Move nova.scheduler.manager.has_enough_resource to nova.scheduler.driver
   4. Any check routine in nova-manage.instance.live_migration is moved to
      nova.scheduler.driver.schedule_live_migration.
			
			
This commit is contained in:
		
							
								
								
									
										8
									
								
								.mailmap
									
									
									
									
									
								
							
							
						
						
									
										8
									
								
								.mailmap
									
									
									
									
									
								
							@@ -19,11 +19,11 @@
 | 
				
			|||||||
<mordred@inaugust.com> <mordred@hudson>
 | 
					<mordred@inaugust.com> <mordred@hudson>
 | 
				
			||||||
<paul@openstack.org> <pvoccio@castor.local>
 | 
					<paul@openstack.org> <pvoccio@castor.local>
 | 
				
			||||||
<paul@openstack.org> <paul.voccio@rackspace.com>
 | 
					<paul@openstack.org> <paul.voccio@rackspace.com>
 | 
				
			||||||
 | 
					<soren.hansen@rackspace.com> <soren@linux2go.dk>
 | 
				
			||||||
<todd@ansolabs.com> <todd@lapex>
 | 
					<todd@ansolabs.com> <todd@lapex>
 | 
				
			||||||
<todd@ansolabs.com> <todd@rubidine.com>
 | 
					<todd@ansolabs.com> <todd@rubidine.com>
 | 
				
			||||||
<vishvananda@gmail.com> <vishvananda@yahoo.com>
 | 
					<vishvananda@gmail.com> <vishvananda@yahoo.com>
 | 
				
			||||||
<vishvananda@gmail.com> <root@mirror.nasanebula.net>
 | 
					<vishvananda@gmail.com> <root@mirror.nasanebula.net>
 | 
				
			||||||
# These are from people who failed to set a proper committer
 | 
					<vishvananda@gmail.com> <root@ubuntu>
 | 
				
			||||||
. <root@tonbuntu>
 | 
					<sleepsonthefloor@gmail.com> <root@tonbuntu>
 | 
				
			||||||
. <laner@controller>
 | 
					<rlane@wikimedia.org> <laner@controller>
 | 
				
			||||||
. <root@ubuntu>
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										10
									
								
								Authors
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								Authors
									
									
									
									
									
								
							@@ -3,8 +3,12 @@ Anne Gentle <anne@openstack.org>
 | 
				
			|||||||
Anthony Young <sleepsonthefloor@gmail.com>
 | 
					Anthony Young <sleepsonthefloor@gmail.com>
 | 
				
			||||||
Armando Migliaccio <Armando.Migliaccio@eu.citrix.com>
 | 
					Armando Migliaccio <Armando.Migliaccio@eu.citrix.com>
 | 
				
			||||||
Chris Behrens <cbehrens@codestud.com>
 | 
					Chris Behrens <cbehrens@codestud.com>
 | 
				
			||||||
 | 
					Chmouel Boudjnah <chmouel@chmouel.com>
 | 
				
			||||||
 | 
					David Pravec <David.Pravec@danix.org>
 | 
				
			||||||
Dean Troyer <dtroyer@gmail.com>
 | 
					Dean Troyer <dtroyer@gmail.com>
 | 
				
			||||||
Devin Carlen <devin.carlen@gmail.com>
 | 
					Devin Carlen <devin.carlen@gmail.com>
 | 
				
			||||||
 | 
					Ed Leafe <ed@leafe.com>
 | 
				
			||||||
 | 
					Eldar Nugaev <enugaev@griddynamics.com>
 | 
				
			||||||
Eric Day <eday@oddments.org>
 | 
					Eric Day <eday@oddments.org>
 | 
				
			||||||
Ewan Mellor <ewan.mellor@citrix.com>
 | 
					Ewan Mellor <ewan.mellor@citrix.com>
 | 
				
			||||||
Hisaki Ohara <hisaki.ohara@intel.com>
 | 
					Hisaki Ohara <hisaki.ohara@intel.com>
 | 
				
			||||||
@@ -12,6 +16,7 @@ Jay Pipes <jaypipes@gmail.com>
 | 
				
			|||||||
Jesse Andrews <anotherjesse@gmail.com>
 | 
					Jesse Andrews <anotherjesse@gmail.com>
 | 
				
			||||||
Joe Heck <heckj@mac.com>
 | 
					Joe Heck <heckj@mac.com>
 | 
				
			||||||
Joel Moore <joelbm24@gmail.com>
 | 
					Joel Moore <joelbm24@gmail.com>
 | 
				
			||||||
 | 
					Jonathan Bryce <jbryce@jbryce.com>
 | 
				
			||||||
Josh Kearney <josh.kearney@rackspace.com>
 | 
					Josh Kearney <josh.kearney@rackspace.com>
 | 
				
			||||||
Joshua McKenty <jmckenty@gmail.com>
 | 
					Joshua McKenty <jmckenty@gmail.com>
 | 
				
			||||||
Justin Santa Barbara <justin@fathomdb.com>
 | 
					Justin Santa Barbara <justin@fathomdb.com>
 | 
				
			||||||
@@ -20,8 +25,13 @@ Michael Gundlach <michael.gundlach@rackspace.com>
 | 
				
			|||||||
Monty Taylor <mordred@inaugust.com>
 | 
					Monty Taylor <mordred@inaugust.com>
 | 
				
			||||||
Paul Voccio <paul@openstack.org>
 | 
					Paul Voccio <paul@openstack.org>
 | 
				
			||||||
Rick Clark <rick@openstack.org>
 | 
					Rick Clark <rick@openstack.org>
 | 
				
			||||||
 | 
					Ryan Lane <rlane@wikimedia.org>
 | 
				
			||||||
 | 
					Ryan Lucio <rlucio@internap.com>
 | 
				
			||||||
 | 
					Sandy Walsh <sandy.walsh@rackspace.com>
 | 
				
			||||||
Soren Hansen <soren.hansen@rackspace.com>
 | 
					Soren Hansen <soren.hansen@rackspace.com>
 | 
				
			||||||
 | 
					Thierry Carrez <thierry@openstack.org>
 | 
				
			||||||
Todd Willey <todd@ansolabs.com>
 | 
					Todd Willey <todd@ansolabs.com>
 | 
				
			||||||
 | 
					Trey Morris <trey.morris@rackspace.com>
 | 
				
			||||||
Vishvananda Ishaya <vishvananda@gmail.com>
 | 
					Vishvananda Ishaya <vishvananda@gmail.com>
 | 
				
			||||||
Youcef Laribi <Youcef.Laribi@eu.citrix.com>
 | 
					Youcef Laribi <Youcef.Laribi@eu.citrix.com>
 | 
				
			||||||
Zhixue Wu <Zhixue.Wu@citrix.com>
 | 
					Zhixue Wu <Zhixue.Wu@citrix.com>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,16 +16,24 @@
 | 
				
			|||||||
#    License for the specific language governing permissions and limitations
 | 
					#    License for the specific language governing permissions and limitations
 | 
				
			||||||
#    under the License.
 | 
					#    under the License.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# ARG is the id of the user
 | 
					# $1 is the id of the project and $2 is the subject of the cert
 | 
				
			||||||
export SUBJ="/C=US/ST=California/L=MountainView/O=AnsoLabs/OU=NovaDev/CN=customer-intCA-$1"
 | 
					NAME=$1
 | 
				
			||||||
mkdir INTER/$1
 | 
					SUBJ=$2
 | 
				
			||||||
cd INTER/$1
 | 
					mkdir -p projects/$NAME
 | 
				
			||||||
 | 
					cd projects/$NAME
 | 
				
			||||||
cp ../../openssl.cnf.tmpl openssl.cnf
 | 
					cp ../../openssl.cnf.tmpl openssl.cnf
 | 
				
			||||||
sed -i -e s/%USERNAME%/$1/g openssl.cnf
 | 
					sed -i -e s/%USERNAME%/$NAME/g openssl.cnf
 | 
				
			||||||
mkdir certs crl newcerts private
 | 
					mkdir certs crl newcerts private
 | 
				
			||||||
 | 
					openssl req -new -x509 -extensions v3_ca -keyout private/cakey.pem -out cacert.pem -days 365 -config ./openssl.cnf -batch -nodes
 | 
				
			||||||
echo "10" > serial
 | 
					echo "10" > serial
 | 
				
			||||||
touch index.txt
 | 
					touch index.txt
 | 
				
			||||||
openssl genrsa -out private/cakey.pem 1024 -config ./openssl.cnf -batch -nodes
 | 
					# NOTE(vish): Disabling intermediate ca's because we don't actually need them.
 | 
				
			||||||
openssl req -new -sha2 -key private/cakey.pem -out ../../reqs/inter$1.csr -batch -subj "$SUBJ"
 | 
					#             It makes more sense to have each project have its own root ca.
 | 
				
			||||||
cd ../../
 | 
					# openssl genrsa -out private/cakey.pem 1024 -config ./openssl.cnf -batch -nodes
 | 
				
			||||||
openssl ca -extensions v3_ca -days 365 -out INTER/$1/cacert.pem -in reqs/inter$1.csr -config openssl.cnf -batch
 | 
					# openssl req -new -sha256 -key private/cakey.pem -out ../../reqs/inter$NAME.csr -batch -subj "$SUBJ"
 | 
				
			||||||
 | 
					openssl ca -gencrl -config ./openssl.cnf -out crl.pem
 | 
				
			||||||
 | 
					if [ "`id -u`" != "`grep nova /etc/passwd | cut -d':' -f3`" ]; then
 | 
				
			||||||
 | 
					    sudo chown -R nova:nogroup .
 | 
				
			||||||
 | 
					fi
 | 
				
			||||||
 | 
					# cd ../../
 | 
				
			||||||
 | 
					# openssl ca -extensions v3_ca -days 365 -out INTER/$NAME/cacert.pem -in reqs/inter$NAME.csr -config openssl.cnf -batch
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -25,4 +25,5 @@ else
 | 
				
			|||||||
    openssl req -new -x509 -extensions v3_ca -keyout private/cakey.pem -out cacert.pem -days 365 -config ./openssl.cnf -batch -nodes
 | 
					    openssl req -new -x509 -extensions v3_ca -keyout private/cakey.pem -out cacert.pem -days 365 -config ./openssl.cnf -batch -nodes
 | 
				
			||||||
    touch index.txt
 | 
					    touch index.txt
 | 
				
			||||||
    echo "10" > serial
 | 
					    echo "10" > serial
 | 
				
			||||||
 | 
					    openssl ca -gencrl -config ./openssl.cnf -out crl.pem
 | 
				
			||||||
fi
 | 
					fi
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										34
									
								
								nova/tests/validator_unittest.py → CA/genvpn.sh
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										34
									
								
								nova/tests/validator_unittest.py → CA/genvpn.sh
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							@@ -1,3 +1,4 @@
 | 
				
			|||||||
 | 
					#!/bin/bash
 | 
				
			||||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
 | 
					# vim: tabstop=4 shiftwidth=4 softtabstop=4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Copyright 2010 United States Government as represented by the
 | 
					# Copyright 2010 United States Government as represented by the
 | 
				
			||||||
@@ -16,27 +17,20 @@
 | 
				
			|||||||
#    License for the specific language governing permissions and limitations
 | 
					#    License for the specific language governing permissions and limitations
 | 
				
			||||||
#    under the License.
 | 
					#    under the License.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import logging
 | 
					# This gets zipped and run on the cloudpipe-managed OpenVPN server
 | 
				
			||||||
import unittest
 | 
					NAME=$1
 | 
				
			||||||
 | 
					SUBJ=$2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from nova import flags
 | 
					mkdir -p projects/$NAME
 | 
				
			||||||
from nova import test
 | 
					cd projects/$NAME
 | 
				
			||||||
from nova import validate
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# generate a server priv key
 | 
				
			||||||
 | 
					openssl genrsa -out server.key 2048
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ValidationTestCase(test.TrialTestCase):
 | 
					# generate a server CSR
 | 
				
			||||||
    def setUp(self):
 | 
					openssl req -new -key server.key -out server.csr -batch -subj "$SUBJ"
 | 
				
			||||||
        super(ValidationTestCase, self).setUp()
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def tearDown(self):
 | 
					novauid=`getent passwd nova | awk -F: '{print $3}'`
 | 
				
			||||||
        super(ValidationTestCase, self).tearDown()
 | 
					if [ ! -z "${novauid}" ] && [ "`id -u`" != "${novauid}" ]; then
 | 
				
			||||||
 | 
					    sudo chown -R nova:nogroup .
 | 
				
			||||||
    def test_type_validation(self):
 | 
					fi
 | 
				
			||||||
        self.assertTrue(type_case("foo", 5, 1))
 | 
					 | 
				
			||||||
        self.assertRaises(TypeError, type_case, "bar", "5", 1)
 | 
					 | 
				
			||||||
        self.assertRaises(TypeError, type_case, None, 5, 1)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@validate.typetest(instanceid=str, size=int, number_of_instances=int)
 | 
					 | 
				
			||||||
def type_case(instanceid, size, number_of_instances):
 | 
					 | 
				
			||||||
    return True
 | 
					 | 
				
			||||||
@@ -24,7 +24,6 @@ dir			= .
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
[ ca ]
 | 
					[ ca ]
 | 
				
			||||||
default_ca		= CA_default
 | 
					default_ca		= CA_default
 | 
				
			||||||
unique_subject		= no
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
[ CA_default ]
 | 
					[ CA_default ]
 | 
				
			||||||
serial			= $dir/serial
 | 
					serial			= $dir/serial
 | 
				
			||||||
@@ -32,6 +31,8 @@ database		= $dir/index.txt
 | 
				
			|||||||
new_certs_dir		= $dir/newcerts
 | 
					new_certs_dir		= $dir/newcerts
 | 
				
			||||||
certificate		= $dir/cacert.pem
 | 
					certificate		= $dir/cacert.pem
 | 
				
			||||||
private_key		= $dir/private/cakey.pem
 | 
					private_key		= $dir/private/cakey.pem
 | 
				
			||||||
 | 
					unique_subject		= no
 | 
				
			||||||
 | 
					default_crl_days	= 365
 | 
				
			||||||
default_days		= 365
 | 
					default_days		= 365
 | 
				
			||||||
default_md		= md5
 | 
					default_md		= md5
 | 
				
			||||||
preserve		= no
 | 
					preserve		= no
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -13,7 +13,7 @@ include nova/cloudpipe/client.ovpn.template
 | 
				
			|||||||
include nova/compute/fakevirtinstance.xml
 | 
					include nova/compute/fakevirtinstance.xml
 | 
				
			||||||
include nova/compute/interfaces.template
 | 
					include nova/compute/interfaces.template
 | 
				
			||||||
include nova/virt/interfaces.template
 | 
					include nova/virt/interfaces.template
 | 
				
			||||||
include nova/virt/libvirt.*.xml.template
 | 
					include nova/virt/libvirt*.xml.template
 | 
				
			||||||
include nova/tests/CA/
 | 
					include nova/tests/CA/
 | 
				
			||||||
include nova/tests/CA/cacert.pem
 | 
					include nova/tests/CA/cacert.pem
 | 
				
			||||||
include nova/tests/CA/private/
 | 
					include nova/tests/CA/private/
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -147,7 +147,7 @@
 | 
				
			|||||||
       
 | 
					       
 | 
				
			||||||
 | 
					
 | 
				
			||||||
3. error checking
 | 
					3. error checking
 | 
				
			||||||
   When live migration fails somehow, error message shows at:
 | 
					   When live migration fails somehow, error messages are shown at:
 | 
				
			||||||
   a. scheduler logfile
 | 
					   a. scheduler logfile
 | 
				
			||||||
   b. source compute node logfile
 | 
					   b. source compute node logfile
 | 
				
			||||||
   c. dest compute node logfile
 | 
					   c. dest compute node logfile
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										23
									
								
								bin/nova-api
									
									
									
									
									
								
							
							
						
						
									
										23
									
								
								bin/nova-api
									
									
									
									
									
								
							@@ -17,10 +17,10 @@
 | 
				
			|||||||
#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
					#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
				
			||||||
#    See the License for the specific language governing permissions and
 | 
					#    See the License for the specific language governing permissions and
 | 
				
			||||||
#    limitations under the License.
 | 
					#    limitations under the License.
 | 
				
			||||||
"""
 | 
					 | 
				
			||||||
Nova API daemon.
 | 
					 | 
				
			||||||
"""
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					"""Starter script for Nova API."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import gettext
 | 
				
			||||||
import os
 | 
					import os
 | 
				
			||||||
import sys
 | 
					import sys
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -32,9 +32,13 @@ possible_topdir = os.path.normpath(os.path.join(os.path.abspath(sys.argv[0]),
 | 
				
			|||||||
if os.path.exists(os.path.join(possible_topdir, 'nova', '__init__.py')):
 | 
					if os.path.exists(os.path.join(possible_topdir, 'nova', '__init__.py')):
 | 
				
			||||||
    sys.path.insert(0, possible_topdir)
 | 
					    sys.path.insert(0, possible_topdir)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					gettext.install('nova', unicode=1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from nova import api
 | 
				
			||||||
from nova import flags
 | 
					from nova import flags
 | 
				
			||||||
from nova import utils
 | 
					from nova import utils
 | 
				
			||||||
from nova import server
 | 
					from nova import wsgi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
FLAGS = flags.FLAGS
 | 
					FLAGS = flags.FLAGS
 | 
				
			||||||
flags.DEFINE_integer('osapi_port', 8774, 'OpenStack API port')
 | 
					flags.DEFINE_integer('osapi_port', 8774, 'OpenStack API port')
 | 
				
			||||||
@@ -43,15 +47,10 @@ flags.DEFINE_integer('ec2api_port', 8773, 'EC2 API port')
 | 
				
			|||||||
flags.DEFINE_string('ec2api_host', '0.0.0.0', 'EC2 API host')
 | 
					flags.DEFINE_string('ec2api_host', '0.0.0.0', 'EC2 API host')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def main(_args):
 | 
					if __name__ == '__main__':
 | 
				
			||||||
    from nova import api
 | 
					    utils.default_flagfile()
 | 
				
			||||||
    from nova import wsgi
 | 
					    FLAGS(sys.argv)
 | 
				
			||||||
    server = wsgi.Server()
 | 
					    server = wsgi.Server()
 | 
				
			||||||
    server.start(api.API('os'), FLAGS.osapi_port, host=FLAGS.osapi_host)
 | 
					    server.start(api.API('os'), FLAGS.osapi_port, host=FLAGS.osapi_host)
 | 
				
			||||||
    server.start(api.API('ec2'), FLAGS.ec2api_port, host=FLAGS.ec2api_host)
 | 
					    server.start(api.API('ec2'), FLAGS.ec2api_port, host=FLAGS.ec2api_host)
 | 
				
			||||||
    server.wait()
 | 
					    server.wait()
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if __name__ == '__main__':
 | 
					 | 
				
			||||||
    utils.default_flagfile()
 | 
					 | 
				
			||||||
    server.serve('nova-api', main)
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										68
									
								
								bin/nova-combined
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										68
									
								
								bin/nova-combined
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,68 @@
 | 
				
			|||||||
 | 
					#!/usr/bin/env python
 | 
				
			||||||
 | 
					# 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.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					"""Combined starter script for Nova services."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import eventlet
 | 
				
			||||||
 | 
					eventlet.monkey_patch()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import gettext
 | 
				
			||||||
 | 
					import os
 | 
				
			||||||
 | 
					import sys
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# If ../nova/__init__.py exists, add ../ to Python search path, so that
 | 
				
			||||||
 | 
					# it will override what happens to be installed in /usr/(local/)lib/python...
 | 
				
			||||||
 | 
					possible_topdir = os.path.normpath(os.path.join(os.path.abspath(sys.argv[0]),
 | 
				
			||||||
 | 
					                                   os.pardir,
 | 
				
			||||||
 | 
					                                   os.pardir))
 | 
				
			||||||
 | 
					if os.path.exists(os.path.join(possible_topdir, 'nova', '__init__.py')):
 | 
				
			||||||
 | 
					    sys.path.insert(0, possible_topdir)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					gettext.install('nova', unicode=1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from nova import api
 | 
				
			||||||
 | 
					from nova import flags
 | 
				
			||||||
 | 
					from nova import service
 | 
				
			||||||
 | 
					from nova import utils
 | 
				
			||||||
 | 
					from nova import wsgi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					FLAGS = flags.FLAGS
 | 
				
			||||||
 | 
					flags.DEFINE_integer('osapi_port', 8774, 'OpenStack API port')
 | 
				
			||||||
 | 
					flags.DEFINE_string('osapi_host', '0.0.0.0', 'OpenStack API host')
 | 
				
			||||||
 | 
					flags.DEFINE_integer('ec2api_port', 8773, 'EC2 API port')
 | 
				
			||||||
 | 
					flags.DEFINE_string('ec2api_host', '0.0.0.0', 'EC2 API host')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if __name__ == '__main__':
 | 
				
			||||||
 | 
					    utils.default_flagfile()
 | 
				
			||||||
 | 
					    FLAGS(sys.argv)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    compute = service.Service.create(binary='nova-compute')
 | 
				
			||||||
 | 
					    network = service.Service.create(binary='nova-network')
 | 
				
			||||||
 | 
					    volume = service.Service.create(binary='nova-volume')
 | 
				
			||||||
 | 
					    scheduler = service.Service.create(binary='nova-scheduler')
 | 
				
			||||||
 | 
					    #objectstore = service.Service.create(binary='nova-objectstore')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    service.serve(compute, network, volume, scheduler)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    server = wsgi.Server()
 | 
				
			||||||
 | 
					    server.start(api.API('os'), FLAGS.osapi_port, host=FLAGS.osapi_host)
 | 
				
			||||||
 | 
					    server.start(api.API('ec2'), FLAGS.ec2api_port, host=FLAGS.ec2api_host)
 | 
				
			||||||
 | 
					    server.wait()
 | 
				
			||||||
@@ -17,10 +17,12 @@
 | 
				
			|||||||
#    License for the specific language governing permissions and limitations
 | 
					#    License for the specific language governing permissions and limitations
 | 
				
			||||||
#    under the License.
 | 
					#    under the License.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
"""
 | 
					"""Starter script for Nova Compute."""
 | 
				
			||||||
  Twistd daemon for the nova compute nodes.
 | 
					 | 
				
			||||||
"""
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import eventlet
 | 
				
			||||||
 | 
					eventlet.monkey_patch()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import gettext
 | 
				
			||||||
import os
 | 
					import os
 | 
				
			||||||
import sys
 | 
					import sys
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -32,14 +34,12 @@ possible_topdir = os.path.normpath(os.path.join(os.path.abspath(sys.argv[0]),
 | 
				
			|||||||
if os.path.exists(os.path.join(possible_topdir, 'nova', '__init__.py')):
 | 
					if os.path.exists(os.path.join(possible_topdir, 'nova', '__init__.py')):
 | 
				
			||||||
    sys.path.insert(0, possible_topdir)
 | 
					    sys.path.insert(0, possible_topdir)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from nova import service
 | 
					gettext.install('nova', unicode=1)
 | 
				
			||||||
from nova import twistd
 | 
					 | 
				
			||||||
from nova import utils
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from nova import service
 | 
				
			||||||
 | 
					from nova import utils
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if __name__ == '__main__':
 | 
					if __name__ == '__main__':
 | 
				
			||||||
    utils.default_flagfile()
 | 
					    utils.default_flagfile()
 | 
				
			||||||
    twistd.serve(__file__)
 | 
					    service.serve()
 | 
				
			||||||
 | 
					    service.wait()
 | 
				
			||||||
if __name__ == '__builtin__':
 | 
					 | 
				
			||||||
    application = service.Service.create()  # pylint: disable=C0103
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -21,6 +21,7 @@
 | 
				
			|||||||
Handle lease database updates from DHCP servers.
 | 
					Handle lease database updates from DHCP servers.
 | 
				
			||||||
"""
 | 
					"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import gettext
 | 
				
			||||||
import logging
 | 
					import logging
 | 
				
			||||||
import os
 | 
					import os
 | 
				
			||||||
import sys
 | 
					import sys
 | 
				
			||||||
@@ -33,6 +34,8 @@ possible_topdir = os.path.normpath(os.path.join(os.path.abspath(sys.argv[0]),
 | 
				
			|||||||
if os.path.exists(os.path.join(possible_topdir, 'nova', '__init__.py')):
 | 
					if os.path.exists(os.path.join(possible_topdir, 'nova', '__init__.py')):
 | 
				
			||||||
    sys.path.insert(0, possible_topdir)
 | 
					    sys.path.insert(0, possible_topdir)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					gettext.install('nova', unicode=1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from nova import context
 | 
					from nova import context
 | 
				
			||||||
from nova import db
 | 
					from nova import db
 | 
				
			||||||
from nova import flags
 | 
					from nova import flags
 | 
				
			||||||
@@ -107,7 +110,6 @@ def main():
 | 
				
			|||||||
        FLAGS.num_networks = 5
 | 
					        FLAGS.num_networks = 5
 | 
				
			||||||
        path = os.path.abspath(os.path.join(os.path.dirname(__file__),
 | 
					        path = os.path.abspath(os.path.join(os.path.dirname(__file__),
 | 
				
			||||||
                                            '..',
 | 
					                                            '..',
 | 
				
			||||||
                                            '_trial_temp',
 | 
					 | 
				
			||||||
                                            'nova.sqlite'))
 | 
					                                            'nova.sqlite'))
 | 
				
			||||||
        FLAGS.sql_connection = 'sqlite:///%s' % path
 | 
					        FLAGS.sql_connection = 'sqlite:///%s' % path
 | 
				
			||||||
    action = argv[1]
 | 
					    action = argv[1]
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -21,6 +21,7 @@
 | 
				
			|||||||
  Download images from Canonical Image Store
 | 
					  Download images from Canonical Image Store
 | 
				
			||||||
"""
 | 
					"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import gettext
 | 
				
			||||||
import json
 | 
					import json
 | 
				
			||||||
import os
 | 
					import os
 | 
				
			||||||
import tempfile
 | 
					import tempfile
 | 
				
			||||||
@@ -37,6 +38,8 @@ possible_topdir = os.path.normpath(os.path.join(os.path.abspath(sys.argv[0]),
 | 
				
			|||||||
if os.path.exists(os.path.join(possible_topdir, 'nova', '__init__.py')):
 | 
					if os.path.exists(os.path.join(possible_topdir, 'nova', '__init__.py')):
 | 
				
			||||||
    sys.path.insert(0, possible_topdir)
 | 
					    sys.path.insert(0, possible_topdir)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					gettext.install('nova', unicode=1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from nova import flags
 | 
					from nova import flags
 | 
				
			||||||
from nova import utils
 | 
					from nova import utils
 | 
				
			||||||
from nova.objectstore import image
 | 
					from nova.objectstore import image
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -21,6 +21,7 @@
 | 
				
			|||||||
  Daemon for Nova RRD based instance resource monitoring.
 | 
					  Daemon for Nova RRD based instance resource monitoring.
 | 
				
			||||||
"""
 | 
					"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import gettext
 | 
				
			||||||
import os
 | 
					import os
 | 
				
			||||||
import logging
 | 
					import logging
 | 
				
			||||||
import sys
 | 
					import sys
 | 
				
			||||||
@@ -34,6 +35,8 @@ possible_topdir = os.path.normpath(os.path.join(os.path.abspath(sys.argv[0]),
 | 
				
			|||||||
if os.path.exists(os.path.join(possible_topdir, 'nova', '__init__.py')):
 | 
					if os.path.exists(os.path.join(possible_topdir, 'nova', '__init__.py')):
 | 
				
			||||||
    sys.path.insert(0, possible_topdir)
 | 
					    sys.path.insert(0, possible_topdir)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					gettext.install('nova', unicode=1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from nova import utils
 | 
					from nova import utils
 | 
				
			||||||
from nova import twistd
 | 
					from nova import twistd
 | 
				
			||||||
from nova.compute import monitor
 | 
					from nova.compute import monitor
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										177
									
								
								bin/nova-manage
									
									
									
									
									
								
							
							
						
						
									
										177
									
								
								bin/nova-manage
									
									
									
									
									
								
							@@ -53,6 +53,7 @@
 | 
				
			|||||||
  CLI interface for nova management.
 | 
					  CLI interface for nova management.
 | 
				
			||||||
"""
 | 
					"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import gettext
 | 
				
			||||||
import logging
 | 
					import logging
 | 
				
			||||||
import os
 | 
					import os
 | 
				
			||||||
import sys
 | 
					import sys
 | 
				
			||||||
@@ -68,20 +69,19 @@ possible_topdir = os.path.normpath(os.path.join(os.path.abspath(sys.argv[0]),
 | 
				
			|||||||
if os.path.exists(os.path.join(possible_topdir, 'nova', '__init__.py')):
 | 
					if os.path.exists(os.path.join(possible_topdir, 'nova', '__init__.py')):
 | 
				
			||||||
    sys.path.insert(0, possible_topdir)
 | 
					    sys.path.insert(0, possible_topdir)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					gettext.install('nova', unicode=1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from nova import context
 | 
					from nova import context
 | 
				
			||||||
 | 
					from nova import crypto
 | 
				
			||||||
from nova import db
 | 
					from nova import db
 | 
				
			||||||
from nova import exception
 | 
					from nova import exception
 | 
				
			||||||
from nova import flags
 | 
					from nova import flags
 | 
				
			||||||
from nova import quota
 | 
					from nova import quota
 | 
				
			||||||
from nova import utils
 | 
					from nova import utils
 | 
				
			||||||
from nova.auth import manager
 | 
					from nova.auth import manager
 | 
				
			||||||
from nova.cloudpipe import pipelib
 | 
					 | 
				
			||||||
#added by masumotok
 | 
					 | 
				
			||||||
from nova import rpc
 | 
					from nova import rpc
 | 
				
			||||||
# added by masumotok
 | 
					from nova.cloudpipe import pipelib
 | 
				
			||||||
from nova.api.ec2 import cloud
 | 
					from nova.api.ec2 import cloud
 | 
				
			||||||
# added by masumotok
 | 
					 | 
				
			||||||
from nova.compute import power_state
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -100,47 +100,43 @@ class VpnCommands(object):
 | 
				
			|||||||
        self.manager = manager.AuthManager()
 | 
					        self.manager = manager.AuthManager()
 | 
				
			||||||
        self.pipe = pipelib.CloudPipe()
 | 
					        self.pipe = pipelib.CloudPipe()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def list(self):
 | 
					    def list(self, project=None):
 | 
				
			||||||
        """Print a listing of the VPNs for all projects."""
 | 
					        """Print a listing of the VPN data for one or all projects.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        args: [project=all]"""
 | 
				
			||||||
        print "%-12s\t" % 'project',
 | 
					        print "%-12s\t" % 'project',
 | 
				
			||||||
        print "%-20s\t" % 'ip:port',
 | 
					        print "%-20s\t" % 'ip:port',
 | 
				
			||||||
 | 
					        print "%-20s\t" % 'private_ip',
 | 
				
			||||||
        print "%s" % 'state'
 | 
					        print "%s" % 'state'
 | 
				
			||||||
        for project in self.manager.get_projects():
 | 
					        if project:
 | 
				
			||||||
 | 
					            projects = [self.manager.get_project(project)]
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            projects = self.manager.get_projects()
 | 
				
			||||||
 | 
					            # NOTE(vish): This hits the database a lot.  We could optimize
 | 
				
			||||||
 | 
					            #             by getting all networks in one query and all vpns
 | 
				
			||||||
 | 
					            #             in aother query, then doing lookups by project
 | 
				
			||||||
 | 
					        for project in projects:
 | 
				
			||||||
            print "%-12s\t" % project.name,
 | 
					            print "%-12s\t" % project.name,
 | 
				
			||||||
 | 
					            ipport = "%s:%s" % (project.vpn_ip, project.vpn_port)
 | 
				
			||||||
            try:
 | 
					            print "%-20s\t" % ipport,
 | 
				
			||||||
                s = "%s:%s" % (project.vpn_ip, project.vpn_port)
 | 
					            ctxt = context.get_admin_context()
 | 
				
			||||||
            except exception.NotFound:
 | 
					            vpn = db.instance_get_project_vpn(ctxt, project.id)
 | 
				
			||||||
                s = "None"
 | 
					 | 
				
			||||||
            print "%-20s\t" % s,
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            vpn = self._vpn_for(project.id)
 | 
					 | 
				
			||||||
            if vpn:
 | 
					            if vpn:
 | 
				
			||||||
                command = "ping -c1 -w1 %s > /dev/null; echo $?"
 | 
					                address = None
 | 
				
			||||||
                out, _err = utils.execute(command % vpn['private_dns_name'],
 | 
					                state = 'down'
 | 
				
			||||||
                                          check_exit_code=False)
 | 
					                if vpn.get('fixed_ip', None):
 | 
				
			||||||
                if out.strip() == '0':
 | 
					                    address = vpn['fixed_ip']['address']
 | 
				
			||||||
                    net = 'up'
 | 
					                if project.vpn_ip and utils.vpn_ping(project.vpn_ip,
 | 
				
			||||||
                else:
 | 
					                                                     project.vpn_port):
 | 
				
			||||||
                    net = 'down'
 | 
					                    state = 'up'
 | 
				
			||||||
                print vpn['private_dns_name'],
 | 
					                print address,
 | 
				
			||||||
                print vpn['node_name'],
 | 
					                print vpn['host'],
 | 
				
			||||||
                print vpn['instance_id'],
 | 
					                print vpn['ec2_id'],
 | 
				
			||||||
                print vpn['state_description'],
 | 
					                print vpn['state_description'],
 | 
				
			||||||
                print net
 | 
					                print state
 | 
				
			||||||
 | 
					 | 
				
			||||||
            else:
 | 
					            else:
 | 
				
			||||||
                print None
 | 
					                print None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def _vpn_for(self, project_id):
 | 
					 | 
				
			||||||
        """Get the VPN instance for a project ID."""
 | 
					 | 
				
			||||||
        for instance in db.instance_get_all(context.get_admin_context()):
 | 
					 | 
				
			||||||
            if (instance['image_id'] == FLAGS.vpn_image_id
 | 
					 | 
				
			||||||
                and not instance['state_description'] in
 | 
					 | 
				
			||||||
                    ['shutting_down', 'shutdown']
 | 
					 | 
				
			||||||
                and instance['project_id'] == project_id):
 | 
					 | 
				
			||||||
                return instance
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def spawn(self):
 | 
					    def spawn(self):
 | 
				
			||||||
        """Run all VPNs."""
 | 
					        """Run all VPNs."""
 | 
				
			||||||
        for p in reversed(self.manager.get_projects()):
 | 
					        for p in reversed(self.manager.get_projects()):
 | 
				
			||||||
@@ -153,6 +149,21 @@ class VpnCommands(object):
 | 
				
			|||||||
        """Start the VPN for a given project."""
 | 
					        """Start the VPN for a given project."""
 | 
				
			||||||
        self.pipe.launch_vpn_instance(project_id)
 | 
					        self.pipe.launch_vpn_instance(project_id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def change(self, project_id, ip, port):
 | 
				
			||||||
 | 
					        """Change the ip and port for a vpn.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        args: project, ip, port"""
 | 
				
			||||||
 | 
					        project = self.manager.get_project(project_id)
 | 
				
			||||||
 | 
					        if not project:
 | 
				
			||||||
 | 
					            print 'No project %s' % (project_id)
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        admin = context.get_admin_context()
 | 
				
			||||||
 | 
					        network_ref = db.project_get_network(admin, project_id)
 | 
				
			||||||
 | 
					        db.network_update(admin,
 | 
				
			||||||
 | 
					                          network_ref['id'],
 | 
				
			||||||
 | 
					                          {'vpn_public_address': ip,
 | 
				
			||||||
 | 
					                           'vpn_public_port': int(port)})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ShellCommands(object):
 | 
					class ShellCommands(object):
 | 
				
			||||||
    def bpython(self):
 | 
					    def bpython(self):
 | 
				
			||||||
@@ -299,6 +310,14 @@ class UserCommands(object):
 | 
				
			|||||||
            is_admin = False
 | 
					            is_admin = False
 | 
				
			||||||
        self.manager.modify_user(name, access_key, secret_key, is_admin)
 | 
					        self.manager.modify_user(name, access_key, secret_key, is_admin)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def revoke(self, user_id, project_id=None):
 | 
				
			||||||
 | 
					        """revoke certs for a user
 | 
				
			||||||
 | 
					        arguments: user_id [project_id]"""
 | 
				
			||||||
 | 
					        if project_id:
 | 
				
			||||||
 | 
					            crypto.revoke_certs_by_user_and_project(user_id, project_id)
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            crypto.revoke_certs_by_user(user_id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ProjectCommands(object):
 | 
					class ProjectCommands(object):
 | 
				
			||||||
    """Class for managing projects."""
 | 
					    """Class for managing projects."""
 | 
				
			||||||
@@ -366,9 +385,14 @@ class ProjectCommands(object):
 | 
				
			|||||||
    def zipfile(self, project_id, user_id, filename='nova.zip'):
 | 
					    def zipfile(self, project_id, user_id, filename='nova.zip'):
 | 
				
			||||||
        """Exports credentials for project to a zip file
 | 
					        """Exports credentials for project to a zip file
 | 
				
			||||||
        arguments: project_id user_id [filename='nova.zip]"""
 | 
					        arguments: project_id user_id [filename='nova.zip]"""
 | 
				
			||||||
        zip_file = self.manager.get_credentials(user_id, project_id)
 | 
					        try:
 | 
				
			||||||
        with open(filename, 'w') as f:
 | 
					            zip_file = self.manager.get_credentials(user_id, project_id)
 | 
				
			||||||
            f.write(zip_file)
 | 
					            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')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class FloatingIpCommands(object):
 | 
					class FloatingIpCommands(object):
 | 
				
			||||||
@@ -431,7 +455,7 @@ class NetworkCommands(object):
 | 
				
			|||||||
                                    int(network_size), int(vlan_start),
 | 
					                                    int(network_size), int(vlan_start),
 | 
				
			||||||
                                    int(vpn_start))
 | 
					                                    int(vpn_start))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# this class is added by masumotok
 | 
					
 | 
				
			||||||
class InstanceCommands(object):
 | 
					class InstanceCommands(object):
 | 
				
			||||||
    """Class for mangaging VM instances."""
 | 
					    """Class for mangaging VM instances."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -441,43 +465,29 @@ class InstanceCommands(object):
 | 
				
			|||||||
        logging.basicConfig()
 | 
					        logging.basicConfig()
 | 
				
			||||||
        ctxt = context.get_admin_context()
 | 
					        ctxt = context.get_admin_context()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # 1. whether destination host exists
 | 
					        try:
 | 
				
			||||||
        host_ref = db.host_get_by_name(ctxt, dest)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # 2. whether instance exists and running
 | 
					 | 
				
			||||||
        #    try-catch clause is necessary because only internal_id is shown
 | 
					 | 
				
			||||||
        #    when NotFound exception occurs. it isnot understandable to admins.
 | 
					 | 
				
			||||||
        try :
 | 
					 | 
				
			||||||
            internal_id = cloud.ec2_id_to_internal_id(ec2_id)
 | 
					            internal_id = cloud.ec2_id_to_internal_id(ec2_id)
 | 
				
			||||||
            instance_ref = db.instance_get_by_internal_id(ctxt, internal_id)
 | 
					            instance_ref = db.instance_get_by_internal_id(ctxt, internal_id)
 | 
				
			||||||
        except exception.NotFound :
 | 
					            instance_id = instance_ref['id']
 | 
				
			||||||
            print 'Not found instance_id(%s (internal_id:%s))' % ( ec2_id, internal_id)
 | 
					        except exception.NotFound as e:
 | 
				
			||||||
            raise
 | 
					            msg = _('instance(%s) is not found')
 | 
				
			||||||
 | 
					            e.args += (msg % ec2_id,)
 | 
				
			||||||
 | 
					            raise e
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if power_state.RUNNING != instance_ref['state'] or \
 | 
					 | 
				
			||||||
           'running' != instance_ref['state_description']:
 | 
					 | 
				
			||||||
            raise exception.Invalid('Instance(%s) is not running' % ec2_id)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # 3. the host where instance is running and dst host is not same
 | 
					 | 
				
			||||||
        if dest == instance_ref['host'] :
 | 
					 | 
				
			||||||
            msg = '%s is where %s is running now. choose other host.' % (dest, ec2_id)
 | 
					 | 
				
			||||||
            raise exception.Invalid(msg)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # 4. live migration
 | 
					 | 
				
			||||||
        ret = rpc.call(ctxt,
 | 
					        ret = rpc.call(ctxt,
 | 
				
			||||||
                       FLAGS.scheduler_topic,
 | 
					                       FLAGS.scheduler_topic,
 | 
				
			||||||
                       { "method": "live_migration",
 | 
					                       {"method": "live_migration",
 | 
				
			||||||
                       "args": {"ec2_id": ec2_id,
 | 
					                        "args": {"instance_id": instance_id,
 | 
				
			||||||
                                "dest":dest}})
 | 
					                                "dest": dest,
 | 
				
			||||||
 | 
					                                "topic": FLAGS.compute_topic}})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if None != ret : 
 | 
					        if None != ret:
 | 
				
			||||||
            raise ret
 | 
					            raise ret
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        print 'Finished all procedure. check instance are migrated successfully'
 | 
					        print 'Finished all procedure. Check migrating finishes successfully'
 | 
				
			||||||
        print 'check status by using euca-describe-instances.'
 | 
					        print 'check status by using euca-describe-instances.'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# this class is created by masumotok
 | 
					 | 
				
			||||||
class HostCommands(object):
 | 
					class HostCommands(object):
 | 
				
			||||||
    """Class for mangaging host(physical nodes)."""
 | 
					    """Class for mangaging host(physical nodes)."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -485,17 +495,18 @@ class HostCommands(object):
 | 
				
			|||||||
    def list(self):
 | 
					    def list(self):
 | 
				
			||||||
        """describe host list."""
 | 
					        """describe host list."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # to supress msg: No handlers could be found for logger "amqplib"
 | 
					        # To supress msg: No handlers could be found for logger "amqplib"
 | 
				
			||||||
        logging.basicConfig()
 | 
					        logging.basicConfig()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        host_refs = db.host_get_all(context.get_admin_context())
 | 
					        host_refs = db.host_get_all(context.get_admin_context())
 | 
				
			||||||
        for host_ref in host_refs:
 | 
					        for host_ref in host_refs:
 | 
				
			||||||
            print host_ref['name']
 | 
					            print host_ref['name']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def show(self, host):
 | 
					    def show(self, host):
 | 
				
			||||||
        """describe cpu/memory/hdd info for host."""
 | 
					        """describe cpu/memory/hdd info for host."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # to supress msg: No handlers could be found for logger "amqplib"
 | 
					        # To supress msg: No handlers could be found for logger "amqplib"
 | 
				
			||||||
        logging.basicConfig()
 | 
					        logging.basicConfig()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        result = rpc.call(context.get_admin_context(),
 | 
					        result = rpc.call(context.get_admin_context(),
 | 
				
			||||||
@@ -503,41 +514,27 @@ class HostCommands(object):
 | 
				
			|||||||
                         {"method": "show_host_resource",
 | 
					                         {"method": "show_host_resource",
 | 
				
			||||||
                          "args": {"host": host}})
 | 
					                          "args": {"host": host}})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # checing result msg format is necessary, that will have done
 | 
					        # Checking result msg format is necessary, that will have done
 | 
				
			||||||
        # when this feture is included in API.
 | 
					        # when this feture is included in API.
 | 
				
			||||||
        if dict != type(result):
 | 
					        if dict != type(result):
 | 
				
			||||||
            print 'Unexpected error occurs'
 | 
					            print 'Unexpected error occurs'
 | 
				
			||||||
        elif not result['ret'] :
 | 
					        elif not result['ret']:
 | 
				
			||||||
            print '%s' % result['msg']
 | 
					            print '%s' % result['msg']
 | 
				
			||||||
        else :
 | 
					        else:
 | 
				
			||||||
            cpu = result['phy_resource']['vcpus']
 | 
					            cpu = result['phy_resource']['vcpus']
 | 
				
			||||||
            mem = result['phy_resource']['memory_mb']
 | 
					            mem = result['phy_resource']['memory_mb']
 | 
				
			||||||
            hdd = result['phy_resource']['local_gb']
 | 
					            hdd = result['phy_resource']['local_gb']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            print 'HOST\t\tPROJECT\t\tcpu\tmem(mb)\tdisk(gb)'
 | 
					            print 'HOST\t\tPROJECT\t\tcpu\tmem(mb)\tdisk(gb)'
 | 
				
			||||||
            print '%s\t\t\t%s\t%s\t%s' % ( host,cpu, mem, hdd)
 | 
					            print '%s\t\t\t%s\t%s\t%s' % (host, cpu, mem, hdd)
 | 
				
			||||||
            for p_id, val in result['usage'].items() :
 | 
					            for p_id, val in result['usage'].items():
 | 
				
			||||||
                print '%s\t%s\t\t%s\t%s\t%s' % ( host,
 | 
					                print '%s\t%s\t\t%s\t%s\t%s' % (host,
 | 
				
			||||||
                                             p_id,
 | 
					                                             p_id,
 | 
				
			||||||
                                             val['vcpus'],
 | 
					                                             val['vcpus'],
 | 
				
			||||||
                                             val['memory_mb'],
 | 
					                                             val['memory_mb'],
 | 
				
			||||||
                                             val['local_gb'])
 | 
					                                             val['local_gb'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def has_keys(self, dic, keys):
 | 
					 | 
				
			||||||
        not_found = [ key for key in keys if not dict.has_key(key) ]
 | 
					 | 
				
			||||||
        return ( (0 == len(not_found)), not_found )
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# modified by masumotok
 | 
					 | 
				
			||||||
#CATEGORIES = [
 | 
					 | 
				
			||||||
#    ('user', UserCommands),
 | 
					 | 
				
			||||||
#    ('project', ProjectCommands),
 | 
					 | 
				
			||||||
#    ('role', RoleCommands),
 | 
					 | 
				
			||||||
#    ('shell', ShellCommands),
 | 
					 | 
				
			||||||
#    ('vpn', VpnCommands),
 | 
					 | 
				
			||||||
#    ('floating', FloatingIpCommands),
 | 
					 | 
				
			||||||
#    ('network', NetworkCommands)]
 | 
					 | 
				
			||||||
CATEGORIES = [
 | 
					CATEGORIES = [
 | 
				
			||||||
    ('user', UserCommands),
 | 
					    ('user', UserCommands),
 | 
				
			||||||
    ('project', ProjectCommands),
 | 
					    ('project', ProjectCommands),
 | 
				
			||||||
@@ -547,7 +544,7 @@ CATEGORIES = [
 | 
				
			|||||||
    ('floating', FloatingIpCommands),
 | 
					    ('floating', FloatingIpCommands),
 | 
				
			||||||
    ('network', NetworkCommands),
 | 
					    ('network', NetworkCommands),
 | 
				
			||||||
    ('instance', InstanceCommands),
 | 
					    ('instance', InstanceCommands),
 | 
				
			||||||
    ('host',HostCommands)]
 | 
					    ('host', HostCommands)]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def lazy_match(name, key_value_tuples):
 | 
					def lazy_match(name, key_value_tuples):
 | 
				
			||||||
    """Finds all objects that have a key that case insensitively contains
 | 
					    """Finds all objects that have a key that case insensitively contains
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,10 +17,12 @@
 | 
				
			|||||||
#    License for the specific language governing permissions and limitations
 | 
					#    License for the specific language governing permissions and limitations
 | 
				
			||||||
#    under the License.
 | 
					#    under the License.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
"""
 | 
					"""Starter script for Nova Network."""
 | 
				
			||||||
  Twistd daemon for the nova network nodes.
 | 
					 | 
				
			||||||
"""
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import eventlet
 | 
				
			||||||
 | 
					eventlet.monkey_patch()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import gettext
 | 
				
			||||||
import os
 | 
					import os
 | 
				
			||||||
import sys
 | 
					import sys
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -32,14 +34,12 @@ possible_topdir = os.path.normpath(os.path.join(os.path.abspath(sys.argv[0]),
 | 
				
			|||||||
if os.path.exists(os.path.join(possible_topdir, 'nova', '__init__.py')):
 | 
					if os.path.exists(os.path.join(possible_topdir, 'nova', '__init__.py')):
 | 
				
			||||||
    sys.path.insert(0, possible_topdir)
 | 
					    sys.path.insert(0, possible_topdir)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from nova import service
 | 
					gettext.install('nova', unicode=1)
 | 
				
			||||||
from nova import twistd
 | 
					 | 
				
			||||||
from nova import utils
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from nova import service
 | 
				
			||||||
 | 
					from nova import utils
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if __name__ == '__main__':
 | 
					if __name__ == '__main__':
 | 
				
			||||||
    utils.default_flagfile()
 | 
					    utils.default_flagfile()
 | 
				
			||||||
    twistd.serve(__file__)
 | 
					    service.serve()
 | 
				
			||||||
 | 
					    service.wait()
 | 
				
			||||||
if __name__ == '__builtin__':
 | 
					 | 
				
			||||||
    application = service.Service.create()  # pylint: disable-msg=C0103
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -21,6 +21,7 @@
 | 
				
			|||||||
  Twisted daemon for nova objectstore. Supports S3 API.
 | 
					  Twisted daemon for nova objectstore. Supports S3 API.
 | 
				
			||||||
"""
 | 
					"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import gettext
 | 
				
			||||||
import os
 | 
					import os
 | 
				
			||||||
import sys
 | 
					import sys
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -32,6 +33,8 @@ possible_topdir = os.path.normpath(os.path.join(os.path.abspath(sys.argv[0]),
 | 
				
			|||||||
if os.path.exists(os.path.join(possible_topdir, 'nova', '__init__.py')):
 | 
					if os.path.exists(os.path.join(possible_topdir, 'nova', '__init__.py')):
 | 
				
			||||||
    sys.path.insert(0, possible_topdir)
 | 
					    sys.path.insert(0, possible_topdir)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					gettext.install('nova', unicode=1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from nova import flags
 | 
					from nova import flags
 | 
				
			||||||
from nova import utils
 | 
					from nova import utils
 | 
				
			||||||
from nova import twistd
 | 
					from nova import twistd
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,10 +17,12 @@
 | 
				
			|||||||
#    License for the specific language governing permissions and limitations
 | 
					#    License for the specific language governing permissions and limitations
 | 
				
			||||||
#    under the License.
 | 
					#    under the License.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
"""
 | 
					"""Starter script for Nova Scheduler."""
 | 
				
			||||||
  Twistd daemon for the nova scheduler nodes.
 | 
					 | 
				
			||||||
"""
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import eventlet
 | 
				
			||||||
 | 
					eventlet.monkey_patch()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import gettext
 | 
				
			||||||
import os
 | 
					import os
 | 
				
			||||||
import sys
 | 
					import sys
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -32,14 +34,12 @@ possible_topdir = os.path.normpath(os.path.join(os.path.abspath(sys.argv[0]),
 | 
				
			|||||||
if os.path.exists(os.path.join(possible_topdir, 'nova', '__init__.py')):
 | 
					if os.path.exists(os.path.join(possible_topdir, 'nova', '__init__.py')):
 | 
				
			||||||
    sys.path.insert(0, possible_topdir)
 | 
					    sys.path.insert(0, possible_topdir)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from nova import service
 | 
					gettext.install('nova', unicode=1)
 | 
				
			||||||
from nova import twistd
 | 
					 | 
				
			||||||
from nova import utils
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from nova import service
 | 
				
			||||||
 | 
					from nova import utils
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if __name__ == '__main__':
 | 
					if __name__ == '__main__':
 | 
				
			||||||
    utils.default_flagfile()
 | 
					    utils.default_flagfile()
 | 
				
			||||||
    twistd.serve(__file__)
 | 
					    service.serve()
 | 
				
			||||||
 | 
					    service.wait()
 | 
				
			||||||
if __name__ == '__builtin__':
 | 
					 | 
				
			||||||
    application = service.Service.create()
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,10 +17,12 @@
 | 
				
			|||||||
#    License for the specific language governing permissions and limitations
 | 
					#    License for the specific language governing permissions and limitations
 | 
				
			||||||
#    under the License.
 | 
					#    under the License.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
"""
 | 
					"""Starter script for Nova Volume."""
 | 
				
			||||||
  Twistd daemon for the nova volume nodes.
 | 
					 | 
				
			||||||
"""
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import eventlet
 | 
				
			||||||
 | 
					eventlet.monkey_patch()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import gettext
 | 
				
			||||||
import os
 | 
					import os
 | 
				
			||||||
import sys
 | 
					import sys
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -32,14 +34,12 @@ possible_topdir = os.path.normpath(os.path.join(os.path.abspath(sys.argv[0]),
 | 
				
			|||||||
if os.path.exists(os.path.join(possible_topdir, 'nova', '__init__.py')):
 | 
					if os.path.exists(os.path.join(possible_topdir, 'nova', '__init__.py')):
 | 
				
			||||||
    sys.path.insert(0, possible_topdir)
 | 
					    sys.path.insert(0, possible_topdir)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from nova import service
 | 
					gettext.install('nova', unicode=1)
 | 
				
			||||||
from nova import twistd
 | 
					 | 
				
			||||||
from nova import utils
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from nova import service
 | 
				
			||||||
 | 
					from nova import utils
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if __name__ == '__main__':
 | 
					if __name__ == '__main__':
 | 
				
			||||||
    utils.default_flagfile()
 | 
					    utils.default_flagfile()
 | 
				
			||||||
    twistd.serve(__file__)
 | 
					    service.serve()
 | 
				
			||||||
 | 
					    service.wait()
 | 
				
			||||||
if __name__ == '__builtin__':
 | 
					 | 
				
			||||||
    application = service.Service.create()  # pylint: disable-msg=C0103
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,8 @@
 | 
				
			|||||||
 | 
					import gettext
 | 
				
			||||||
import os
 | 
					import os
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					gettext.install('nova')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from nova import utils
 | 
					from nova import utils
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def setup(app):
 | 
					def setup(app):
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -23,7 +23,7 @@ In Nova, users organize their cloud resources in projects. A Nova project consis
 | 
				
			|||||||
Nova Network Strategies
 | 
					Nova Network Strategies
 | 
				
			||||||
-----------------------
 | 
					-----------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Currently, Nova supports three kinds of networks, implemented in three "Network Manager" types respectively: Flat Network Manager, Flat DHCP Network Manager, and VLAN Network Manager. The three kinds of networks can c-exist in a cloud system. However, the scheduler for selecting the type of network for a given project is not yet implemented. Here is a brief description of each of the different network strategies, with a focus on the VLAN Manager in a separate section. 
 | 
					Currently, Nova supports three kinds of networks, implemented in three "Network Manager" types respectively: Flat Network Manager, Flat DHCP Network Manager, and VLAN Network Manager. The three kinds of networks can co-exist in a cloud system. However, the scheduler for selecting the type of network for a given project is not yet implemented. Here is a brief description of each of the different network strategies, with a focus on the VLAN Manager in a separate section. 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Read more about Nova network strategies here:
 | 
					Read more about Nova network strategies here:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -19,7 +19,7 @@ Installing Nova on Multiple Servers
 | 
				
			|||||||
===================================
 | 
					===================================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
When you move beyond evaluating the technology and into building an actual
 | 
					When you move beyond evaluating the technology and into building an actual
 | 
				
			||||||
production environemnt, you will need to know how to configure your datacenter
 | 
					production environment, you will need to know how to configure your datacenter
 | 
				
			||||||
and how to deploy components across your clusters.  This guide should help you
 | 
					and how to deploy components across your clusters.  This guide should help you
 | 
				
			||||||
through that process.
 | 
					through that process.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -35,7 +35,6 @@ Requirements for a multi-node installation
 | 
				
			|||||||
* For a recommended HA setup, consider a MySQL master/slave replication, with as many slaves as you like, and probably a heartbeat to kick one of the slaves into being a master if it dies.
 | 
					* For a recommended HA setup, consider a MySQL master/slave replication, with as many slaves as you like, and probably a heartbeat to kick one of the slaves into being a master if it dies.
 | 
				
			||||||
* For performance optimization, split reads and writes to the database. MySQL proxy is the easiest way to make this work if running MySQL.
 | 
					* For performance optimization, split reads and writes to the database. MySQL proxy is the easiest way to make this work if running MySQL.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
Assumptions
 | 
					Assumptions
 | 
				
			||||||
^^^^^^^^^^^
 | 
					^^^^^^^^^^^
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -69,14 +68,14 @@ Step 1 Use apt-get to get the latest code
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
It is highly likely that there will be errors when the nova services come up since they are not yet configured. Don't worry, you're only at step 1!
 | 
					It is highly likely that there will be errors when the nova services come up since they are not yet configured. Don't worry, you're only at step 1!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Step 2 Setup configuration files (installed in /etc/nova)
 | 
					Step 2 Setup configuration file (installed in /etc/nova)
 | 
				
			||||||
---------------------------------------------------------
 | 
					---------------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Note: CC_ADDR=<the external IP address of your cloud controller>
 | 
					Note: CC_ADDR=<the external IP address of your cloud controller>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
1. These need to be defined in EACH configuration file
 | 
					Nova development has consolidated all .conf files to nova.conf as of November 2010. References to specific .conf files may be ignored.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
::
 | 
					#. These need to be defined in the nova.conf configuration file::
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   --sql_connection=mysql://root:nova@$CC_ADDR/nova # location of nova sql db
 | 
					   --sql_connection=mysql://root:nova@$CC_ADDR/nova # location of nova sql db
 | 
				
			||||||
   --s3_host=$CC_ADDR  # This is where nova is hosting the objectstore service, which
 | 
					   --s3_host=$CC_ADDR  # This is where nova is hosting the objectstore service, which
 | 
				
			||||||
@@ -87,31 +86,14 @@ Note: CC_ADDR=<the external IP address of your cloud controller>
 | 
				
			|||||||
   --ec2_url=http://$CC_ADDR:8773/services/Cloud
 | 
					   --ec2_url=http://$CC_ADDR:8773/services/Cloud
 | 
				
			||||||
   --network_manager=nova.network.manager.FlatManager # simple, no-vlan networking type
 | 
					   --network_manager=nova.network.manager.FlatManager # simple, no-vlan networking type
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
2. nova-manage specific flags
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
::
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   --fixed_range=<network/prefix>   # ip network to use for VM guests, ex 192.168.2.64/26
 | 
					   --fixed_range=<network/prefix>   # ip network to use for VM guests, ex 192.168.2.64/26
 | 
				
			||||||
   --network_size=<# of addrs>      # number of ip addrs to use for VM guests, ex 64
 | 
					   --network_size=<# of addrs>      # number of ip addrs to use for VM guests, ex 64
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#. Create a nova group::
 | 
				
			||||||
3. nova-network specific flags
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
::
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   --fixed_range=<network/prefix>   # ip network to use for VM guests, ex 192.168.2.64/26
 | 
					 | 
				
			||||||
   --network_size=<# of addrs>      # number of ip addrs to use for VM guests, ex 64
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
4. Create a nova group
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
::
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
   sudo addgroup nova
 | 
					   sudo addgroup nova
 | 
				
			||||||
 | 
					
 | 
				
			||||||
5. nova-objectstore specific flags < no specific config needed >
 | 
					The Nova config file should have its owner set to root:nova, and mode set to 0640, since they contain your MySQL server's root password.
 | 
				
			||||||
 | 
					 | 
				
			||||||
Config files should be have their owner set to root:nova, and mode set to 0640, since they contain your MySQL server's root password.
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
::
 | 
					::
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -121,7 +103,7 @@ Config files should be have their owner set to root:nova, and mode set to 0640,
 | 
				
			|||||||
Step 3 Setup the sql db
 | 
					Step 3 Setup the sql db
 | 
				
			||||||
-----------------------
 | 
					-----------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
1. First you 'preseed' (using vishy's :doc:`../quickstart`). Run this as root.
 | 
					1. First you 'preseed' (using the Quick Start method :doc:`../quickstart`). Run this as root.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
::
 | 
					::
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -161,7 +143,7 @@ Step 3 Setup the sql db
 | 
				
			|||||||
   GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' WITH GRANT OPTION;
 | 
					   GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' WITH GRANT OPTION;
 | 
				
			||||||
   SET PASSWORD FOR 'root'@'%' = PASSWORD('nova');
 | 
					   SET PASSWORD FOR 'root'@'%' = PASSWORD('nova');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
7. branch and install Nova
 | 
					7. Branch and install Nova
 | 
				
			||||||
 | 
					
 | 
				
			||||||
::
 | 
					::
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -186,9 +168,7 @@ Step 4 Setup Nova environment
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
Note: The nova-manage service assumes that the first IP address is your network (like 192.168.0.0), that the 2nd IP is your gateway (192.168.0.1), and that the broadcast is the very last IP in the range you defined (192.168.0.255). If this is not the case you will need to manually edit the sql db 'networks' table.o.
 | 
					Note: The nova-manage service assumes that the first IP address is your network (like 192.168.0.0), that the 2nd IP is your gateway (192.168.0.1), and that the broadcast is the very last IP in the range you defined (192.168.0.255). If this is not the case you will need to manually edit the sql db 'networks' table.o.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
On running this command, entries are made in the 'networks' and 'fixed_ips' table. However, one of the networks listed in the 'networks' table needs to be marked as bridge in order for the code to know that a bridge exists. We ended up doing this manually, (update query fired directly in the DB). Is there a better way to mark a network as bridged?
 | 
					On running this command, entries are made in the 'networks' and 'fixed_ips' table. However, one of the networks listed in the 'networks' table needs to be marked as bridge in order for the code to know that a bridge exists. The Network is marked as bridged automatically based on the type of network manager selected.
 | 
				
			||||||
 | 
					 | 
				
			||||||
Update: This has been resolved w.e.f 27/10. network is marked as bridged automatically based on the type of n/w manager selected.
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
More networking details to create a network bridge for flat network
 | 
					More networking details to create a network bridge for flat network
 | 
				
			||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 | 
					^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 | 
				
			||||||
@@ -233,7 +213,6 @@ unzip them in your home directory, and add them to your environment::
 | 
				
			|||||||
   echo ". creds/novarc" >> ~/.bashrc
 | 
					   echo ". creds/novarc" >> ~/.bashrc
 | 
				
			||||||
   ~/.bashrc
 | 
					   ~/.bashrc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
Step 6 Restart all relevant services
 | 
					Step 6 Restart all relevant services
 | 
				
			||||||
------------------------------------
 | 
					------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -249,8 +228,8 @@ Restart relevant nova services::
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
.. todo:: do we still need the content below?
 | 
					.. todo:: do we still need the content below?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Bare-metal Provisioning
 | 
					Bare-metal Provisioning Notes
 | 
				
			||||||
-----------------------
 | 
					-----------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
To install the base operating system you can use PXE booting.
 | 
					To install the base operating system you can use PXE booting.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,7 +9,7 @@ The fastest way to get a test cloud running is through our :doc:`../quickstart`.
 | 
				
			|||||||
Step 1 and 2: Get the latest Nova code system software
 | 
					Step 1 and 2: Get the latest Nova code system software
 | 
				
			||||||
------------------------------------------------------
 | 
					------------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Depending on your system, the mehod for accomplishing this varies
 | 
					Depending on your system, the method for accomplishing this varies
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.. toctree::
 | 
					.. toctree::
 | 
				
			||||||
   :maxdepth: 1
 | 
					   :maxdepth: 1
 | 
				
			||||||
@@ -63,8 +63,20 @@ 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_ACCESS_KEY=4e6498a2-blah-blah-blah-17d1333t97fd
 | 
				
			||||||
    export EC2_SECRET_KEY=0a520304-blah-blah-blah-340sp34k05bbe9a7
 | 
					    export EC2_SECRET_KEY=0a520304-blah-blah-blah-340sp34k05bbe9a7
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Step 5: Create the network 
 | 
				
			||||||
 | 
					--------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Step 5: Create a project with the user you created
 | 
					Type or copy/paste in the following line to create a network prior to creating a project. 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					::
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sudo nova-manage network create 10.0.0.0/8 1 64
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					For this command, the IP address is the cidr notation for your netmask, such as 192.168.1.0/24. The value 1 is the total number of networks you want made, and the 64 value is the total number of ips in all networks.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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
 | 
				
			||||||
--------------------------------------------------
 | 
					--------------------------------------------------
 | 
				
			||||||
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.
 | 
					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.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -94,7 +106,7 @@ Type or copy/paste in the following line to create a project named IRT (for Ice
 | 
				
			|||||||
    Data Base Updated
 | 
					    Data Base Updated
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Step 6: Unzip the nova.zip
 | 
					Step 7: Unzip the nova.zip
 | 
				
			||||||
--------------------------
 | 
					--------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
You should have a nova.zip file in your current working directory. Unzip it with this command:
 | 
					You should have a nova.zip file in your current working directory. Unzip it with this command:
 | 
				
			||||||
@@ -116,7 +128,7 @@ You'll see these files extract.
 | 
				
			|||||||
     extracting: cacert.pem
 | 
					     extracting: cacert.pem
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Step 7: Source the rc file
 | 
					Step 8: Source the rc file
 | 
				
			||||||
--------------------------
 | 
					--------------------------
 | 
				
			||||||
Type or copy/paste the following to source the novarc file in your current working directory.
 | 
					Type or copy/paste the following to source the novarc file in your current working directory.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -125,9 +137,9 @@ Type or copy/paste the following to source the novarc file in your current worki
 | 
				
			|||||||
    . novarc
 | 
					    . novarc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Step 8: Pat yourself on the back :)
 | 
					Step 9: Pat yourself on the back :)
 | 
				
			||||||
-----------------------------------
 | 
					-----------------------------------
 | 
				
			||||||
Congratulations, your cloud is up and running, you’ve created an admin user, retrieved the user's credentials and put them in your environment.
 | 
					Congratulations, your cloud is up and running, you’ve created an admin user, created a network, retrieved the user's credentials and put them in your environment.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Now you need an image.
 | 
					Now you need an image.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -54,6 +54,8 @@ Cloud computing offers different service models depending on the capabilities a
 | 
				
			|||||||
The US-based National Institute of Standards and Technology offers definitions for cloud computing
 | 
					The US-based National Institute of Standards and Technology offers definitions for cloud computing
 | 
				
			||||||
and the service models that are emerging. 
 | 
					and the service models that are emerging. 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					These definitions are summarized from http://csrc.nist.gov/groups/SNS/cloud-computing/.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
SaaS - Software as a Service
 | 
					SaaS - Software as a Service
 | 
				
			||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 | 
					^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -72,12 +74,15 @@ IaaS - Infrastructure as a Service
 | 
				
			|||||||
Provides infrastructure such as computer instances, network connections, and storage so that people 
 | 
					Provides infrastructure such as computer instances, network connections, and storage so that people 
 | 
				
			||||||
can run any software or operating system.
 | 
					can run any software or operating system.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.. todo:: Use definitions from http://csrc.nist.gov/groups/SNS/cloud-computing/ and attribute NIST
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
Types of Cloud Deployments
 | 
					Types of Cloud Deployments
 | 
				
			||||||
--------------------------
 | 
					--------------------------
 | 
				
			||||||
.. todo:: describe public/private/hybrid/etc
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					When you hear terms such as public cloud or private cloud, these refer to the deployment model for the cloud. A private cloud operates for a single organization, but can be managed on-premise or off-premise. A public cloud has an infrastructure that is available to the general public or a large industry group and is likely owned by a cloud services company. 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The NIST also defines community cloud as shared by several organizations supporting a specific community with shared concerns. 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					A hybrid cloud can be a deployment model, as a composition of both public and private clouds, or a hybrid model for cloud computing may involve both virtual and physical servers.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Work in the Clouds
 | 
					Work in the Clouds
 | 
				
			||||||
------------------
 | 
					------------------
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										
											BIN
										
									
								
								doc/source/images/novascreens.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								doc/source/images/novascreens.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 27 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								doc/source/images/novashvirtually.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								doc/source/images/novashvirtually.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 38 KiB  | 
@@ -26,7 +26,7 @@ Nova is written with the following design guidelines in mind:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
* **Component based architecture**: Quickly add new behaviors
 | 
					* **Component based architecture**: Quickly add new behaviors
 | 
				
			||||||
* **Highly available**: Scale to very serious workloads
 | 
					* **Highly available**: Scale to very serious workloads
 | 
				
			||||||
* **Fault-Tollerant**: Isloated processes avoid cascading failures
 | 
					* **Fault-Tolerant**: Isolated processes avoid cascading failures
 | 
				
			||||||
* **Recoverable**: Failures should be easy to diagnose, debug, and rectify
 | 
					* **Recoverable**: Failures should be easy to diagnose, debug, and rectify
 | 
				
			||||||
* **Open Standards**: Be a reference implementation for a community-driven api
 | 
					* **Open Standards**: Be a reference implementation for a community-driven api
 | 
				
			||||||
* **API Compatibility**: Nova strives to provide API-compatible with popular systems like Amazon EC2
 | 
					* **API Compatibility**: Nova strives to provide API-compatible with popular systems like Amazon EC2
 | 
				
			||||||
@@ -62,8 +62,6 @@ Administrator's Documentation
 | 
				
			|||||||
   adminguide/single.node.install
 | 
					   adminguide/single.node.install
 | 
				
			||||||
   adminguide/multi.node.install
 | 
					   adminguide/multi.node.install
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.. todo:: add swiftadmin
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Developer Docs
 | 
					Developer Docs
 | 
				
			||||||
==============
 | 
					==============
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,2 +1,48 @@
 | 
				
			|||||||
Installing the Live CD
 | 
					Installing the Live CD
 | 
				
			||||||
======================
 | 
					======================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					If you'd like to set up a sandbox installation of Nova, you can use one of these Live CD images. 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					If you don't already have VirtualBox installed, you can download it from http://www.virtualbox.org/wiki/Downloads.
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					Download the zip or iso file and then follow these steps to try Nova in a virtual environment.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					http://c0047913.cdn1.cloudfiles.rackspacecloud.com/OpenStackNova.x86_64-2010.1.2.iso (OpenSUSE image; root password is "linux" for this image)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					http://c0028699.cdn1.cloudfiles.rackspacecloud.com/nova-vm.zip (~900 MB) (log in information is nova/nova)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Once a VM is configured and started, here are the basics:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 #. Login to Ubuntu using ID nova and Password nova.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 #. Switch to running as sudo (enter nova when prompted for the password)::
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sudo -s
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 #. To run Nova for the first time, enter::
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cd /var/openstack/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 #. Now that you're in the correct directory, enter::
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ./nova.sh run
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    .. image:: images/novashvirtually.png
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					If it's already running, use screen -ls, and when the nova screen is presented,then enter screen -d -r nova.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					These are the steps to get an instance running (the image is already provided in this environment). Enter these commands in the "test" screen.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					::
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 euca-add-keypair test > test.pem
 | 
				
			||||||
 | 
					 chmod 600 test.pem
 | 
				
			||||||
 | 
					 euca-run-instances -k test -t m1.tiny ami-tiny
 | 
				
			||||||
 | 
					 euca-describe-instances
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 ssh -i test.pem root@10.0.0.3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					To see output from the various workers, switch screen windows with Ctrl+A " (quotation mark). 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    .. image:: images/novascreens.png 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -194,6 +194,7 @@ class HostInfo(object):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class NovaAdminClient(object):
 | 
					class NovaAdminClient(object):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __init__(
 | 
					    def __init__(
 | 
				
			||||||
            self,
 | 
					            self,
 | 
				
			||||||
            clc_url=DEFAULT_CLC_URL,
 | 
					            clc_url=DEFAULT_CLC_URL,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -37,7 +37,6 @@ class DbDriver(object):
 | 
				
			|||||||
    def __init__(self):
 | 
					    def __init__(self):
 | 
				
			||||||
        """Imports the LDAP module"""
 | 
					        """Imports the LDAP module"""
 | 
				
			||||||
        pass
 | 
					        pass
 | 
				
			||||||
        db
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __enter__(self):
 | 
					    def __enter__(self):
 | 
				
			||||||
        return self
 | 
					        return self
 | 
				
			||||||
@@ -83,7 +82,7 @@ class DbDriver(object):
 | 
				
			|||||||
            user_ref = db.user_create(context.get_admin_context(), values)
 | 
					            user_ref = db.user_create(context.get_admin_context(), values)
 | 
				
			||||||
            return self._db_user_to_auth_user(user_ref)
 | 
					            return self._db_user_to_auth_user(user_ref)
 | 
				
			||||||
        except exception.Duplicate, e:
 | 
					        except exception.Duplicate, e:
 | 
				
			||||||
            raise exception.Duplicate('User %s already exists' % name)
 | 
					            raise exception.Duplicate(_('User %s already exists') % name)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def _db_user_to_auth_user(self, user_ref):
 | 
					    def _db_user_to_auth_user(self, user_ref):
 | 
				
			||||||
        return {'id': user_ref['id'],
 | 
					        return {'id': user_ref['id'],
 | 
				
			||||||
@@ -105,8 +104,9 @@ class DbDriver(object):
 | 
				
			|||||||
        """Create a project"""
 | 
					        """Create a project"""
 | 
				
			||||||
        manager = db.user_get(context.get_admin_context(), manager_uid)
 | 
					        manager = db.user_get(context.get_admin_context(), manager_uid)
 | 
				
			||||||
        if not manager:
 | 
					        if not manager:
 | 
				
			||||||
            raise exception.NotFound("Project can't be created because "
 | 
					            raise exception.NotFound(_("Project can't be created because "
 | 
				
			||||||
                                     "manager %s doesn't exist" % manager_uid)
 | 
					                                       "manager %s doesn't exist")
 | 
				
			||||||
 | 
					                                     % manager_uid)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # description is a required attribute
 | 
					        # description is a required attribute
 | 
				
			||||||
        if description is None:
 | 
					        if description is None:
 | 
				
			||||||
@@ -133,8 +133,8 @@ class DbDriver(object):
 | 
				
			|||||||
        try:
 | 
					        try:
 | 
				
			||||||
            project = db.project_create(context.get_admin_context(), values)
 | 
					            project = db.project_create(context.get_admin_context(), values)
 | 
				
			||||||
        except exception.Duplicate:
 | 
					        except exception.Duplicate:
 | 
				
			||||||
            raise exception.Duplicate("Project can't be created because "
 | 
					            raise exception.Duplicate(_("Project can't be created because "
 | 
				
			||||||
                                      "project %s already exists" % name)
 | 
					                                        "project %s already exists") % name)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for member in members:
 | 
					        for member in members:
 | 
				
			||||||
            db.project_add_member(context.get_admin_context(),
 | 
					            db.project_add_member(context.get_admin_context(),
 | 
				
			||||||
@@ -155,8 +155,8 @@ class DbDriver(object):
 | 
				
			|||||||
        if manager_uid:
 | 
					        if manager_uid:
 | 
				
			||||||
            manager = db.user_get(context.get_admin_context(), manager_uid)
 | 
					            manager = db.user_get(context.get_admin_context(), manager_uid)
 | 
				
			||||||
            if not manager:
 | 
					            if not manager:
 | 
				
			||||||
                raise exception.NotFound("Project can't be modified because "
 | 
					                raise exception.NotFound(_("Project can't be modified because "
 | 
				
			||||||
                                          "manager %s doesn't exist" %
 | 
					                                           "manager %s doesn't exist") %
 | 
				
			||||||
                                          manager_uid)
 | 
					                                          manager_uid)
 | 
				
			||||||
            values['project_manager'] = manager['id']
 | 
					            values['project_manager'] = manager['id']
 | 
				
			||||||
        if description:
 | 
					        if description:
 | 
				
			||||||
@@ -243,8 +243,8 @@ class DbDriver(object):
 | 
				
			|||||||
    def _validate_user_and_project(self, user_id, project_id):
 | 
					    def _validate_user_and_project(self, user_id, project_id):
 | 
				
			||||||
        user = db.user_get(context.get_admin_context(), user_id)
 | 
					        user = db.user_get(context.get_admin_context(), user_id)
 | 
				
			||||||
        if not user:
 | 
					        if not user:
 | 
				
			||||||
            raise exception.NotFound('User "%s" not found' % user_id)
 | 
					            raise exception.NotFound(_('User "%s" not found') % user_id)
 | 
				
			||||||
        project = db.project_get(context.get_admin_context(), project_id)
 | 
					        project = db.project_get(context.get_admin_context(), project_id)
 | 
				
			||||||
        if not project:
 | 
					        if not project:
 | 
				
			||||||
            raise exception.NotFound('Project "%s" not found' % project_id)
 | 
					            raise exception.NotFound(_('Project "%s" not found') % project_id)
 | 
				
			||||||
        return user, project
 | 
					        return user, project
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,7 +15,7 @@
 | 
				
			|||||||
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
					#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
				
			||||||
#    License for the specific language governing permissions and limitations
 | 
					#    License for the specific language governing permissions and limitations
 | 
				
			||||||
#    under the License.
 | 
					#    under the License.
 | 
				
			||||||
"""Fake LDAP server for test harness, backs to ReDIS.
 | 
					"""Fake LDAP server for test harness.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
This class does very little error checking, and knows nothing about ldap
 | 
					This class does very little error checking, and knows nothing about ldap
 | 
				
			||||||
class definitions.  It implements the minimum emulation of the python ldap
 | 
					class definitions.  It implements the minimum emulation of the python ldap
 | 
				
			||||||
@@ -23,34 +23,65 @@ library to work with nova.
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
"""
 | 
					"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import fnmatch
 | 
				
			||||||
import json
 | 
					import json
 | 
				
			||||||
import redis
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from nova import flags
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
FLAGS = flags.FLAGS
 | 
					 | 
				
			||||||
flags.DEFINE_string('redis_host', '127.0.0.1',
 | 
					 | 
				
			||||||
                    'Host that redis is running on.')
 | 
					 | 
				
			||||||
flags.DEFINE_integer('redis_port', 6379,
 | 
					 | 
				
			||||||
                    'Port that redis is running on.')
 | 
					 | 
				
			||||||
flags.DEFINE_integer('redis_db', 0, 'Multiple DB keeps tests away')
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Redis(object):
 | 
					class Store(object):
 | 
				
			||||||
    def __init__(self):
 | 
					    def __init__(self):
 | 
				
			||||||
        if hasattr(self.__class__, '_instance'):
 | 
					        if hasattr(self.__class__, '_instance'):
 | 
				
			||||||
            raise Exception('Attempted to instantiate singleton')
 | 
					            raise Exception(_('Attempted to instantiate singleton'))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @classmethod
 | 
					    @classmethod
 | 
				
			||||||
    def instance(cls):
 | 
					    def instance(cls):
 | 
				
			||||||
        if not hasattr(cls, '_instance'):
 | 
					        if not hasattr(cls, '_instance'):
 | 
				
			||||||
            inst = redis.Redis(host=FLAGS.redis_host,
 | 
					            cls._instance = _StorageDict()
 | 
				
			||||||
                               port=FLAGS.redis_port,
 | 
					 | 
				
			||||||
                               db=FLAGS.redis_db)
 | 
					 | 
				
			||||||
            cls._instance = inst
 | 
					 | 
				
			||||||
        return cls._instance
 | 
					        return cls._instance
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class _StorageDict(dict):
 | 
				
			||||||
 | 
					    def keys(self, pat=None):
 | 
				
			||||||
 | 
					        ret = super(_StorageDict, self).keys()
 | 
				
			||||||
 | 
					        if pat is not None:
 | 
				
			||||||
 | 
					            ret = fnmatch.filter(ret, pat)
 | 
				
			||||||
 | 
					        return ret
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def delete(self, key):
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            del self[key]
 | 
				
			||||||
 | 
					        except KeyError:
 | 
				
			||||||
 | 
					            pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def flushdb(self):
 | 
				
			||||||
 | 
					        self.clear()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def hgetall(self, key):
 | 
				
			||||||
 | 
					        """Returns the hash for the given key; creates
 | 
				
			||||||
 | 
					        the hash if the key doesn't exist."""
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            return self[key]
 | 
				
			||||||
 | 
					        except KeyError:
 | 
				
			||||||
 | 
					            self[key] = {}
 | 
				
			||||||
 | 
					            return self[key]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def hget(self, key, field):
 | 
				
			||||||
 | 
					        hashdict = self.hgetall(key)
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            return hashdict[field]
 | 
				
			||||||
 | 
					        except KeyError:
 | 
				
			||||||
 | 
					            hashdict[field] = {}
 | 
				
			||||||
 | 
					            return hashdict[field]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def hset(self, key, field, val):
 | 
				
			||||||
 | 
					        hashdict = self.hgetall(key)
 | 
				
			||||||
 | 
					        hashdict[field] = val
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def hmset(self, key, value_dict):
 | 
				
			||||||
 | 
					        hashdict = self.hgetall(key)
 | 
				
			||||||
 | 
					        for field, val in value_dict.items():
 | 
				
			||||||
 | 
					            hashdict[field] = val
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
SCOPE_BASE = 0
 | 
					SCOPE_BASE = 0
 | 
				
			||||||
SCOPE_ONELEVEL = 1  # Not implemented
 | 
					SCOPE_ONELEVEL = 1  # Not implemented
 | 
				
			||||||
SCOPE_SUBTREE = 2
 | 
					SCOPE_SUBTREE = 2
 | 
				
			||||||
@@ -119,6 +150,9 @@ def _match(key, value, attrs):
 | 
				
			|||||||
    """Match a given key and value against an attribute list."""
 | 
					    """Match a given key and value against an attribute list."""
 | 
				
			||||||
    if key not in attrs:
 | 
					    if key not in attrs:
 | 
				
			||||||
        return False
 | 
					        return False
 | 
				
			||||||
 | 
					    # This is a wild card search. Implemented as all or nothing for now.
 | 
				
			||||||
 | 
					    if value == "*":
 | 
				
			||||||
 | 
					        return True
 | 
				
			||||||
    if key != "objectclass":
 | 
					    if key != "objectclass":
 | 
				
			||||||
        return value in attrs[key]
 | 
					        return value in attrs[key]
 | 
				
			||||||
    # it is an objectclass check, so check subclasses
 | 
					    # it is an objectclass check, so check subclasses
 | 
				
			||||||
@@ -169,8 +203,6 @@ def _to_json(unencoded):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class FakeLDAP(object):
 | 
					class FakeLDAP(object):
 | 
				
			||||||
    #TODO(vish): refactor this class to use a wrapper instead of accessing
 | 
					 | 
				
			||||||
    #            redis directly
 | 
					 | 
				
			||||||
    """Fake LDAP connection."""
 | 
					    """Fake LDAP connection."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def simple_bind_s(self, dn, password):
 | 
					    def simple_bind_s(self, dn, password):
 | 
				
			||||||
@@ -183,14 +215,13 @@ class FakeLDAP(object):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    def add_s(self, dn, attr):
 | 
					    def add_s(self, dn, attr):
 | 
				
			||||||
        """Add an object with the specified attributes at dn."""
 | 
					        """Add an object with the specified attributes at dn."""
 | 
				
			||||||
        key = "%s%s" % (self.__redis_prefix, dn)
 | 
					        key = "%s%s" % (self.__prefix, dn)
 | 
				
			||||||
 | 
					 | 
				
			||||||
        value_dict = dict([(k, _to_json(v)) for k, v in attr])
 | 
					        value_dict = dict([(k, _to_json(v)) for k, v in attr])
 | 
				
			||||||
        Redis.instance().hmset(key, value_dict)
 | 
					        Store.instance().hmset(key, value_dict)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def delete_s(self, dn):
 | 
					    def delete_s(self, dn):
 | 
				
			||||||
        """Remove the ldap object at specified dn."""
 | 
					        """Remove the ldap object at specified dn."""
 | 
				
			||||||
        Redis.instance().delete("%s%s" % (self.__redis_prefix, dn))
 | 
					        Store.instance().delete("%s%s" % (self.__prefix, dn))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def modify_s(self, dn, attrs):
 | 
					    def modify_s(self, dn, attrs):
 | 
				
			||||||
        """Modify the object at dn using the attribute list.
 | 
					        """Modify the object at dn using the attribute list.
 | 
				
			||||||
@@ -201,18 +232,18 @@ class FakeLDAP(object):
 | 
				
			|||||||
            ([MOD_ADD | MOD_DELETE | MOD_REPACE], attribute, value)
 | 
					            ([MOD_ADD | MOD_DELETE | MOD_REPACE], attribute, value)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        redis = Redis.instance()
 | 
					        store = Store.instance()
 | 
				
			||||||
        key = "%s%s" % (self.__redis_prefix, dn)
 | 
					        key = "%s%s" % (self.__prefix, dn)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for cmd, k, v in attrs:
 | 
					        for cmd, k, v in attrs:
 | 
				
			||||||
            values = _from_json(redis.hget(key, k))
 | 
					            values = _from_json(store.hget(key, k))
 | 
				
			||||||
            if cmd == MOD_ADD:
 | 
					            if cmd == MOD_ADD:
 | 
				
			||||||
                values.append(v)
 | 
					                values.append(v)
 | 
				
			||||||
            elif cmd == MOD_REPLACE:
 | 
					            elif cmd == MOD_REPLACE:
 | 
				
			||||||
                values = [v]
 | 
					                values = [v]
 | 
				
			||||||
            else:
 | 
					            else:
 | 
				
			||||||
                values.remove(v)
 | 
					                values.remove(v)
 | 
				
			||||||
            values = redis.hset(key, k, _to_json(values))
 | 
					            values = store.hset(key, k, _to_json(values))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def search_s(self, dn, scope, query=None, fields=None):
 | 
					    def search_s(self, dn, scope, query=None, fields=None):
 | 
				
			||||||
        """Search for all matching objects under dn using the query.
 | 
					        """Search for all matching objects under dn using the query.
 | 
				
			||||||
@@ -226,16 +257,17 @@ class FakeLDAP(object):
 | 
				
			|||||||
        """
 | 
					        """
 | 
				
			||||||
        if scope != SCOPE_BASE and scope != SCOPE_SUBTREE:
 | 
					        if scope != SCOPE_BASE and scope != SCOPE_SUBTREE:
 | 
				
			||||||
            raise NotImplementedError(str(scope))
 | 
					            raise NotImplementedError(str(scope))
 | 
				
			||||||
        redis = Redis.instance()
 | 
					        store = Store.instance()
 | 
				
			||||||
        if scope == SCOPE_BASE:
 | 
					        if scope == SCOPE_BASE:
 | 
				
			||||||
            keys = ["%s%s" % (self.__redis_prefix, dn)]
 | 
					            keys = ["%s%s" % (self.__prefix, dn)]
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            keys = redis.keys("%s*%s" % (self.__redis_prefix, dn))
 | 
					            keys = store.keys("%s*%s" % (self.__prefix, dn))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        objects = []
 | 
					        objects = []
 | 
				
			||||||
        for key in keys:
 | 
					        for key in keys:
 | 
				
			||||||
            # get the attributes from redis
 | 
					            # get the attributes from the store
 | 
				
			||||||
            attrs = redis.hgetall(key)
 | 
					            attrs = store.hgetall(key)
 | 
				
			||||||
            # turn the values from redis into lists
 | 
					            # turn the values from the store into lists
 | 
				
			||||||
            # pylint: disable-msg=E1103
 | 
					            # pylint: disable-msg=E1103
 | 
				
			||||||
            attrs = dict([(k, _from_json(v))
 | 
					            attrs = dict([(k, _from_json(v))
 | 
				
			||||||
                          for k, v in attrs.iteritems()])
 | 
					                          for k, v in attrs.iteritems()])
 | 
				
			||||||
@@ -244,13 +276,13 @@ class FakeLDAP(object):
 | 
				
			|||||||
                # filter the attributes by fields
 | 
					                # filter the attributes by fields
 | 
				
			||||||
                attrs = dict([(k, v) for k, v in attrs.iteritems()
 | 
					                attrs = dict([(k, v) for k, v in attrs.iteritems()
 | 
				
			||||||
                              if not fields or k in fields])
 | 
					                              if not fields or k in fields])
 | 
				
			||||||
                objects.append((key[len(self.__redis_prefix):], attrs))
 | 
					                objects.append((key[len(self.__prefix):], attrs))
 | 
				
			||||||
            # pylint: enable-msg=E1103
 | 
					            # pylint: enable-msg=E1103
 | 
				
			||||||
        if objects == []:
 | 
					        if objects == []:
 | 
				
			||||||
            raise NO_SUCH_OBJECT()
 | 
					            raise NO_SUCH_OBJECT()
 | 
				
			||||||
        return objects
 | 
					        return objects
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @property
 | 
					    @property
 | 
				
			||||||
    def __redis_prefix(self):  # pylint: disable-msg=R0201
 | 
					    def __prefix(self):  # pylint: disable-msg=R0201
 | 
				
			||||||
        """Get the prefix to use for all redis keys."""
 | 
					        """Get the prefix to use for all keys."""
 | 
				
			||||||
        return 'ldap:'
 | 
					        return 'ldap:'
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -32,14 +32,21 @@ from nova import flags
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
FLAGS = flags.FLAGS
 | 
					FLAGS = flags.FLAGS
 | 
				
			||||||
 | 
					flags.DEFINE_integer('ldap_schema_version', 2,
 | 
				
			||||||
 | 
					                     'Current version of the LDAP schema')
 | 
				
			||||||
flags.DEFINE_string('ldap_url', 'ldap://localhost',
 | 
					flags.DEFINE_string('ldap_url', 'ldap://localhost',
 | 
				
			||||||
                    'Point this at your ldap server')
 | 
					                    'Point this at your ldap server')
 | 
				
			||||||
flags.DEFINE_string('ldap_password', 'changeme', 'LDAP password')
 | 
					flags.DEFINE_string('ldap_password', 'changeme', 'LDAP password')
 | 
				
			||||||
flags.DEFINE_string('ldap_user_dn', 'cn=Manager,dc=example,dc=com',
 | 
					flags.DEFINE_string('ldap_user_dn', 'cn=Manager,dc=example,dc=com',
 | 
				
			||||||
                    'DN of admin user')
 | 
					                    'DN of admin user')
 | 
				
			||||||
 | 
					flags.DEFINE_string('ldap_user_id_attribute', 'uid', 'Attribute to use as id')
 | 
				
			||||||
 | 
					flags.DEFINE_string('ldap_user_name_attribute', 'cn',
 | 
				
			||||||
 | 
					                    'Attribute to use as name')
 | 
				
			||||||
flags.DEFINE_string('ldap_user_unit', 'Users', 'OID for Users')
 | 
					flags.DEFINE_string('ldap_user_unit', 'Users', 'OID for Users')
 | 
				
			||||||
flags.DEFINE_string('ldap_user_subtree', 'ou=Users,dc=example,dc=com',
 | 
					flags.DEFINE_string('ldap_user_subtree', 'ou=Users,dc=example,dc=com',
 | 
				
			||||||
                    'OU for Users')
 | 
					                    'OU for Users')
 | 
				
			||||||
 | 
					flags.DEFINE_boolean('ldap_user_modify_only', False,
 | 
				
			||||||
 | 
					                    'Modify attributes for users instead of creating/deleting')
 | 
				
			||||||
flags.DEFINE_string('ldap_project_subtree', 'ou=Groups,dc=example,dc=com',
 | 
					flags.DEFINE_string('ldap_project_subtree', 'ou=Groups,dc=example,dc=com',
 | 
				
			||||||
                    'OU for Projects')
 | 
					                    'OU for Projects')
 | 
				
			||||||
flags.DEFINE_string('role_project_subtree', 'ou=Groups,dc=example,dc=com',
 | 
					flags.DEFINE_string('role_project_subtree', 'ou=Groups,dc=example,dc=com',
 | 
				
			||||||
@@ -71,10 +78,20 @@ class LdapDriver(object):
 | 
				
			|||||||
    Defines enter and exit and therefore supports the with/as syntax.
 | 
					    Defines enter and exit and therefore supports the with/as syntax.
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    project_pattern = '(owner=*)'
 | 
				
			||||||
 | 
					    isadmin_attribute = 'isNovaAdmin'
 | 
				
			||||||
 | 
					    project_attribute = 'owner'
 | 
				
			||||||
 | 
					    project_objectclass = 'groupOfNames'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __init__(self):
 | 
					    def __init__(self):
 | 
				
			||||||
        """Imports the LDAP module"""
 | 
					        """Imports the LDAP module"""
 | 
				
			||||||
        self.ldap = __import__('ldap')
 | 
					        self.ldap = __import__('ldap')
 | 
				
			||||||
        self.conn = None
 | 
					        self.conn = None
 | 
				
			||||||
 | 
					        if FLAGS.ldap_schema_version == 1:
 | 
				
			||||||
 | 
					            LdapDriver.project_pattern = '(objectclass=novaProject)'
 | 
				
			||||||
 | 
					            LdapDriver.isadmin_attribute = 'isAdmin'
 | 
				
			||||||
 | 
					            LdapDriver.project_attribute = 'projectManager'
 | 
				
			||||||
 | 
					            LdapDriver.project_objectclass = 'novaProject'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __enter__(self):
 | 
					    def __enter__(self):
 | 
				
			||||||
        """Creates the connection to LDAP"""
 | 
					        """Creates the connection to LDAP"""
 | 
				
			||||||
@@ -89,8 +106,7 @@ class LdapDriver(object):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    def get_user(self, uid):
 | 
					    def get_user(self, uid):
 | 
				
			||||||
        """Retrieve user by id"""
 | 
					        """Retrieve user by id"""
 | 
				
			||||||
        attr = self.__find_object(self.__uid_to_dn(uid),
 | 
					        attr = self.__get_ldap_user(uid)
 | 
				
			||||||
                                '(objectclass=novaUser)')
 | 
					 | 
				
			||||||
        return self.__to_user(attr)
 | 
					        return self.__to_user(attr)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_user_from_access_key(self, access):
 | 
					    def get_user_from_access_key(self, access):
 | 
				
			||||||
@@ -103,18 +119,23 @@ class LdapDriver(object):
 | 
				
			|||||||
        """Retrieve project by id"""
 | 
					        """Retrieve project by id"""
 | 
				
			||||||
        dn = 'cn=%s,%s' % (pid,
 | 
					        dn = 'cn=%s,%s' % (pid,
 | 
				
			||||||
                           FLAGS.ldap_project_subtree)
 | 
					                           FLAGS.ldap_project_subtree)
 | 
				
			||||||
        attr = self.__find_object(dn, '(objectclass=novaProject)')
 | 
					        attr = self.__find_object(dn, LdapDriver.project_pattern)
 | 
				
			||||||
        return self.__to_project(attr)
 | 
					        return self.__to_project(attr)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_users(self):
 | 
					    def get_users(self):
 | 
				
			||||||
        """Retrieve list of users"""
 | 
					        """Retrieve list of users"""
 | 
				
			||||||
        attrs = self.__find_objects(FLAGS.ldap_user_subtree,
 | 
					        attrs = self.__find_objects(FLAGS.ldap_user_subtree,
 | 
				
			||||||
                                  '(objectclass=novaUser)')
 | 
					                                    '(objectclass=novaUser)')
 | 
				
			||||||
        return [self.__to_user(attr) for attr in attrs]
 | 
					        users = []
 | 
				
			||||||
 | 
					        for attr in attrs:
 | 
				
			||||||
 | 
					            user = self.__to_user(attr)
 | 
				
			||||||
 | 
					            if user is not None:
 | 
				
			||||||
 | 
					                users.append(user)
 | 
				
			||||||
 | 
					        return users
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_projects(self, uid=None):
 | 
					    def get_projects(self, uid=None):
 | 
				
			||||||
        """Retrieve list of projects"""
 | 
					        """Retrieve list of projects"""
 | 
				
			||||||
        pattern = '(objectclass=novaProject)'
 | 
					        pattern = LdapDriver.project_pattern
 | 
				
			||||||
        if uid:
 | 
					        if uid:
 | 
				
			||||||
            pattern = "(&%s(member=%s))" % (pattern, self.__uid_to_dn(uid))
 | 
					            pattern = "(&%s(member=%s))" % (pattern, self.__uid_to_dn(uid))
 | 
				
			||||||
        attrs = self.__find_objects(FLAGS.ldap_project_subtree,
 | 
					        attrs = self.__find_objects(FLAGS.ldap_project_subtree,
 | 
				
			||||||
@@ -125,51 +146,85 @@ class LdapDriver(object):
 | 
				
			|||||||
        """Create a user"""
 | 
					        """Create a user"""
 | 
				
			||||||
        if self.__user_exists(name):
 | 
					        if self.__user_exists(name):
 | 
				
			||||||
            raise exception.Duplicate("LDAP user %s already exists" % name)
 | 
					            raise exception.Duplicate("LDAP user %s already exists" % name)
 | 
				
			||||||
        attr = [
 | 
					        if FLAGS.ldap_user_modify_only:
 | 
				
			||||||
            ('objectclass', ['person',
 | 
					            if self.__ldap_user_exists(name):
 | 
				
			||||||
                             'organizationalPerson',
 | 
					                # Retrieve user by name
 | 
				
			||||||
                             'inetOrgPerson',
 | 
					                user = self.__get_ldap_user(name)
 | 
				
			||||||
                             'novaUser']),
 | 
					                # Entry could be malformed, test for missing attrs.
 | 
				
			||||||
            ('ou', [FLAGS.ldap_user_unit]),
 | 
					                # Malformed entries are useless, replace attributes found.
 | 
				
			||||||
            ('uid', [name]),
 | 
					                attr = []
 | 
				
			||||||
            ('sn', [name]),
 | 
					                if 'secretKey' in user.keys():
 | 
				
			||||||
            ('cn', [name]),
 | 
					                    attr.append((self.ldap.MOD_REPLACE, 'secretKey',
 | 
				
			||||||
            ('secretKey', [secret_key]),
 | 
					                                 [secret_key]))
 | 
				
			||||||
            ('accessKey', [access_key]),
 | 
					                else:
 | 
				
			||||||
            ('isAdmin', [str(is_admin).upper()]),
 | 
					                    attr.append((self.ldap.MOD_ADD, 'secretKey',
 | 
				
			||||||
        ]
 | 
					                                 [secret_key]))
 | 
				
			||||||
        self.conn.add_s(self.__uid_to_dn(name), attr)
 | 
					                if 'accessKey' in user.keys():
 | 
				
			||||||
        return self.__to_user(dict(attr))
 | 
					                    attr.append((self.ldap.MOD_REPLACE, 'accessKey',
 | 
				
			||||||
 | 
					                                 [access_key]))
 | 
				
			||||||
 | 
					                else:
 | 
				
			||||||
 | 
					                    attr.append((self.ldap.MOD_ADD, 'accessKey',
 | 
				
			||||||
 | 
					                                 [access_key]))
 | 
				
			||||||
 | 
					                if LdapDriver.isadmin_attribute in user.keys():
 | 
				
			||||||
 | 
					                    attr.append((self.ldap.MOD_REPLACE,
 | 
				
			||||||
 | 
					                                 LdapDriver.isadmin_attribute,
 | 
				
			||||||
 | 
					                                 [str(is_admin).upper()]))
 | 
				
			||||||
 | 
					                else:
 | 
				
			||||||
 | 
					                    attr.append((self.ldap.MOD_ADD,
 | 
				
			||||||
 | 
					                                 LdapDriver.isadmin_attribute,
 | 
				
			||||||
 | 
					                                 [str(is_admin).upper()]))
 | 
				
			||||||
 | 
					                self.conn.modify_s(self.__uid_to_dn(name), attr)
 | 
				
			||||||
 | 
					                return self.get_user(name)
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                raise exception.NotFound(_("LDAP object for %s doesn't exist")
 | 
				
			||||||
 | 
					                                         % name)
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            attr = [
 | 
				
			||||||
 | 
					                ('objectclass', ['person',
 | 
				
			||||||
 | 
					                                 'organizationalPerson',
 | 
				
			||||||
 | 
					                                 'inetOrgPerson',
 | 
				
			||||||
 | 
					                                 'novaUser']),
 | 
				
			||||||
 | 
					                ('ou', [FLAGS.ldap_user_unit]),
 | 
				
			||||||
 | 
					                (FLAGS.ldap_user_id_attribute, [name]),
 | 
				
			||||||
 | 
					                ('sn', [name]),
 | 
				
			||||||
 | 
					                (FLAGS.ldap_user_name_attribute, [name]),
 | 
				
			||||||
 | 
					                ('secretKey', [secret_key]),
 | 
				
			||||||
 | 
					                ('accessKey', [access_key]),
 | 
				
			||||||
 | 
					                (LdapDriver.isadmin_attribute, [str(is_admin).upper()]),
 | 
				
			||||||
 | 
					            ]
 | 
				
			||||||
 | 
					            self.conn.add_s(self.__uid_to_dn(name), attr)
 | 
				
			||||||
 | 
					            return self.__to_user(dict(attr))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def create_project(self, name, manager_uid,
 | 
					    def create_project(self, name, manager_uid,
 | 
				
			||||||
                       description=None, member_uids=None):
 | 
					                       description=None, member_uids=None):
 | 
				
			||||||
        """Create a project"""
 | 
					        """Create a project"""
 | 
				
			||||||
        if self.__project_exists(name):
 | 
					        if self.__project_exists(name):
 | 
				
			||||||
            raise exception.Duplicate("Project can't be created because "
 | 
					            raise exception.Duplicate(_("Project can't be created because "
 | 
				
			||||||
                                      "project %s already exists" % name)
 | 
					                                        "project %s already exists") % name)
 | 
				
			||||||
        if not self.__user_exists(manager_uid):
 | 
					        if not self.__user_exists(manager_uid):
 | 
				
			||||||
            raise exception.NotFound("Project can't be created because "
 | 
					            raise exception.NotFound(_("Project can't be created because "
 | 
				
			||||||
                                     "manager %s doesn't exist" % manager_uid)
 | 
					                                       "manager %s doesn't exist")
 | 
				
			||||||
 | 
					                                     % manager_uid)
 | 
				
			||||||
        manager_dn = self.__uid_to_dn(manager_uid)
 | 
					        manager_dn = self.__uid_to_dn(manager_uid)
 | 
				
			||||||
        # description is a required attribute
 | 
					        # description is a required attribute
 | 
				
			||||||
        if description is None:
 | 
					        if description is None:
 | 
				
			||||||
            description = name
 | 
					            description = name
 | 
				
			||||||
        members = []
 | 
					        members = []
 | 
				
			||||||
        if member_uids != None:
 | 
					        if member_uids is not None:
 | 
				
			||||||
            for member_uid in member_uids:
 | 
					            for member_uid in member_uids:
 | 
				
			||||||
                if not self.__user_exists(member_uid):
 | 
					                if not self.__user_exists(member_uid):
 | 
				
			||||||
                    raise exception.NotFound("Project can't be created "
 | 
					                    raise exception.NotFound(_("Project can't be created "
 | 
				
			||||||
                                             "because user %s doesn't exist"
 | 
					                                               "because user %s doesn't exist")
 | 
				
			||||||
                                             % member_uid)
 | 
					                                             % member_uid)
 | 
				
			||||||
                members.append(self.__uid_to_dn(member_uid))
 | 
					                members.append(self.__uid_to_dn(member_uid))
 | 
				
			||||||
        # always add the manager as a member because members is required
 | 
					        # always add the manager as a member because members is required
 | 
				
			||||||
        if not manager_dn in members:
 | 
					        if not manager_dn in members:
 | 
				
			||||||
            members.append(manager_dn)
 | 
					            members.append(manager_dn)
 | 
				
			||||||
        attr = [
 | 
					        attr = [
 | 
				
			||||||
            ('objectclass', ['novaProject']),
 | 
					            ('objectclass', [LdapDriver.project_objectclass]),
 | 
				
			||||||
            ('cn', [name]),
 | 
					            ('cn', [name]),
 | 
				
			||||||
            ('description', [description]),
 | 
					            ('description', [description]),
 | 
				
			||||||
            ('projectManager', [manager_dn]),
 | 
					            (LdapDriver.project_attribute, [manager_dn]),
 | 
				
			||||||
            ('member', members)]
 | 
					            ('member', members)]
 | 
				
			||||||
        self.conn.add_s('cn=%s,%s' % (name, FLAGS.ldap_project_subtree), attr)
 | 
					        self.conn.add_s('cn=%s,%s' % (name, FLAGS.ldap_project_subtree), attr)
 | 
				
			||||||
        return self.__to_project(dict(attr))
 | 
					        return self.__to_project(dict(attr))
 | 
				
			||||||
@@ -181,11 +236,12 @@ class LdapDriver(object):
 | 
				
			|||||||
        attr = []
 | 
					        attr = []
 | 
				
			||||||
        if manager_uid:
 | 
					        if manager_uid:
 | 
				
			||||||
            if not self.__user_exists(manager_uid):
 | 
					            if not self.__user_exists(manager_uid):
 | 
				
			||||||
                raise exception.NotFound("Project can't be modified because "
 | 
					                raise exception.NotFound(_("Project can't be modified because "
 | 
				
			||||||
                                         "manager %s doesn't exist" %
 | 
					                                           "manager %s doesn't exist")
 | 
				
			||||||
                                         manager_uid)
 | 
					                                         % manager_uid)
 | 
				
			||||||
            manager_dn = self.__uid_to_dn(manager_uid)
 | 
					            manager_dn = self.__uid_to_dn(manager_uid)
 | 
				
			||||||
            attr.append((self.ldap.MOD_REPLACE, 'projectManager', manager_dn))
 | 
					            attr.append((self.ldap.MOD_REPLACE, LdapDriver.project_attribute,
 | 
				
			||||||
 | 
					                         manager_dn))
 | 
				
			||||||
        if description:
 | 
					        if description:
 | 
				
			||||||
            attr.append((self.ldap.MOD_REPLACE, 'description', description))
 | 
					            attr.append((self.ldap.MOD_REPLACE, 'description', description))
 | 
				
			||||||
        self.conn.modify_s('cn=%s,%s' % (project_id,
 | 
					        self.conn.modify_s('cn=%s,%s' % (project_id,
 | 
				
			||||||
@@ -245,10 +301,9 @@ class LdapDriver(object):
 | 
				
			|||||||
            return roles
 | 
					            return roles
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            project_dn = 'cn=%s,%s' % (project_id, FLAGS.ldap_project_subtree)
 | 
					            project_dn = 'cn=%s,%s' % (project_id, FLAGS.ldap_project_subtree)
 | 
				
			||||||
            roles = self.__find_objects(project_dn,
 | 
					            query = ('(&(&(objectclass=groupOfNames)(!%s))(member=%s))' %
 | 
				
			||||||
                                        '(&(&(objectclass=groupOfNames)'
 | 
					                     (LdapDriver.project_pattern, self.__uid_to_dn(uid)))
 | 
				
			||||||
                                        '(!(objectclass=novaProject)))'
 | 
					            roles = self.__find_objects(project_dn, query)
 | 
				
			||||||
                                        '(member=%s))' % self.__uid_to_dn(uid))
 | 
					 | 
				
			||||||
            return [role['cn'][0] for role in roles]
 | 
					            return [role['cn'][0] for role in roles]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def delete_user(self, uid):
 | 
					    def delete_user(self, uid):
 | 
				
			||||||
@@ -256,7 +311,25 @@ class LdapDriver(object):
 | 
				
			|||||||
        if not self.__user_exists(uid):
 | 
					        if not self.__user_exists(uid):
 | 
				
			||||||
            raise exception.NotFound("User %s doesn't exist" % uid)
 | 
					            raise exception.NotFound("User %s doesn't exist" % uid)
 | 
				
			||||||
        self.__remove_from_all(uid)
 | 
					        self.__remove_from_all(uid)
 | 
				
			||||||
        self.conn.delete_s(self.__uid_to_dn(uid))
 | 
					        if FLAGS.ldap_user_modify_only:
 | 
				
			||||||
 | 
					            # Delete attributes
 | 
				
			||||||
 | 
					            attr = []
 | 
				
			||||||
 | 
					            # Retrieve user by name
 | 
				
			||||||
 | 
					            user = self.__get_ldap_user(uid)
 | 
				
			||||||
 | 
					            if 'secretKey' in user.keys():
 | 
				
			||||||
 | 
					                attr.append((self.ldap.MOD_DELETE, 'secretKey',
 | 
				
			||||||
 | 
					                             user['secretKey']))
 | 
				
			||||||
 | 
					            if 'accessKey' in user.keys():
 | 
				
			||||||
 | 
					                attr.append((self.ldap.MOD_DELETE, 'accessKey',
 | 
				
			||||||
 | 
					                             user['accessKey']))
 | 
				
			||||||
 | 
					            if LdapDriver.isadmin_attribute in user.keys():
 | 
				
			||||||
 | 
					                attr.append((self.ldap.MOD_DELETE,
 | 
				
			||||||
 | 
					                             LdapDriver.isadmin_attribute,
 | 
				
			||||||
 | 
					                             user[LdapDriver.isadmin_attribute]))
 | 
				
			||||||
 | 
					            self.conn.modify_s(self.__uid_to_dn(uid), attr)
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            # Delete entry
 | 
				
			||||||
 | 
					            self.conn.delete_s(self.__uid_to_dn(uid))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def delete_project(self, project_id):
 | 
					    def delete_project(self, project_id):
 | 
				
			||||||
        """Delete a project"""
 | 
					        """Delete a project"""
 | 
				
			||||||
@@ -265,7 +338,7 @@ class LdapDriver(object):
 | 
				
			|||||||
        self.__delete_group(project_dn)
 | 
					        self.__delete_group(project_dn)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def modify_user(self, uid, access_key=None, secret_key=None, admin=None):
 | 
					    def modify_user(self, uid, access_key=None, secret_key=None, admin=None):
 | 
				
			||||||
        """Modify an existing project"""
 | 
					        """Modify an existing user"""
 | 
				
			||||||
        if not access_key and not secret_key and admin is None:
 | 
					        if not access_key and not secret_key and admin is None:
 | 
				
			||||||
            return
 | 
					            return
 | 
				
			||||||
        attr = []
 | 
					        attr = []
 | 
				
			||||||
@@ -274,16 +347,27 @@ class LdapDriver(object):
 | 
				
			|||||||
        if secret_key:
 | 
					        if secret_key:
 | 
				
			||||||
            attr.append((self.ldap.MOD_REPLACE, 'secretKey', secret_key))
 | 
					            attr.append((self.ldap.MOD_REPLACE, 'secretKey', secret_key))
 | 
				
			||||||
        if admin is not None:
 | 
					        if admin is not None:
 | 
				
			||||||
            attr.append((self.ldap.MOD_REPLACE, 'isAdmin', str(admin).upper()))
 | 
					            attr.append((self.ldap.MOD_REPLACE, LdapDriver.isadmin_attribute,
 | 
				
			||||||
 | 
					                         str(admin).upper()))
 | 
				
			||||||
        self.conn.modify_s(self.__uid_to_dn(uid), attr)
 | 
					        self.conn.modify_s(self.__uid_to_dn(uid), attr)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __user_exists(self, uid):
 | 
					    def __user_exists(self, uid):
 | 
				
			||||||
        """Check if user exists"""
 | 
					        """Check if user exists"""
 | 
				
			||||||
        return self.get_user(uid) != None
 | 
					        return self.get_user(uid) is not None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __ldap_user_exists(self, uid):
 | 
				
			||||||
 | 
					        """Check if the user exists in ldap"""
 | 
				
			||||||
 | 
					        return self.__get_ldap_user(uid) is not None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __project_exists(self, project_id):
 | 
					    def __project_exists(self, project_id):
 | 
				
			||||||
        """Check if project exists"""
 | 
					        """Check if project exists"""
 | 
				
			||||||
        return self.get_project(project_id) != None
 | 
					        return self.get_project(project_id) is not None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __get_ldap_user(self, uid):
 | 
				
			||||||
 | 
					        """Retrieve LDAP user entry by id"""
 | 
				
			||||||
 | 
					        attr = self.__find_object(self.__uid_to_dn(uid),
 | 
				
			||||||
 | 
					                                  '(objectclass=novaUser)')
 | 
				
			||||||
 | 
					        return attr
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __find_object(self, dn, query=None, scope=None):
 | 
					    def __find_object(self, dn, query=None, scope=None):
 | 
				
			||||||
        """Find an object by dn and query"""
 | 
					        """Find an object by dn and query"""
 | 
				
			||||||
@@ -318,24 +402,26 @@ class LdapDriver(object):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    def __find_role_dns(self, tree):
 | 
					    def __find_role_dns(self, tree):
 | 
				
			||||||
        """Find dns of role objects in given tree"""
 | 
					        """Find dns of role objects in given tree"""
 | 
				
			||||||
        return self.__find_dns(tree,
 | 
					        query = ('(&(objectclass=groupOfNames)(!%s))' %
 | 
				
			||||||
                '(&(objectclass=groupOfNames)(!(objectclass=novaProject)))')
 | 
					                 LdapDriver.project_pattern)
 | 
				
			||||||
 | 
					        return self.__find_dns(tree, query)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __find_group_dns_with_member(self, tree, uid):
 | 
					    def __find_group_dns_with_member(self, tree, uid):
 | 
				
			||||||
        """Find dns of group objects in a given tree that contain member"""
 | 
					        """Find dns of group objects in a given tree that contain member"""
 | 
				
			||||||
        dns = self.__find_dns(tree,
 | 
					        query = ('(&(objectclass=groupOfNames)(member=%s))' %
 | 
				
			||||||
                            '(&(objectclass=groupOfNames)(member=%s))' %
 | 
					                 self.__uid_to_dn(uid))
 | 
				
			||||||
                            self.__uid_to_dn(uid))
 | 
					        dns = self.__find_dns(tree, query)
 | 
				
			||||||
        return dns
 | 
					        return dns
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __group_exists(self, dn):
 | 
					    def __group_exists(self, dn):
 | 
				
			||||||
        """Check if group exists"""
 | 
					        """Check if group exists"""
 | 
				
			||||||
        return self.__find_object(dn, '(objectclass=groupOfNames)') != None
 | 
					        query = '(objectclass=groupOfNames)'
 | 
				
			||||||
 | 
					        return self.__find_object(dn, query) is not None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @staticmethod
 | 
					    @staticmethod
 | 
				
			||||||
    def __role_to_dn(role, project_id=None):
 | 
					    def __role_to_dn(role, project_id=None):
 | 
				
			||||||
        """Convert role to corresponding dn"""
 | 
					        """Convert role to corresponding dn"""
 | 
				
			||||||
        if project_id == None:
 | 
					        if project_id is None:
 | 
				
			||||||
            return FLAGS.__getitem__("ldap_%s" % role).value
 | 
					            return FLAGS.__getitem__("ldap_%s" % role).value
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            return 'cn=%s,cn=%s,%s' % (role,
 | 
					            return 'cn=%s,cn=%s,%s' % (role,
 | 
				
			||||||
@@ -349,11 +435,12 @@ class LdapDriver(object):
 | 
				
			|||||||
            raise exception.Duplicate("Group can't be created because "
 | 
					            raise exception.Duplicate("Group can't be created because "
 | 
				
			||||||
                                      "group %s already exists" % name)
 | 
					                                      "group %s already exists" % name)
 | 
				
			||||||
        members = []
 | 
					        members = []
 | 
				
			||||||
        if member_uids != None:
 | 
					        if member_uids is not None:
 | 
				
			||||||
            for member_uid in member_uids:
 | 
					            for member_uid in member_uids:
 | 
				
			||||||
                if not self.__user_exists(member_uid):
 | 
					                if not self.__user_exists(member_uid):
 | 
				
			||||||
                    raise exception.NotFound("Group can't be created "
 | 
					                    raise exception.NotFound("Group can't be created "
 | 
				
			||||||
                            "because user %s doesn't exist" % member_uid)
 | 
					                                             "because user %s doesn't exist" %
 | 
				
			||||||
 | 
					                                             member_uid)
 | 
				
			||||||
                members.append(self.__uid_to_dn(member_uid))
 | 
					                members.append(self.__uid_to_dn(member_uid))
 | 
				
			||||||
        dn = self.__uid_to_dn(uid)
 | 
					        dn = self.__uid_to_dn(uid)
 | 
				
			||||||
        if not dn in members:
 | 
					        if not dn in members:
 | 
				
			||||||
@@ -369,25 +456,25 @@ class LdapDriver(object):
 | 
				
			|||||||
        """Check if user is in group"""
 | 
					        """Check if user is in group"""
 | 
				
			||||||
        if not self.__user_exists(uid):
 | 
					        if not self.__user_exists(uid):
 | 
				
			||||||
            raise exception.NotFound("User %s can't be searched in group "
 | 
					            raise exception.NotFound("User %s can't be searched in group "
 | 
				
			||||||
                    "becuase the user doesn't exist" % (uid,))
 | 
					                                     "because the user doesn't exist" % uid)
 | 
				
			||||||
        if not self.__group_exists(group_dn):
 | 
					        if not self.__group_exists(group_dn):
 | 
				
			||||||
            return False
 | 
					            return False
 | 
				
			||||||
        res = self.__find_object(group_dn,
 | 
					        res = self.__find_object(group_dn,
 | 
				
			||||||
                                 '(member=%s)' % self.__uid_to_dn(uid),
 | 
					                                 '(member=%s)' % self.__uid_to_dn(uid),
 | 
				
			||||||
                                 self.ldap.SCOPE_BASE)
 | 
					                                 self.ldap.SCOPE_BASE)
 | 
				
			||||||
        return res != None
 | 
					        return res is not None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __add_to_group(self, uid, group_dn):
 | 
					    def __add_to_group(self, uid, group_dn):
 | 
				
			||||||
        """Add user to group"""
 | 
					        """Add user to group"""
 | 
				
			||||||
        if not self.__user_exists(uid):
 | 
					        if not self.__user_exists(uid):
 | 
				
			||||||
            raise exception.NotFound("User %s can't be added to the group "
 | 
					            raise exception.NotFound("User %s can't be added to the group "
 | 
				
			||||||
                    "becuase the user doesn't exist" % (uid,))
 | 
					                                     "because the user doesn't exist" % uid)
 | 
				
			||||||
        if not self.__group_exists(group_dn):
 | 
					        if not self.__group_exists(group_dn):
 | 
				
			||||||
            raise exception.NotFound("The group at dn %s doesn't exist" %
 | 
					            raise exception.NotFound("The group at dn %s doesn't exist" %
 | 
				
			||||||
                                     (group_dn,))
 | 
					                                     group_dn)
 | 
				
			||||||
        if self.__is_in_group(uid, group_dn):
 | 
					        if self.__is_in_group(uid, group_dn):
 | 
				
			||||||
            raise exception.Duplicate("User %s is already a member of "
 | 
					            raise exception.Duplicate(_("User %s is already a member of "
 | 
				
			||||||
                                      "the group %s" % (uid, group_dn))
 | 
					                                        "the group %s") % (uid, group_dn))
 | 
				
			||||||
        attr = [(self.ldap.MOD_ADD, 'member', self.__uid_to_dn(uid))]
 | 
					        attr = [(self.ldap.MOD_ADD, 'member', self.__uid_to_dn(uid))]
 | 
				
			||||||
        self.conn.modify_s(group_dn, attr)
 | 
					        self.conn.modify_s(group_dn, attr)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -395,16 +482,16 @@ class LdapDriver(object):
 | 
				
			|||||||
        """Remove user from group"""
 | 
					        """Remove user from group"""
 | 
				
			||||||
        if not self.__group_exists(group_dn):
 | 
					        if not self.__group_exists(group_dn):
 | 
				
			||||||
            raise exception.NotFound("The group at dn %s doesn't exist" %
 | 
					            raise exception.NotFound("The group at dn %s doesn't exist" %
 | 
				
			||||||
                                     (group_dn,))
 | 
					                                     group_dn)
 | 
				
			||||||
        if not self.__user_exists(uid):
 | 
					        if not self.__user_exists(uid):
 | 
				
			||||||
            raise exception.NotFound("User %s can't be removed from the "
 | 
					            raise exception.NotFound("User %s can't be removed from the "
 | 
				
			||||||
                    "group because the user doesn't exist" % (uid,))
 | 
					                                     "group because the user doesn't exist" %
 | 
				
			||||||
 | 
					                                     uid)
 | 
				
			||||||
        if not self.__is_in_group(uid, group_dn):
 | 
					        if not self.__is_in_group(uid, group_dn):
 | 
				
			||||||
            raise exception.NotFound("User %s is not a member of the group" %
 | 
					            raise exception.NotFound("User %s is not a member of the group" %
 | 
				
			||||||
                                     (uid,))
 | 
					                                     uid)
 | 
				
			||||||
        # NOTE(vish): remove user from group and any sub_groups
 | 
					        # NOTE(vish): remove user from group and any sub_groups
 | 
				
			||||||
        sub_dns = self.__find_group_dns_with_member(
 | 
					        sub_dns = self.__find_group_dns_with_member(group_dn, uid)
 | 
				
			||||||
                group_dn, uid)
 | 
					 | 
				
			||||||
        for sub_dn in sub_dns:
 | 
					        for sub_dn in sub_dns:
 | 
				
			||||||
            self.__safe_remove_from_group(uid, sub_dn)
 | 
					            self.__safe_remove_from_group(uid, sub_dn)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -415,15 +502,15 @@ class LdapDriver(object):
 | 
				
			|||||||
        try:
 | 
					        try:
 | 
				
			||||||
            self.conn.modify_s(group_dn, attr)
 | 
					            self.conn.modify_s(group_dn, attr)
 | 
				
			||||||
        except self.ldap.OBJECT_CLASS_VIOLATION:
 | 
					        except self.ldap.OBJECT_CLASS_VIOLATION:
 | 
				
			||||||
            logging.debug("Attempted to remove the last member of a group. "
 | 
					            logging.debug(_("Attempted to remove the last member of a group. "
 | 
				
			||||||
                          "Deleting the group at %s instead.", group_dn)
 | 
					                            "Deleting the group at %s instead."), group_dn)
 | 
				
			||||||
            self.__delete_group(group_dn)
 | 
					            self.__delete_group(group_dn)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __remove_from_all(self, uid):
 | 
					    def __remove_from_all(self, uid):
 | 
				
			||||||
        """Remove user from all roles and projects"""
 | 
					        """Remove user from all roles and projects"""
 | 
				
			||||||
        if not self.__user_exists(uid):
 | 
					        if not self.__user_exists(uid):
 | 
				
			||||||
            raise exception.NotFound("User %s can't be removed from all "
 | 
					            raise exception.NotFound("User %s can't be removed from all "
 | 
				
			||||||
                    "because the user doesn't exist" % (uid,))
 | 
					                                     "because the user doesn't exist" % uid)
 | 
				
			||||||
        role_dns = self.__find_group_dns_with_member(
 | 
					        role_dns = self.__find_group_dns_with_member(
 | 
				
			||||||
                FLAGS.role_project_subtree, uid)
 | 
					                FLAGS.role_project_subtree, uid)
 | 
				
			||||||
        for role_dn in role_dns:
 | 
					        for role_dn in role_dns:
 | 
				
			||||||
@@ -436,7 +523,8 @@ class LdapDriver(object):
 | 
				
			|||||||
    def __delete_group(self, group_dn):
 | 
					    def __delete_group(self, group_dn):
 | 
				
			||||||
        """Delete Group"""
 | 
					        """Delete Group"""
 | 
				
			||||||
        if not self.__group_exists(group_dn):
 | 
					        if not self.__group_exists(group_dn):
 | 
				
			||||||
            raise exception.NotFound("Group at dn %s doesn't exist" % group_dn)
 | 
					            raise exception.NotFound(_("Group at dn %s doesn't exist")
 | 
				
			||||||
 | 
					                                     % group_dn)
 | 
				
			||||||
        self.conn.delete_s(group_dn)
 | 
					        self.conn.delete_s(group_dn)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __delete_roles(self, project_dn):
 | 
					    def __delete_roles(self, project_dn):
 | 
				
			||||||
@@ -447,24 +535,29 @@ class LdapDriver(object):
 | 
				
			|||||||
    @staticmethod
 | 
					    @staticmethod
 | 
				
			||||||
    def __to_user(attr):
 | 
					    def __to_user(attr):
 | 
				
			||||||
        """Convert ldap attributes to User object"""
 | 
					        """Convert ldap attributes to User object"""
 | 
				
			||||||
        if attr == None:
 | 
					        if attr is None:
 | 
				
			||||||
 | 
					            return None
 | 
				
			||||||
 | 
					        if ('accessKey' in attr.keys() and 'secretKey' in attr.keys() \
 | 
				
			||||||
 | 
					            and LdapDriver.isadmin_attribute in attr.keys()):
 | 
				
			||||||
 | 
					            return {
 | 
				
			||||||
 | 
					                'id': attr[FLAGS.ldap_user_id_attribute][0],
 | 
				
			||||||
 | 
					                'name': attr[FLAGS.ldap_user_name_attribute][0],
 | 
				
			||||||
 | 
					                'access': attr['accessKey'][0],
 | 
				
			||||||
 | 
					                'secret': attr['secretKey'][0],
 | 
				
			||||||
 | 
					                'admin': (attr[LdapDriver.isadmin_attribute][0] == 'TRUE')}
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
            return None
 | 
					            return None
 | 
				
			||||||
        return {
 | 
					 | 
				
			||||||
            'id': attr['uid'][0],
 | 
					 | 
				
			||||||
            'name': attr['cn'][0],
 | 
					 | 
				
			||||||
            'access': attr['accessKey'][0],
 | 
					 | 
				
			||||||
            'secret': attr['secretKey'][0],
 | 
					 | 
				
			||||||
            'admin': (attr['isAdmin'][0] == 'TRUE')}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __to_project(self, attr):
 | 
					    def __to_project(self, attr):
 | 
				
			||||||
        """Convert ldap attributes to Project object"""
 | 
					        """Convert ldap attributes to Project object"""
 | 
				
			||||||
        if attr == None:
 | 
					        if attr is None:
 | 
				
			||||||
            return None
 | 
					            return None
 | 
				
			||||||
        member_dns = attr.get('member', [])
 | 
					        member_dns = attr.get('member', [])
 | 
				
			||||||
        return {
 | 
					        return {
 | 
				
			||||||
            'id': attr['cn'][0],
 | 
					            'id': attr['cn'][0],
 | 
				
			||||||
            'name': attr['cn'][0],
 | 
					            'name': attr['cn'][0],
 | 
				
			||||||
            'project_manager_id': self.__dn_to_uid(attr['projectManager'][0]),
 | 
					            'project_manager_id':
 | 
				
			||||||
 | 
					                self.__dn_to_uid(attr[LdapDriver.project_attribute][0]),
 | 
				
			||||||
            'description': attr.get('description', [None])[0],
 | 
					            'description': attr.get('description', [None])[0],
 | 
				
			||||||
            'member_ids': [self.__dn_to_uid(x) for x in member_dns]}
 | 
					            'member_ids': [self.__dn_to_uid(x) for x in member_dns]}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -474,9 +567,10 @@ class LdapDriver(object):
 | 
				
			|||||||
        return dn.split(',')[0].split('=')[1]
 | 
					        return dn.split(',')[0].split('=')[1]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @staticmethod
 | 
					    @staticmethod
 | 
				
			||||||
    def __uid_to_dn(dn):
 | 
					    def __uid_to_dn(uid):
 | 
				
			||||||
        """Convert uid to dn"""
 | 
					        """Convert uid to dn"""
 | 
				
			||||||
        return 'uid=%s,%s' % (dn, FLAGS.ldap_user_subtree)
 | 
					        return (FLAGS.ldap_user_id_attribute + '=%s,%s'
 | 
				
			||||||
 | 
					                % (uid, FLAGS.ldap_user_subtree))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class FakeLdapDriver(LdapDriver):
 | 
					class FakeLdapDriver(LdapDriver):
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -64,12 +64,9 @@ flags.DEFINE_string('credential_key_file', 'pk.pem',
 | 
				
			|||||||
                    'Filename of private key in credentials zip')
 | 
					                    'Filename of private key in credentials zip')
 | 
				
			||||||
flags.DEFINE_string('credential_cert_file', 'cert.pem',
 | 
					flags.DEFINE_string('credential_cert_file', 'cert.pem',
 | 
				
			||||||
                    'Filename of certificate in credentials zip')
 | 
					                    'Filename of certificate in credentials zip')
 | 
				
			||||||
flags.DEFINE_string('credential_rc_file', 'novarc',
 | 
					flags.DEFINE_string('credential_rc_file', '%src',
 | 
				
			||||||
                    'Filename of rc in credentials zip')
 | 
					                    'Filename of rc in credentials zip, %s will be '
 | 
				
			||||||
flags.DEFINE_string('credential_cert_subject',
 | 
					                    'replaced by name of the region (nova by default)')
 | 
				
			||||||
                    '/C=US/ST=California/L=MountainView/O=AnsoLabs/'
 | 
					 | 
				
			||||||
                    'OU=NovaDev/CN=%s-%s',
 | 
					 | 
				
			||||||
                    'Subject for certificate for users')
 | 
					 | 
				
			||||||
flags.DEFINE_string('auth_driver', 'nova.auth.dbdriver.DbDriver',
 | 
					flags.DEFINE_string('auth_driver', 'nova.auth.dbdriver.DbDriver',
 | 
				
			||||||
                    'Driver that auth manager uses')
 | 
					                    'Driver that auth manager uses')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -257,12 +254,12 @@ class AuthManager(object):
 | 
				
			|||||||
        # TODO(vish): check for valid timestamp
 | 
					        # TODO(vish): check for valid timestamp
 | 
				
			||||||
        (access_key, _sep, project_id) = access.partition(':')
 | 
					        (access_key, _sep, project_id) = access.partition(':')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        logging.info('Looking up user: %r', access_key)
 | 
					        logging.info(_('Looking up user: %r'), access_key)
 | 
				
			||||||
        user = self.get_user_from_access_key(access_key)
 | 
					        user = self.get_user_from_access_key(access_key)
 | 
				
			||||||
        logging.info('user: %r', user)
 | 
					        logging.info('user: %r', user)
 | 
				
			||||||
        if user == None:
 | 
					        if user == None:
 | 
				
			||||||
            raise exception.NotFound('No user found for access key %s' %
 | 
					            raise exception.NotFound(_('No user found for access key %s')
 | 
				
			||||||
                                     access_key)
 | 
					                                     % access_key)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # NOTE(vish): if we stop using project name as id we need better
 | 
					        # NOTE(vish): if we stop using project name as id we need better
 | 
				
			||||||
        #             logic to find a default project for user
 | 
					        #             logic to find a default project for user
 | 
				
			||||||
@@ -271,12 +268,12 @@ class AuthManager(object):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        project = self.get_project(project_id)
 | 
					        project = self.get_project(project_id)
 | 
				
			||||||
        if project == None:
 | 
					        if project == None:
 | 
				
			||||||
            raise exception.NotFound('No project called %s could be found' %
 | 
					            raise exception.NotFound(_('No project called %s could be found')
 | 
				
			||||||
                                     project_id)
 | 
					                                     % project_id)
 | 
				
			||||||
        if not self.is_admin(user) and not self.is_project_member(user,
 | 
					        if not self.is_admin(user) and not self.is_project_member(user,
 | 
				
			||||||
                                                                  project):
 | 
					                                                                  project):
 | 
				
			||||||
            raise exception.NotFound('User %s is not a member of project %s' %
 | 
					            raise exception.NotFound(_('User %s is not a member of project %s')
 | 
				
			||||||
                                     (user.id, project.id))
 | 
					                                     % (user.id, project.id))
 | 
				
			||||||
        if check_type == 's3':
 | 
					        if check_type == 's3':
 | 
				
			||||||
            sign = signer.Signer(user.secret.encode())
 | 
					            sign = signer.Signer(user.secret.encode())
 | 
				
			||||||
            expected_signature = sign.s3_authorization(headers, verb, path)
 | 
					            expected_signature = sign.s3_authorization(headers, verb, path)
 | 
				
			||||||
@@ -284,7 +281,7 @@ class AuthManager(object):
 | 
				
			|||||||
            logging.debug('expected_signature: %s', expected_signature)
 | 
					            logging.debug('expected_signature: %s', expected_signature)
 | 
				
			||||||
            logging.debug('signature: %s', signature)
 | 
					            logging.debug('signature: %s', signature)
 | 
				
			||||||
            if signature != expected_signature:
 | 
					            if signature != expected_signature:
 | 
				
			||||||
                raise exception.NotAuthorized('Signature does not match')
 | 
					                raise exception.NotAuthorized(_('Signature does not match'))
 | 
				
			||||||
        elif check_type == 'ec2':
 | 
					        elif check_type == 'ec2':
 | 
				
			||||||
            # NOTE(vish): hmac can't handle unicode, so encode ensures that
 | 
					            # NOTE(vish): hmac can't handle unicode, so encode ensures that
 | 
				
			||||||
            #             secret isn't unicode
 | 
					            #             secret isn't unicode
 | 
				
			||||||
@@ -294,7 +291,7 @@ class AuthManager(object):
 | 
				
			|||||||
            logging.debug('expected_signature: %s', expected_signature)
 | 
					            logging.debug('expected_signature: %s', expected_signature)
 | 
				
			||||||
            logging.debug('signature: %s', signature)
 | 
					            logging.debug('signature: %s', signature)
 | 
				
			||||||
            if signature != expected_signature:
 | 
					            if signature != expected_signature:
 | 
				
			||||||
                raise exception.NotAuthorized('Signature does not match')
 | 
					                raise exception.NotAuthorized(_('Signature does not match'))
 | 
				
			||||||
        return (user, project)
 | 
					        return (user, project)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_access_key(self, user, project):
 | 
					    def get_access_key(self, user, project):
 | 
				
			||||||
@@ -364,7 +361,7 @@ class AuthManager(object):
 | 
				
			|||||||
        with self.driver() as drv:
 | 
					        with self.driver() as drv:
 | 
				
			||||||
            if role == 'projectmanager':
 | 
					            if role == 'projectmanager':
 | 
				
			||||||
                if not project:
 | 
					                if not project:
 | 
				
			||||||
                    raise exception.Error("Must specify project")
 | 
					                    raise exception.Error(_("Must specify project"))
 | 
				
			||||||
                return self.is_project_manager(user, project)
 | 
					                return self.is_project_manager(user, project)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            global_role = drv.has_role(User.safe_id(user),
 | 
					            global_role = drv.has_role(User.safe_id(user),
 | 
				
			||||||
@@ -398,9 +395,9 @@ class AuthManager(object):
 | 
				
			|||||||
        @param project: Project in which to add local role.
 | 
					        @param project: Project in which to add local role.
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        if role not in FLAGS.allowed_roles:
 | 
					        if role not in FLAGS.allowed_roles:
 | 
				
			||||||
            raise exception.NotFound("The %s role can not be found" % role)
 | 
					            raise exception.NotFound(_("The %s role can not be found") % role)
 | 
				
			||||||
        if project is not None and role in FLAGS.global_roles:
 | 
					        if project is not None and role in FLAGS.global_roles:
 | 
				
			||||||
            raise exception.NotFound("The %s role is global only" % role)
 | 
					            raise exception.NotFound(_("The %s role is global only") % role)
 | 
				
			||||||
        with self.driver() as drv:
 | 
					        with self.driver() as drv:
 | 
				
			||||||
            drv.add_role(User.safe_id(user), role, Project.safe_id(project))
 | 
					            drv.add_role(User.safe_id(user), role, Project.safe_id(project))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -543,10 +540,10 @@ class AuthManager(object):
 | 
				
			|||||||
        """
 | 
					        """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        network_ref = db.project_get_network(context.get_admin_context(),
 | 
					        network_ref = db.project_get_network(context.get_admin_context(),
 | 
				
			||||||
                                             Project.safe_id(project))
 | 
					                                             Project.safe_id(project), False)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if not network_ref['vpn_public_port']:
 | 
					        if not network_ref:
 | 
				
			||||||
            raise exception.NotFound('project network data has not been set')
 | 
					            return (None, None)
 | 
				
			||||||
        return (network_ref['vpn_public_address'],
 | 
					        return (network_ref['vpn_public_address'],
 | 
				
			||||||
                network_ref['vpn_public_port'])
 | 
					                network_ref['vpn_public_port'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -624,27 +621,41 @@ class AuthManager(object):
 | 
				
			|||||||
        with self.driver() as drv:
 | 
					        with self.driver() as drv:
 | 
				
			||||||
            drv.modify_user(uid, access_key, secret_key, admin)
 | 
					            drv.modify_user(uid, access_key, secret_key, admin)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_credentials(self, user, project=None):
 | 
					    @staticmethod
 | 
				
			||||||
 | 
					    def get_key_pairs(context):
 | 
				
			||||||
 | 
					        return db.key_pair_get_all_by_user(context.elevated(), context.user_id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_credentials(self, user, project=None, use_dmz=True):
 | 
				
			||||||
        """Get credential zip for user in project"""
 | 
					        """Get credential zip for user in project"""
 | 
				
			||||||
        if not isinstance(user, User):
 | 
					        if not isinstance(user, User):
 | 
				
			||||||
            user = self.get_user(user)
 | 
					            user = self.get_user(user)
 | 
				
			||||||
        if project is None:
 | 
					        if project is None:
 | 
				
			||||||
            project = user.id
 | 
					            project = user.id
 | 
				
			||||||
        pid = Project.safe_id(project)
 | 
					        pid = Project.safe_id(project)
 | 
				
			||||||
        rc = self.__generate_rc(user.access, user.secret, pid)
 | 
					        private_key, signed_cert = crypto.generate_x509_cert(user.id, pid)
 | 
				
			||||||
        private_key, signed_cert = self._generate_x509_cert(user.id, pid)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        tmpdir = tempfile.mkdtemp()
 | 
					        tmpdir = tempfile.mkdtemp()
 | 
				
			||||||
        zf = os.path.join(tmpdir, "temp.zip")
 | 
					        zf = os.path.join(tmpdir, "temp.zip")
 | 
				
			||||||
        zippy = zipfile.ZipFile(zf, 'w')
 | 
					        zippy = zipfile.ZipFile(zf, 'w')
 | 
				
			||||||
        zippy.writestr(FLAGS.credential_rc_file, rc)
 | 
					        if use_dmz and FLAGS.region_list:
 | 
				
			||||||
 | 
					            regions = {}
 | 
				
			||||||
 | 
					            for item in FLAGS.region_list:
 | 
				
			||||||
 | 
					                region, _sep, region_host = item.partition("=")
 | 
				
			||||||
 | 
					                regions[region] = region_host
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            regions = {'nova': FLAGS.cc_host}
 | 
				
			||||||
 | 
					        for region, host in regions.iteritems():
 | 
				
			||||||
 | 
					            rc = self.__generate_rc(user.access,
 | 
				
			||||||
 | 
					                                    user.secret,
 | 
				
			||||||
 | 
					                                    pid,
 | 
				
			||||||
 | 
					                                    use_dmz,
 | 
				
			||||||
 | 
					                                    host)
 | 
				
			||||||
 | 
					            zippy.writestr(FLAGS.credential_rc_file % region, rc)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        zippy.writestr(FLAGS.credential_key_file, private_key)
 | 
					        zippy.writestr(FLAGS.credential_key_file, private_key)
 | 
				
			||||||
        zippy.writestr(FLAGS.credential_cert_file, signed_cert)
 | 
					        zippy.writestr(FLAGS.credential_cert_file, signed_cert)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        try:
 | 
					        (vpn_ip, vpn_port) = self.get_project_vpn_data(project)
 | 
				
			||||||
            (vpn_ip, vpn_port) = self.get_project_vpn_data(project)
 | 
					 | 
				
			||||||
        except exception.NotFound:
 | 
					 | 
				
			||||||
            vpn_ip = None
 | 
					 | 
				
			||||||
        if vpn_ip:
 | 
					        if vpn_ip:
 | 
				
			||||||
            configfile = open(FLAGS.vpn_client_template, "r")
 | 
					            configfile = open(FLAGS.vpn_client_template, "r")
 | 
				
			||||||
            s = string.Template(configfile.read())
 | 
					            s = string.Template(configfile.read())
 | 
				
			||||||
@@ -655,10 +666,9 @@ class AuthManager(object):
 | 
				
			|||||||
                                  port=vpn_port)
 | 
					                                  port=vpn_port)
 | 
				
			||||||
            zippy.writestr(FLAGS.credential_vpn_file, config)
 | 
					            zippy.writestr(FLAGS.credential_vpn_file, config)
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            logging.warn("No vpn data for project %s" %
 | 
					            logging.warn(_("No vpn data for project %s"), pid)
 | 
				
			||||||
                                  pid)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        zippy.writestr(FLAGS.ca_file, crypto.fetch_ca(user.id))
 | 
					        zippy.writestr(FLAGS.ca_file, crypto.fetch_ca(pid))
 | 
				
			||||||
        zippy.close()
 | 
					        zippy.close()
 | 
				
			||||||
        with open(zf, 'rb') as f:
 | 
					        with open(zf, 'rb') as f:
 | 
				
			||||||
            read_buffer = f.read()
 | 
					            read_buffer = f.read()
 | 
				
			||||||
@@ -666,38 +676,38 @@ class AuthManager(object):
 | 
				
			|||||||
        shutil.rmtree(tmpdir)
 | 
					        shutil.rmtree(tmpdir)
 | 
				
			||||||
        return read_buffer
 | 
					        return read_buffer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_environment_rc(self, user, project=None):
 | 
					    def get_environment_rc(self, user, project=None, use_dmz=True):
 | 
				
			||||||
        """Get credential zip for user in project"""
 | 
					        """Get credential zip for user in project"""
 | 
				
			||||||
        if not isinstance(user, User):
 | 
					        if not isinstance(user, User):
 | 
				
			||||||
            user = self.get_user(user)
 | 
					            user = self.get_user(user)
 | 
				
			||||||
        if project is None:
 | 
					        if project is None:
 | 
				
			||||||
            project = user.id
 | 
					            project = user.id
 | 
				
			||||||
        pid = Project.safe_id(project)
 | 
					        pid = Project.safe_id(project)
 | 
				
			||||||
        return self.__generate_rc(user.access, user.secret, pid)
 | 
					        return self.__generate_rc(user.access, user.secret, pid, use_dmz)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @staticmethod
 | 
					    @staticmethod
 | 
				
			||||||
    def __generate_rc(access, secret, pid):
 | 
					    def __generate_rc(access, secret, pid, use_dmz=True, host=None):
 | 
				
			||||||
        """Generate rc file for user"""
 | 
					        """Generate rc file for user"""
 | 
				
			||||||
 | 
					        if use_dmz:
 | 
				
			||||||
 | 
					            cc_host = FLAGS.cc_dmz
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            cc_host = FLAGS.cc_host
 | 
				
			||||||
 | 
					        # NOTE(vish): Always use the dmz since it is used from inside the
 | 
				
			||||||
 | 
					        #             instance
 | 
				
			||||||
 | 
					        s3_host = FLAGS.s3_dmz
 | 
				
			||||||
 | 
					        if host:
 | 
				
			||||||
 | 
					            s3_host = host
 | 
				
			||||||
 | 
					            cc_host = host
 | 
				
			||||||
        rc = open(FLAGS.credentials_template).read()
 | 
					        rc = open(FLAGS.credentials_template).read()
 | 
				
			||||||
        rc = rc % {'access': access,
 | 
					        rc = rc % {'access': access,
 | 
				
			||||||
                   'project': pid,
 | 
					                   'project': pid,
 | 
				
			||||||
                   'secret': secret,
 | 
					                   'secret': secret,
 | 
				
			||||||
                   'ec2': FLAGS.ec2_url,
 | 
					                   'ec2': '%s://%s:%s%s' % (FLAGS.ec2_prefix,
 | 
				
			||||||
                   's3': 'http://%s:%s' % (FLAGS.s3_host, FLAGS.s3_port),
 | 
					                                            cc_host,
 | 
				
			||||||
 | 
					                                            FLAGS.cc_port,
 | 
				
			||||||
 | 
					                                            FLAGS.ec2_suffix),
 | 
				
			||||||
 | 
					                   's3': 'http://%s:%s' % (s3_host, FLAGS.s3_port),
 | 
				
			||||||
                   'nova': FLAGS.ca_file,
 | 
					                   'nova': FLAGS.ca_file,
 | 
				
			||||||
                   'cert': FLAGS.credential_cert_file,
 | 
					                   'cert': FLAGS.credential_cert_file,
 | 
				
			||||||
                   'key': FLAGS.credential_key_file}
 | 
					                   'key': FLAGS.credential_key_file}
 | 
				
			||||||
        return rc
 | 
					        return rc
 | 
				
			||||||
 | 
					 | 
				
			||||||
    def _generate_x509_cert(self, uid, pid):
 | 
					 | 
				
			||||||
        """Generate x509 cert for user"""
 | 
					 | 
				
			||||||
        (private_key, csr) = crypto.generate_x509_cert(
 | 
					 | 
				
			||||||
                self.__cert_subject(uid))
 | 
					 | 
				
			||||||
        # TODO(joshua): This should be async call back to the cloud controller
 | 
					 | 
				
			||||||
        signed_cert = crypto.sign_csr(csr, pid)
 | 
					 | 
				
			||||||
        return (private_key, signed_cert)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @staticmethod
 | 
					 | 
				
			||||||
    def __cert_subject(uid):
 | 
					 | 
				
			||||||
        """Helper to generate cert subject"""
 | 
					 | 
				
			||||||
        return FLAGS.credential_cert_subject % (uid, utils.isotime())
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,9 @@
 | 
				
			|||||||
#
 | 
					#
 | 
				
			||||||
# Person object for Nova
 | 
					# Person object for Nova
 | 
				
			||||||
# inetorgperson with extra attributes
 | 
					# inetorgperson with extra attributes
 | 
				
			||||||
# Author: Vishvananda Ishaya <vishvananda@yahoo.com>
 | 
					# Schema version: 2
 | 
				
			||||||
 | 
					# Authors: Vishvananda Ishaya <vishvananda@gmail.com>
 | 
				
			||||||
 | 
					#          Ryan Lane <rlane@wikimedia.org>
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -30,55 +32,19 @@ attributetype (
 | 
				
			|||||||
    SINGLE-VALUE
 | 
					    SINGLE-VALUE
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
attributetype (
 | 
					 | 
				
			||||||
    novaAttrs:3
 | 
					 | 
				
			||||||
    NAME 'keyFingerprint'
 | 
					 | 
				
			||||||
    DESC 'Fingerprint of private key'
 | 
					 | 
				
			||||||
    EQUALITY caseIgnoreMatch
 | 
					 | 
				
			||||||
    SUBSTR caseIgnoreSubstringsMatch
 | 
					 | 
				
			||||||
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
 | 
					 | 
				
			||||||
    SINGLE-VALUE
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
attributetype (
 | 
					attributetype (
 | 
				
			||||||
    novaAttrs:4
 | 
					    novaAttrs:4
 | 
				
			||||||
    NAME 'isAdmin'
 | 
					    NAME 'isNovaAdmin'
 | 
				
			||||||
    DESC 'Is user an administrator?'
 | 
					    DESC 'Is user an nova administrator?'
 | 
				
			||||||
    EQUALITY booleanMatch
 | 
					    EQUALITY booleanMatch
 | 
				
			||||||
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.7
 | 
					    SYNTAX 1.3.6.1.4.1.1466.115.121.1.7
 | 
				
			||||||
    SINGLE-VALUE
 | 
					    SINGLE-VALUE
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
attributetype (
 | 
					 | 
				
			||||||
    novaAttrs:5
 | 
					 | 
				
			||||||
    NAME 'projectManager'
 | 
					 | 
				
			||||||
    DESC 'Project Managers of a project'
 | 
					 | 
				
			||||||
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.12
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
objectClass (
 | 
					objectClass (
 | 
				
			||||||
    novaOCs:1
 | 
					    novaOCs:1
 | 
				
			||||||
    NAME 'novaUser'
 | 
					    NAME 'novaUser'
 | 
				
			||||||
    DESC 'access and secret keys'
 | 
					    DESC 'access and secret keys'
 | 
				
			||||||
    AUXILIARY
 | 
					    AUXILIARY
 | 
				
			||||||
    MUST ( uid )
 | 
					    MAY  ( accessKey $ secretKey $ isNovaAdmin )
 | 
				
			||||||
    MAY  ( accessKey $ secretKey $ isAdmin )
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
objectClass (
 | 
					 | 
				
			||||||
    novaOCs:2
 | 
					 | 
				
			||||||
    NAME 'novaKeyPair'
 | 
					 | 
				
			||||||
    DESC 'Key pair for User'
 | 
					 | 
				
			||||||
    SUP top
 | 
					 | 
				
			||||||
    STRUCTURAL
 | 
					 | 
				
			||||||
    MUST ( cn $ sshPublicKey $ keyFingerprint )
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
objectClass (
 | 
					 | 
				
			||||||
    novaOCs:3
 | 
					 | 
				
			||||||
    NAME 'novaProject'
 | 
					 | 
				
			||||||
    DESC 'Container for project'
 | 
					 | 
				
			||||||
    SUP groupOfNames
 | 
					 | 
				
			||||||
    STRUCTURAL
 | 
					 | 
				
			||||||
    MUST ( cn $ projectManager )
 | 
					 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,16 +1,13 @@
 | 
				
			|||||||
#
 | 
					#
 | 
				
			||||||
# Person object for Nova
 | 
					# Person object for Nova
 | 
				
			||||||
# inetorgperson with extra attributes
 | 
					# inetorgperson with extra attributes
 | 
				
			||||||
# Author: Vishvananda Ishaya <vishvananda@yahoo.com>
 | 
					# Schema version: 2
 | 
				
			||||||
# Modified for strict RFC 4512 compatibility by: Ryan Lane <ryan@ryandlane.com>
 | 
					# Authors: Vishvananda Ishaya <vishvananda@gmail.com>
 | 
				
			||||||
 | 
					#          Ryan Lane <rlane@wikimedia.org>
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
# using internet experimental oid arc as per BP64 3.1
 | 
					# using internet experimental oid arc as per BP64 3.1
 | 
				
			||||||
dn: cn=schema
 | 
					dn: cn=schema
 | 
				
			||||||
attributeTypes: ( 1.3.6.1.3.1.666.666.3.1 NAME 'accessKey' DESC 'Key for accessing data' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
 | 
					attributeTypes: ( 1.3.6.1.3.1.666.666.3.1 NAME 'accessKey' DESC 'Key for accessing data' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
 | 
				
			||||||
attributeTypes: ( 1.3.6.1.3.1.666.666.3.2 NAME 'secretKey' DESC 'Secret key' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
 | 
					attributeTypes: ( 1.3.6.1.3.1.666.666.3.2 NAME 'secretKey' DESC 'Secret key' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
 | 
				
			||||||
attributeTypes: ( 1.3.6.1.3.1.666.666.3.3 NAME 'keyFingerprint' DESC 'Fingerprint of private key' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE)
 | 
					attributeTypes: ( 1.3.6.1.3.1.666.666.3.4 NAME 'isNovaAdmin' DESC 'Is user a nova administrator?' EQUALITY booleanMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE ) 
 | 
				
			||||||
attributeTypes: ( 1.3.6.1.3.1.666.666.3.4 NAME 'isAdmin' DESC 'Is user an administrator?' EQUALITY booleanMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE ) 
 | 
					objectClasses: ( 1.3.6.1.3.1.666.666.4.1 NAME 'novaUser' DESC 'access and secret keys' SUP top AUXILIARY MAY  ( accessKey $ secretKey $ isNovaAdmin ) ) 
 | 
				
			||||||
attributeTypes: ( 1.3.6.1.3.1.666.666.3.5 NAME 'projectManager' DESC 'Project Managers of a project' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )
 | 
					 | 
				
			||||||
objectClasses: ( 1.3.6.1.3.1.666.666.4.1 NAME 'novaUser' DESC 'access and secret keys' SUP top AUXILIARY MUST ( uid ) MAY  ( accessKey $ secretKey $ isAdmin ) ) 
 | 
					 | 
				
			||||||
objectClasses: ( 1.3.6.1.3.1.666.666.4.2 NAME 'novaKeyPair' DESC 'Key pair for User' SUP top STRUCTURAL MUST ( cn $ sshPublicKey $ keyFingerprint ) )
 | 
					 | 
				
			||||||
objectClasses: ( 1.3.6.1.3.1.666.666.4.3 NAME 'novaProject' DESC 'Container for project' SUP groupOfNames STRUCTURAL MUST ( cn $ projectManager ) )
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										118
									
								
								nova/auth/opendj.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										118
									
								
								nova/auth/opendj.sh
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,118 @@
 | 
				
			|||||||
 | 
					#!/usr/bin/env bash
 | 
				
			||||||
 | 
					# vim: tabstop=4 shiftwidth=4 softtabstop=4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Copyright 2010 United States Government as represented by the
 | 
				
			||||||
 | 
					# Administrator of the National Aeronautics and Space Administration.
 | 
				
			||||||
 | 
					# All Rights Reserved.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					#    Licensed under the Apache License, Version 2.0 (the "License"); you may
 | 
				
			||||||
 | 
					#    not use this file except in compliance with the License. You may obtain
 | 
				
			||||||
 | 
					#    a copy of the License at
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					#         http://www.apache.org/licenses/LICENSE-2.0
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					#    Unless required by applicable law or agreed to in writing, software
 | 
				
			||||||
 | 
					#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
				
			||||||
 | 
					#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
				
			||||||
 | 
					#    License for the specific language governing permissions and limitations
 | 
				
			||||||
 | 
					#    under the License.
 | 
				
			||||||
 | 
					# LDAP INSTALL SCRIPT -  IS IDEMPOTENT, does not scrub users
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					apt-get install -y ldap-utils python-ldap openjdk-6-jre
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if [ ! -d "/usr/opendj" ]
 | 
				
			||||||
 | 
					then
 | 
				
			||||||
 | 
					    # TODO(rlane): Wikimedia Foundation is the current package maintainer.
 | 
				
			||||||
 | 
					    # After the package is included in Ubuntu's channel, change this.
 | 
				
			||||||
 | 
					    wget http://apt.wikimedia.org/wikimedia/pool/main/o/opendj/opendj_2.4.0-7_amd64.deb
 | 
				
			||||||
 | 
					    dpkg -i opendj_2.4.0-7_amd64.deb
 | 
				
			||||||
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					abspath=`dirname "$(cd "${0%/*}" 2>/dev/null; echo "$PWD"/"${0##*/}")"`
 | 
				
			||||||
 | 
					schemapath='/var/opendj/instance/config/schema'
 | 
				
			||||||
 | 
					cp $abspath/openssh-lpk_sun.schema $schemapath/97-openssh-lpk_sun.ldif
 | 
				
			||||||
 | 
					cp $abspath/nova_sun.schema $schemapath/98-nova_sun.ldif
 | 
				
			||||||
 | 
					chown opendj:opendj $schemapath/98-nova_sun.ldif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					cat >/etc/ldap/ldap.conf <<LDAP_CONF_EOF
 | 
				
			||||||
 | 
					# LDAP Client Settings
 | 
				
			||||||
 | 
					URI ldap://localhost
 | 
				
			||||||
 | 
					BASE dc=example,dc=com
 | 
				
			||||||
 | 
					BINDDN cn=Directory Manager
 | 
				
			||||||
 | 
					SIZELIMIT  0
 | 
				
			||||||
 | 
					TIMELIMIT  0
 | 
				
			||||||
 | 
					LDAP_CONF_EOF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					cat >/etc/ldap/base.ldif <<BASE_LDIF_EOF
 | 
				
			||||||
 | 
					# This is the root of the directory tree
 | 
				
			||||||
 | 
					dn: dc=example,dc=com
 | 
				
			||||||
 | 
					description: Example.Com, your trusted non-existent corporation.
 | 
				
			||||||
 | 
					dc: example
 | 
				
			||||||
 | 
					o: Example.Com
 | 
				
			||||||
 | 
					objectClass: top
 | 
				
			||||||
 | 
					objectClass: dcObject
 | 
				
			||||||
 | 
					objectClass: organization
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Subtree for users
 | 
				
			||||||
 | 
					dn: ou=Users,dc=example,dc=com
 | 
				
			||||||
 | 
					ou: Users
 | 
				
			||||||
 | 
					description: Users
 | 
				
			||||||
 | 
					objectClass: organizationalUnit
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Subtree for groups
 | 
				
			||||||
 | 
					dn: ou=Groups,dc=example,dc=com
 | 
				
			||||||
 | 
					ou: Groups
 | 
				
			||||||
 | 
					description: Groups
 | 
				
			||||||
 | 
					objectClass: organizationalUnit
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Subtree for system accounts
 | 
				
			||||||
 | 
					dn: ou=System,dc=example,dc=com
 | 
				
			||||||
 | 
					ou: System
 | 
				
			||||||
 | 
					description: Special accounts used by software applications.
 | 
				
			||||||
 | 
					objectClass: organizationalUnit
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Special Account for Authentication:
 | 
				
			||||||
 | 
					dn: uid=authenticate,ou=System,dc=example,dc=com
 | 
				
			||||||
 | 
					uid: authenticate
 | 
				
			||||||
 | 
					ou: System
 | 
				
			||||||
 | 
					description: Special account for authenticating users
 | 
				
			||||||
 | 
					userPassword: {MD5}TLnIqASP0CKUR3/LGkEZGg==
 | 
				
			||||||
 | 
					objectClass: account
 | 
				
			||||||
 | 
					objectClass: simpleSecurityObject
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# create the sysadmin entry
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					dn: cn=developers,ou=Groups,dc=example,dc=com
 | 
				
			||||||
 | 
					objectclass: groupOfNames
 | 
				
			||||||
 | 
					cn: developers
 | 
				
			||||||
 | 
					description: IT admin group
 | 
				
			||||||
 | 
					member: uid=admin,ou=Users,dc=example,dc=com
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					dn: cn=sysadmins,ou=Groups,dc=example,dc=com
 | 
				
			||||||
 | 
					objectclass: groupOfNames
 | 
				
			||||||
 | 
					cn: sysadmins
 | 
				
			||||||
 | 
					description: IT admin group
 | 
				
			||||||
 | 
					member: uid=admin,ou=Users,dc=example,dc=com
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					dn: cn=netadmins,ou=Groups,dc=example,dc=com
 | 
				
			||||||
 | 
					objectclass: groupOfNames
 | 
				
			||||||
 | 
					cn: netadmins
 | 
				
			||||||
 | 
					description: Network admin group
 | 
				
			||||||
 | 
					member: uid=admin,ou=Users,dc=example,dc=com
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					dn: cn=cloudadmins,ou=Groups,dc=example,dc=com
 | 
				
			||||||
 | 
					objectclass: groupOfNames
 | 
				
			||||||
 | 
					cn: cloudadmins
 | 
				
			||||||
 | 
					description: Cloud admin group
 | 
				
			||||||
 | 
					member: uid=admin,ou=Users,dc=example,dc=com
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					dn: cn=itsec,ou=Groups,dc=example,dc=com
 | 
				
			||||||
 | 
					objectclass: groupOfNames
 | 
				
			||||||
 | 
					cn: itsec
 | 
				
			||||||
 | 
					description: IT security users group
 | 
				
			||||||
 | 
					member: uid=admin,ou=Users,dc=example,dc=com
 | 
				
			||||||
 | 
					BASE_LDIF_EOF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/etc/init.d/opendj stop
 | 
				
			||||||
 | 
					su - opendj -c '/usr/opendj/setup -i -b "dc=example,dc=com" -l /etc/ldap/base.ldif -S -w changeme -O -n --noPropertiesFile'
 | 
				
			||||||
 | 
					/etc/init.d/opendj start
 | 
				
			||||||
@@ -22,7 +22,7 @@ apt-get install -y slapd ldap-utils python-ldap
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
abspath=`dirname "$(cd "${0%/*}" 2>/dev/null; echo "$PWD"/"${0##*/}")"`
 | 
					abspath=`dirname "$(cd "${0%/*}" 2>/dev/null; echo "$PWD"/"${0##*/}")"`
 | 
				
			||||||
cp $abspath/openssh-lpk_openldap.schema /etc/ldap/schema/openssh-lpk_openldap.schema
 | 
					cp $abspath/openssh-lpk_openldap.schema /etc/ldap/schema/openssh-lpk_openldap.schema
 | 
				
			||||||
cp $abspath/nova_openldap.schema /etc/ldap/schema/nova_openldap.schema
 | 
					cp $abspath/nova_openldap.schema /etc/ldap/schema/nova.schema
 | 
				
			||||||
 | 
					
 | 
				
			||||||
mv /etc/ldap/slapd.conf /etc/ldap/slapd.conf.orig
 | 
					mv /etc/ldap/slapd.conf /etc/ldap/slapd.conf.orig
 | 
				
			||||||
cat >/etc/ldap/slapd.conf <<SLAPD_CONF_EOF
 | 
					cat >/etc/ldap/slapd.conf <<SLAPD_CONF_EOF
 | 
				
			||||||
@@ -33,7 +33,6 @@ cat >/etc/ldap/slapd.conf <<SLAPD_CONF_EOF
 | 
				
			|||||||
include /etc/ldap/schema/core.schema
 | 
					include /etc/ldap/schema/core.schema
 | 
				
			||||||
include /etc/ldap/schema/cosine.schema
 | 
					include /etc/ldap/schema/cosine.schema
 | 
				
			||||||
include /etc/ldap/schema/inetorgperson.schema
 | 
					include /etc/ldap/schema/inetorgperson.schema
 | 
				
			||||||
include /etc/ldap/schema/openssh-lpk_openldap.schema
 | 
					 | 
				
			||||||
include /etc/ldap/schema/nova.schema
 | 
					include /etc/ldap/schema/nova.schema
 | 
				
			||||||
pidfile /var/run/slapd/slapd.pid
 | 
					pidfile /var/run/slapd/slapd.pid
 | 
				
			||||||
argsfile /var/run/slapd/slapd.args
 | 
					argsfile /var/run/slapd/slapd.args
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -27,23 +27,26 @@ import traceback
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ProcessExecutionError(IOError):
 | 
					class ProcessExecutionError(IOError):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __init__(self, stdout=None, stderr=None, exit_code=None, cmd=None,
 | 
					    def __init__(self, stdout=None, stderr=None, exit_code=None, cmd=None,
 | 
				
			||||||
                 description=None):
 | 
					                 description=None):
 | 
				
			||||||
        if description is None:
 | 
					        if description is None:
 | 
				
			||||||
            description = "Unexpected error while running command."
 | 
					            description = _("Unexpected error while running command.")
 | 
				
			||||||
        if exit_code is None:
 | 
					        if exit_code is None:
 | 
				
			||||||
            exit_code = '-'
 | 
					            exit_code = '-'
 | 
				
			||||||
        message = "%s\nCommand: %s\nExit code: %s\nStdout: %r\nStderr: %r" % (
 | 
					        message = _("%s\nCommand: %s\nExit code: %s\nStdout: %r\nStderr: %r")\
 | 
				
			||||||
                  description, cmd, exit_code, stdout, stderr)
 | 
					                % (description, cmd, exit_code, stdout, stderr)
 | 
				
			||||||
        IOError.__init__(self, message)
 | 
					        IOError.__init__(self, message)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Error(Exception):
 | 
					class Error(Exception):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __init__(self, message=None):
 | 
					    def __init__(self, message=None):
 | 
				
			||||||
        super(Error, self).__init__(message)
 | 
					        super(Error, self).__init__(message)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ApiError(Error):
 | 
					class ApiError(Error):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __init__(self, message='Unknown', code='Unknown'):
 | 
					    def __init__(self, message='Unknown', code='Unknown'):
 | 
				
			||||||
        self.message = message
 | 
					        self.message = message
 | 
				
			||||||
        self.code = code
 | 
					        self.code = code
 | 
				
			||||||
@@ -81,7 +84,7 @@ def wrap_exception(f):
 | 
				
			|||||||
        except Exception, e:
 | 
					        except Exception, e:
 | 
				
			||||||
            if not isinstance(e, Error):
 | 
					            if not isinstance(e, Error):
 | 
				
			||||||
                #exc_type, exc_value, exc_traceback = sys.exc_info()
 | 
					                #exc_type, exc_value, exc_traceback = sys.exc_info()
 | 
				
			||||||
                logging.exception('Uncaught exception')
 | 
					                logging.exception(_('Uncaught exception'))
 | 
				
			||||||
                #logging.error(traceback.extract_stack(exc_traceback))
 | 
					                #logging.error(traceback.extract_stack(exc_traceback))
 | 
				
			||||||
                raise Error(str(e))
 | 
					                raise Error(str(e))
 | 
				
			||||||
            raise
 | 
					            raise
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										59
									
								
								nova/fakememcache.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								nova/fakememcache.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,59 @@
 | 
				
			|||||||
 | 
					# vim: tabstop=4 shiftwidth=4 softtabstop=4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Copyright 2010 United States Government as represented by the
 | 
				
			||||||
 | 
					# Administrator of the National Aeronautics and Space Administration.
 | 
				
			||||||
 | 
					# All Rights Reserved.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					#    Licensed under the Apache License, Version 2.0 (the "License"); you may
 | 
				
			||||||
 | 
					#    not use this file except in compliance with the License. You may obtain
 | 
				
			||||||
 | 
					#    a copy of the License at
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					#         http://www.apache.org/licenses/LICENSE-2.0
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					#    Unless required by applicable law or agreed to in writing, software
 | 
				
			||||||
 | 
					#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
				
			||||||
 | 
					#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
				
			||||||
 | 
					#    License for the specific language governing permissions and limitations
 | 
				
			||||||
 | 
					#    under the License.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					"""Super simple fake memcache client."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import utils
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Client(object):
 | 
				
			||||||
 | 
					    """Replicates a tiny subset of memcached client interface."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, *args, **kwargs):
 | 
				
			||||||
 | 
					        """Ignores the passed in args"""
 | 
				
			||||||
 | 
					        self.cache = {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get(self, key):
 | 
				
			||||||
 | 
					        """Retrieves the value for a key or None."""
 | 
				
			||||||
 | 
					        (timeout, value) = self.cache.get(key, (0, None))
 | 
				
			||||||
 | 
					        if timeout == 0 or utils.utcnow_ts() < timeout:
 | 
				
			||||||
 | 
					            return value
 | 
				
			||||||
 | 
					        return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def set(self, key, value, time=0, min_compress_len=0):
 | 
				
			||||||
 | 
					        """Sets the value for a key."""
 | 
				
			||||||
 | 
					        timeout = 0
 | 
				
			||||||
 | 
					        if time != 0:
 | 
				
			||||||
 | 
					            timeout = utils.utcnow_ts() + time
 | 
				
			||||||
 | 
					        self.cache[key] = (timeout, value)
 | 
				
			||||||
 | 
					        return True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def add(self, key, value, time=0, min_compress_len=0):
 | 
				
			||||||
 | 
					        """Sets the value for a key if it doesn't exist."""
 | 
				
			||||||
 | 
					        if not self.get(key) is None:
 | 
				
			||||||
 | 
					            return False
 | 
				
			||||||
 | 
					        return self.set(key, value, time, min_compress_len)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def incr(self, key, delta=1):
 | 
				
			||||||
 | 
					        """Increments the value for a key."""
 | 
				
			||||||
 | 
					        value = self.get(key)
 | 
				
			||||||
 | 
					        if value is None:
 | 
				
			||||||
 | 
					            return None
 | 
				
			||||||
 | 
					        new_value = int(value) + delta
 | 
				
			||||||
 | 
					        self.cache[key] = (self.cache[key][0], str(new_value))
 | 
				
			||||||
 | 
					        return new_value
 | 
				
			||||||
@@ -25,6 +25,10 @@ from carrot.backends import base
 | 
				
			|||||||
from eventlet import greenthread
 | 
					from eventlet import greenthread
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					EXCHANGES = {}
 | 
				
			||||||
 | 
					QUEUES = {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Message(base.BaseMessage):
 | 
					class Message(base.BaseMessage):
 | 
				
			||||||
    pass
 | 
					    pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -37,12 +41,12 @@ class Exchange(object):
 | 
				
			|||||||
        self._routes = {}
 | 
					        self._routes = {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def publish(self, message, routing_key=None):
 | 
					    def publish(self, message, routing_key=None):
 | 
				
			||||||
        logging.debug('(%s) publish (key: %s) %s',
 | 
					        logging.debug(_('(%s) publish (key: %s) %s'),
 | 
				
			||||||
                      self.name, routing_key, message)
 | 
					                      self.name, routing_key, message)
 | 
				
			||||||
        routing_key = routing_key.split('.')[0]
 | 
					        routing_key = routing_key.split('.')[0]
 | 
				
			||||||
        if routing_key in self._routes:
 | 
					        if routing_key in self._routes:
 | 
				
			||||||
            for f in self._routes[routing_key]:
 | 
					            for f in self._routes[routing_key]:
 | 
				
			||||||
                logging.debug('Publishing to route %s', f)
 | 
					                logging.debug(_('Publishing to route %s'), f)
 | 
				
			||||||
                f(message, routing_key=routing_key)
 | 
					                f(message, routing_key=routing_key)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def bind(self, callback, routing_key):
 | 
					    def bind(self, callback, routing_key):
 | 
				
			||||||
@@ -68,81 +72,63 @@ class Queue(object):
 | 
				
			|||||||
        return self._queue.get()
 | 
					        return self._queue.get()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Backend(object):
 | 
					class Backend(base.BaseBackend):
 | 
				
			||||||
    """ Singleton backend for testing """
 | 
					    def queue_declare(self, queue, **kwargs):
 | 
				
			||||||
    class __impl(base.BaseBackend):
 | 
					        global QUEUES
 | 
				
			||||||
        def __init__(self, *args, **kwargs):
 | 
					        if queue not in QUEUES:
 | 
				
			||||||
            #super(__impl, self).__init__(*args, **kwargs)
 | 
					            logging.debug(_('Declaring queue %s'), queue)
 | 
				
			||||||
            self._exchanges = {}
 | 
					            QUEUES[queue] = Queue(queue)
 | 
				
			||||||
            self._queues = {}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        def _reset_all(self):
 | 
					    def exchange_declare(self, exchange, type, *args, **kwargs):
 | 
				
			||||||
            self._exchanges = {}
 | 
					        global EXCHANGES
 | 
				
			||||||
            self._queues = {}
 | 
					        if exchange not in EXCHANGES:
 | 
				
			||||||
 | 
					            logging.debug(_('Declaring exchange %s'), exchange)
 | 
				
			||||||
 | 
					            EXCHANGES[exchange] = Exchange(exchange, type)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        def queue_declare(self, queue, **kwargs):
 | 
					    def queue_bind(self, queue, exchange, routing_key, **kwargs):
 | 
				
			||||||
            if queue not in self._queues:
 | 
					        global EXCHANGES
 | 
				
			||||||
                logging.debug('Declaring queue %s', queue)
 | 
					        global QUEUES
 | 
				
			||||||
                self._queues[queue] = Queue(queue)
 | 
					        logging.debug(_('Binding %s to %s with key %s'),
 | 
				
			||||||
 | 
					                      queue, exchange, routing_key)
 | 
				
			||||||
 | 
					        EXCHANGES[exchange].bind(QUEUES[queue].push, routing_key)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        def exchange_declare(self, exchange, type, *args, **kwargs):
 | 
					    def declare_consumer(self, queue, callback, *args, **kwargs):
 | 
				
			||||||
            if exchange not in self._exchanges:
 | 
					        self.current_queue = queue
 | 
				
			||||||
                logging.debug('Declaring exchange %s', exchange)
 | 
					        self.current_callback = callback
 | 
				
			||||||
                self._exchanges[exchange] = Exchange(exchange, type)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        def queue_bind(self, queue, exchange, routing_key, **kwargs):
 | 
					    def consume(self, limit=None):
 | 
				
			||||||
            logging.debug('Binding %s to %s with key %s',
 | 
					        while True:
 | 
				
			||||||
                          queue, exchange, routing_key)
 | 
					            item = self.get(self.current_queue)
 | 
				
			||||||
            self._exchanges[exchange].bind(self._queues[queue].push,
 | 
					            if item:
 | 
				
			||||||
                                           routing_key)
 | 
					                self.current_callback(item)
 | 
				
			||||||
 | 
					                raise StopIteration()
 | 
				
			||||||
 | 
					            greenthread.sleep(0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        def declare_consumer(self, queue, callback, *args, **kwargs):
 | 
					    def get(self, queue, no_ack=False):
 | 
				
			||||||
            self.current_queue = queue
 | 
					        global QUEUES
 | 
				
			||||||
            self.current_callback = callback
 | 
					        if not queue in QUEUES or not QUEUES[queue].size():
 | 
				
			||||||
 | 
					            return None
 | 
				
			||||||
 | 
					        (message_data, content_type, content_encoding) = QUEUES[queue].pop()
 | 
				
			||||||
 | 
					        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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        def consume(self, *args, **kwargs):
 | 
					    def prepare_message(self, message_data, delivery_mode,
 | 
				
			||||||
            while True:
 | 
					                        content_type, content_encoding, **kwargs):
 | 
				
			||||||
                item = self.get(self.current_queue)
 | 
					        """Prepare message for sending."""
 | 
				
			||||||
                if item:
 | 
					        return (message_data, content_type, content_encoding)
 | 
				
			||||||
                    self.current_callback(item)
 | 
					 | 
				
			||||||
                    raise StopIteration()
 | 
					 | 
				
			||||||
                greenthread.sleep(0)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        def get(self, queue, no_ack=False):
 | 
					    def publish(self, message, exchange, routing_key, **kwargs):
 | 
				
			||||||
            if not queue in self._queues or not self._queues[queue].size():
 | 
					        global EXCHANGES
 | 
				
			||||||
                return None
 | 
					        if exchange in EXCHANGES:
 | 
				
			||||||
            (message_data, content_type, content_encoding) = \
 | 
					            EXCHANGES[exchange].publish(message, routing_key=routing_key)
 | 
				
			||||||
                    self._queues[queue].pop()
 | 
					 | 
				
			||||||
            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
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        def prepare_message(self, message_data, delivery_mode,
 | 
					 | 
				
			||||||
                            content_type, content_encoding, **kwargs):
 | 
					 | 
				
			||||||
            """Prepare message for sending."""
 | 
					 | 
				
			||||||
            return (message_data, content_type, content_encoding)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        def publish(self, message, exchange, routing_key, **kwargs):
 | 
					 | 
				
			||||||
            if exchange in self._exchanges:
 | 
					 | 
				
			||||||
                self._exchanges[exchange].publish(
 | 
					 | 
				
			||||||
                        message, routing_key=routing_key)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    __instance = None
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def __init__(self, *args, **kwargs):
 | 
					 | 
				
			||||||
        if Backend.__instance is None:
 | 
					 | 
				
			||||||
            Backend.__instance = Backend.__impl(*args, **kwargs)
 | 
					 | 
				
			||||||
        self.__dict__['_Backend__instance'] = Backend.__instance
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def __getattr__(self, attr):
 | 
					 | 
				
			||||||
        return getattr(self.__instance, attr)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def __setattr__(self, attr, value):
 | 
					 | 
				
			||||||
        return setattr(self.__instance, attr, value)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def reset_all():
 | 
					def reset_all():
 | 
				
			||||||
    Backend()._reset_all()
 | 
					    global EXCHANGES
 | 
				
			||||||
 | 
					    global QUEUES
 | 
				
			||||||
 | 
					    EXCHANGES = {}
 | 
				
			||||||
 | 
					    QUEUES = {}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -29,6 +29,8 @@ import sys
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import gflags
 | 
					import gflags
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from nova import utils
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class FlagValues(gflags.FlagValues):
 | 
					class FlagValues(gflags.FlagValues):
 | 
				
			||||||
    """Extension of gflags.FlagValues that allows undefined and runtime flags.
 | 
					    """Extension of gflags.FlagValues that allows undefined and runtime flags.
 | 
				
			||||||
@@ -159,6 +161,7 @@ class StrWrapper(object):
 | 
				
			|||||||
                return str(val)
 | 
					                return str(val)
 | 
				
			||||||
        raise KeyError(name)
 | 
					        raise KeyError(name)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
FLAGS = FlagValues()
 | 
					FLAGS = FlagValues()
 | 
				
			||||||
gflags.FLAGS = FLAGS
 | 
					gflags.FLAGS = FLAGS
 | 
				
			||||||
gflags.DEFINE_flag(gflags.HelpFlag(), FLAGS)
 | 
					gflags.DEFINE_flag(gflags.HelpFlag(), FLAGS)
 | 
				
			||||||
@@ -183,6 +186,12 @@ DEFINE_list = _wrapper(gflags.DEFINE_list)
 | 
				
			|||||||
DEFINE_spaceseplist = _wrapper(gflags.DEFINE_spaceseplist)
 | 
					DEFINE_spaceseplist = _wrapper(gflags.DEFINE_spaceseplist)
 | 
				
			||||||
DEFINE_multistring = _wrapper(gflags.DEFINE_multistring)
 | 
					DEFINE_multistring = _wrapper(gflags.DEFINE_multistring)
 | 
				
			||||||
DEFINE_multi_int = _wrapper(gflags.DEFINE_multi_int)
 | 
					DEFINE_multi_int = _wrapper(gflags.DEFINE_multi_int)
 | 
				
			||||||
 | 
					DEFINE_flag = _wrapper(gflags.DEFINE_flag)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					HelpFlag = gflags.HelpFlag
 | 
				
			||||||
 | 
					HelpshortFlag = gflags.HelpshortFlag
 | 
				
			||||||
 | 
					HelpXMLFlag = gflags.HelpXMLFlag
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def DECLARE(name, module_string, flag_values=FLAGS):
 | 
					def DECLARE(name, module_string, flag_values=FLAGS):
 | 
				
			||||||
@@ -204,7 +213,8 @@ DEFINE_string('connection_type', 'libvirt', 'libvirt, xenapi or fake')
 | 
				
			|||||||
DEFINE_string('aws_access_key_id', 'admin', 'AWS Access ID')
 | 
					DEFINE_string('aws_access_key_id', 'admin', 'AWS Access ID')
 | 
				
			||||||
DEFINE_string('aws_secret_access_key', 'admin', 'AWS Access Key')
 | 
					DEFINE_string('aws_secret_access_key', 'admin', 'AWS Access Key')
 | 
				
			||||||
DEFINE_integer('s3_port', 3333, 's3 port')
 | 
					DEFINE_integer('s3_port', 3333, 's3 port')
 | 
				
			||||||
DEFINE_string('s3_host', '127.0.0.1', 's3 host')
 | 
					DEFINE_string('s3_host', utils.get_my_ip(), 's3 host (for infrastructure)')
 | 
				
			||||||
 | 
					DEFINE_string('s3_dmz', utils.get_my_ip(), 's3 dmz ip (for instances)')
 | 
				
			||||||
DEFINE_string('compute_topic', 'compute', 'the topic compute nodes listen on')
 | 
					DEFINE_string('compute_topic', 'compute', 'the topic compute nodes listen on')
 | 
				
			||||||
DEFINE_string('scheduler_topic', 'scheduler',
 | 
					DEFINE_string('scheduler_topic', 'scheduler',
 | 
				
			||||||
              'the topic scheduler nodes listen on')
 | 
					              'the topic scheduler nodes listen on')
 | 
				
			||||||
@@ -223,22 +233,24 @@ DEFINE_string('rabbit_virtual_host', '/', 'rabbit virtual host')
 | 
				
			|||||||
DEFINE_integer('rabbit_retry_interval', 10, 'rabbit connection retry interval')
 | 
					DEFINE_integer('rabbit_retry_interval', 10, 'rabbit connection retry interval')
 | 
				
			||||||
DEFINE_integer('rabbit_max_retries', 12, 'rabbit connection attempts')
 | 
					DEFINE_integer('rabbit_max_retries', 12, 'rabbit connection attempts')
 | 
				
			||||||
DEFINE_string('control_exchange', 'nova', 'the main exchange to connect to')
 | 
					DEFINE_string('control_exchange', 'nova', 'the main exchange to connect to')
 | 
				
			||||||
DEFINE_string('ec2_url', 'http://127.0.0.1:8773/services/Cloud',
 | 
					DEFINE_string('ec2_prefix', 'http', 'prefix for ec2')
 | 
				
			||||||
              'Url to ec2 api server')
 | 
					DEFINE_string('cc_host', utils.get_my_ip(), 'ip of api server')
 | 
				
			||||||
 | 
					DEFINE_string('cc_dmz', utils.get_my_ip(), 'internal ip of api server')
 | 
				
			||||||
 | 
					DEFINE_integer('cc_port', 8773, 'cloud controller port')
 | 
				
			||||||
 | 
					DEFINE_string('ec2_suffix', '/services/Cloud', 'suffix for ec2')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DEFINE_string('default_image', 'ami-11111',
 | 
					DEFINE_string('default_image', 'ami-11111',
 | 
				
			||||||
              'default image to use, testing only')
 | 
					              'default image to use, testing only')
 | 
				
			||||||
DEFINE_string('default_kernel', 'aki-11111',
 | 
					 | 
				
			||||||
              'default kernel to use, testing only')
 | 
					 | 
				
			||||||
DEFINE_string('default_ramdisk', 'ari-11111',
 | 
					 | 
				
			||||||
              'default ramdisk to use, testing only')
 | 
					 | 
				
			||||||
DEFINE_string('default_instance_type', 'm1.small',
 | 
					DEFINE_string('default_instance_type', 'm1.small',
 | 
				
			||||||
              'default instance type to use, testing only')
 | 
					              'default instance type to use, testing only')
 | 
				
			||||||
 | 
					DEFINE_string('null_kernel', 'nokernel',
 | 
				
			||||||
 | 
					              'kernel image that indicates not to use a kernel,'
 | 
				
			||||||
 | 
					              ' but to use a raw disk image instead')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DEFINE_string('vpn_image_id', 'ami-CLOUDPIPE', 'AMI for cloudpipe vpn server')
 | 
					DEFINE_string('vpn_image_id', 'ami-cloudpipe', 'AMI for cloudpipe vpn server')
 | 
				
			||||||
DEFINE_string('vpn_key_suffix',
 | 
					DEFINE_string('vpn_key_suffix',
 | 
				
			||||||
              '-key',
 | 
					              '-vpn',
 | 
				
			||||||
              'Suffix to add to project name for vpn key')
 | 
					              'Suffix to add to project name for vpn key and secgroups')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DEFINE_integer('auth_token_ttl', 3600, 'Seconds for auth tokens to linger')
 | 
					DEFINE_integer('auth_token_ttl', 3600, 'Seconds for auth tokens to linger')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -259,7 +271,7 @@ DEFINE_string('scheduler_manager', 'nova.scheduler.manager.SchedulerManager',
 | 
				
			|||||||
              'Manager for scheduler')
 | 
					              'Manager for scheduler')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# The service to use for image search and retrieval
 | 
					# The service to use for image search and retrieval
 | 
				
			||||||
DEFINE_string('image_service', 'nova.image.local.LocalImageService',
 | 
					DEFINE_string('image_service', 'nova.image.s3.S3ImageService',
 | 
				
			||||||
              'The service to use for retrieving and searching for images.')
 | 
					              'The service to use for retrieving and searching for images.')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DEFINE_string('host', socket.gethostname(),
 | 
					DEFINE_string('host', socket.gethostname(),
 | 
				
			||||||
 
 | 
				
			|||||||
										
											Binary file not shown.
										
									
								
							@@ -35,7 +35,6 @@ try :
 | 
				
			|||||||
    from nova import flags
 | 
					    from nova import flags
 | 
				
			||||||
    from nova import quota
 | 
					    from nova import quota
 | 
				
			||||||
    from nova import utils
 | 
					    from nova import utils
 | 
				
			||||||
    from nova import process
 | 
					 | 
				
			||||||
    from nova.auth import manager
 | 
					    from nova.auth import manager
 | 
				
			||||||
    from nova.cloudpipe import pipelib
 | 
					    from nova.cloudpipe import pipelib
 | 
				
			||||||
    from nova import rpc
 | 
					    from nova import rpc
 | 
				
			||||||
@@ -177,10 +176,11 @@ class LibvirtConnectionTestFunctions(unittest.TestCase):
 | 
				
			|||||||
    def test03(self):
 | 
					    def test03(self):
 | 
				
			||||||
        """03: Unexpected exception occurs on finding volume on DB. """
 | 
					        """03: Unexpected exception occurs on finding volume on DB. """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        utils.execute = Mock( side_effect=process.ProcessExecutionError('ERR') )
 | 
					        utils.execute = Mock( side_effect=exception.ProcessExecutionError('ERR') )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.assertRaises(process.ProcessExecutionError,
 | 
					        self.assertRaises(exception.ProcessExecutionError,
 | 
				
			||||||
                         self.manager.live_migration,
 | 
					                         self.manager._live_migration,
 | 
				
			||||||
 | 
					                         self.ctxt,
 | 
				
			||||||
                         self.instance1,
 | 
					                         self.instance1,
 | 
				
			||||||
                         'host2')
 | 
					                         'host2')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -195,6 +195,7 @@ class LibvirtConnectionTestFunctions(unittest.TestCase):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        self.assertRaises(TypeError,
 | 
					        self.assertRaises(TypeError,
 | 
				
			||||||
                         self.manager._post_live_migration,
 | 
					                         self.manager._post_live_migration,
 | 
				
			||||||
 | 
					                         self.ctxt,
 | 
				
			||||||
                         "dummy string",
 | 
					                         "dummy string",
 | 
				
			||||||
                         'host2')
 | 
					                         'host2')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -202,7 +203,7 @@ class LibvirtConnectionTestFunctions(unittest.TestCase):
 | 
				
			|||||||
        """05: db.instance_get_fixed_address return None"""
 | 
					        """05: db.instance_get_fixed_address return None"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        db.instance_get_fixed_address  = Mock( return_value=None )
 | 
					        db.instance_get_fixed_address  = Mock( return_value=None )
 | 
				
			||||||
        ret = self.manager._post_live_migration(self.instance1, 'host1')
 | 
					        ret = self.manager._post_live_migration(self.ctxt, self.instance1, 'host1')
 | 
				
			||||||
        c1 = (ret == None)
 | 
					        c1 = (ret == None)
 | 
				
			||||||
        c2 = (0 <= sys.stderr.buffer.find('fixed_ip is not found'))
 | 
					        c2 = (0 <= sys.stderr.buffer.find('fixed_ip is not found'))
 | 
				
			||||||
        self.assertEqual(c1 and c2, True)
 | 
					        self.assertEqual(c1 and c2, True)
 | 
				
			||||||
@@ -213,6 +214,7 @@ class LibvirtConnectionTestFunctions(unittest.TestCase):
 | 
				
			|||||||
        db.instance_get_fixed_address  = Mock( side_effect=exception.NotFound('ERR') )
 | 
					        db.instance_get_fixed_address  = Mock( side_effect=exception.NotFound('ERR') )
 | 
				
			||||||
        self.assertRaises(exception.NotFound,
 | 
					        self.assertRaises(exception.NotFound,
 | 
				
			||||||
                         self.manager._post_live_migration,
 | 
					                         self.manager._post_live_migration,
 | 
				
			||||||
 | 
					                         self.ctxt,
 | 
				
			||||||
                         self.instance1,
 | 
					                         self.instance1,
 | 
				
			||||||
                         'host2')
 | 
					                         'host2')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -222,6 +224,7 @@ class LibvirtConnectionTestFunctions(unittest.TestCase):
 | 
				
			|||||||
        db.instance_get_fixed_address  = Mock( side_effect=TypeError('ERR') )
 | 
					        db.instance_get_fixed_address  = Mock( side_effect=TypeError('ERR') )
 | 
				
			||||||
        self.assertRaises(TypeError,
 | 
					        self.assertRaises(TypeError,
 | 
				
			||||||
                         self.manager._post_live_migration,
 | 
					                         self.manager._post_live_migration,
 | 
				
			||||||
 | 
					                         self.ctxt,
 | 
				
			||||||
                         self.instance1,
 | 
					                         self.instance1,
 | 
				
			||||||
                         'host1')
 | 
					                         'host1')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -231,6 +234,7 @@ class LibvirtConnectionTestFunctions(unittest.TestCase):
 | 
				
			|||||||
        db.fixed_ip_update =  Mock( side_effect=exception.NotFound('ERR') )
 | 
					        db.fixed_ip_update =  Mock( side_effect=exception.NotFound('ERR') )
 | 
				
			||||||
        self.assertRaises(exception.NotFound,
 | 
					        self.assertRaises(exception.NotFound,
 | 
				
			||||||
                         self.manager._post_live_migration,
 | 
					                         self.manager._post_live_migration,
 | 
				
			||||||
 | 
					                         self.ctxt,
 | 
				
			||||||
                         self.instance1,
 | 
					                         self.instance1,
 | 
				
			||||||
                         'host1')
 | 
					                         'host1')
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
@@ -239,6 +243,7 @@ class LibvirtConnectionTestFunctions(unittest.TestCase):
 | 
				
			|||||||
        db.fixed_ip_update =  Mock( side_effect=exception.NotAuthorized('ERR') )
 | 
					        db.fixed_ip_update =  Mock( side_effect=exception.NotAuthorized('ERR') )
 | 
				
			||||||
        self.assertRaises(exception.NotAuthorized,
 | 
					        self.assertRaises(exception.NotAuthorized,
 | 
				
			||||||
                         self.manager._post_live_migration,
 | 
					                         self.manager._post_live_migration,
 | 
				
			||||||
 | 
					                         self.ctxt,
 | 
				
			||||||
                         self.instance1,
 | 
					                         self.instance1,
 | 
				
			||||||
                         'host1')
 | 
					                         'host1')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -247,6 +252,7 @@ class LibvirtConnectionTestFunctions(unittest.TestCase):
 | 
				
			|||||||
        db.fixed_ip_update =  Mock( side_effect=TypeError('ERR') )
 | 
					        db.fixed_ip_update =  Mock( side_effect=TypeError('ERR') )
 | 
				
			||||||
        self.assertRaises(TypeError,
 | 
					        self.assertRaises(TypeError,
 | 
				
			||||||
                         self.manager._post_live_migration,
 | 
					                         self.manager._post_live_migration,
 | 
				
			||||||
 | 
					                         self.ctxt,
 | 
				
			||||||
                         self.instance1,
 | 
					                         self.instance1,
 | 
				
			||||||
                         'host1')
 | 
					                         'host1')
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
@@ -256,6 +262,7 @@ class LibvirtConnectionTestFunctions(unittest.TestCase):
 | 
				
			|||||||
        db.fixed_ip_get_network =  Mock( side_effect=exception.NotFound('ERR') )
 | 
					        db.fixed_ip_get_network =  Mock( side_effect=exception.NotFound('ERR') )
 | 
				
			||||||
        self.assertRaises(exception.NotFound,
 | 
					        self.assertRaises(exception.NotFound,
 | 
				
			||||||
                         self.manager._post_live_migration,
 | 
					                         self.manager._post_live_migration,
 | 
				
			||||||
 | 
					                         self.ctxt,
 | 
				
			||||||
                         self.instance1,
 | 
					                         self.instance1,
 | 
				
			||||||
                         'host1')
 | 
					                         'host1')
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
@@ -268,6 +275,7 @@ class LibvirtConnectionTestFunctions(unittest.TestCase):
 | 
				
			|||||||
        db.fixed_ip_get_network =  Mock( side_effect=TypeError('ERR') )
 | 
					        db.fixed_ip_get_network =  Mock( side_effect=TypeError('ERR') )
 | 
				
			||||||
        self.assertRaises(TypeError,
 | 
					        self.assertRaises(TypeError,
 | 
				
			||||||
                         self.manager._post_live_migration,
 | 
					                         self.manager._post_live_migration,
 | 
				
			||||||
 | 
					                         self.ctxt,
 | 
				
			||||||
                         self.instance1,
 | 
					                         self.instance1,
 | 
				
			||||||
                         'host1')
 | 
					                         'host1')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -276,13 +284,14 @@ class LibvirtConnectionTestFunctions(unittest.TestCase):
 | 
				
			|||||||
        db.network_update =  Mock( side_effect=TypeError('ERR') )
 | 
					        db.network_update =  Mock( side_effect=TypeError('ERR') )
 | 
				
			||||||
        self.assertRaises(TypeError,
 | 
					        self.assertRaises(TypeError,
 | 
				
			||||||
                         self.manager._post_live_migration,
 | 
					                         self.manager._post_live_migration,
 | 
				
			||||||
 | 
					                         self.ctxt,
 | 
				
			||||||
                         self.instance1,
 | 
					                         self.instance1,
 | 
				
			||||||
                         'host1')
 | 
					                         'host1')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test14(self):
 | 
					    def test14(self):
 | 
				
			||||||
        """14: db.instance_get_floating_address raises NotFound. """
 | 
					        """14: db.instance_get_floating_address raises NotFound. """
 | 
				
			||||||
        db.instance_get_floating_address = Mock(side_effect=exception.NotFound("ERR"))
 | 
					        db.instance_get_floating_address = Mock(side_effect=exception.NotFound("ERR"))
 | 
				
			||||||
        ret = self.manager._post_live_migration(self.instance1, 'host1')
 | 
					        ret = self.manager._post_live_migration(self.ctxt, self.instance1, 'host1')
 | 
				
			||||||
        c1 = (ret == None)
 | 
					        c1 = (ret == None)
 | 
				
			||||||
        c2 = (0 <= sys.stderr.buffer.find('doesnt have floating_ip'))
 | 
					        c2 = (0 <= sys.stderr.buffer.find('doesnt have floating_ip'))
 | 
				
			||||||
        self.assertEqual(c1 and c2, True)
 | 
					        self.assertEqual(c1 and c2, True)
 | 
				
			||||||
@@ -292,7 +301,7 @@ class LibvirtConnectionTestFunctions(unittest.TestCase):
 | 
				
			|||||||
        """15: db.instance_get_floating_address returns None. """
 | 
					        """15: db.instance_get_floating_address returns None. """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        db.instance_get_floating_address = Mock( return_value=None )
 | 
					        db.instance_get_floating_address = Mock( return_value=None )
 | 
				
			||||||
        ret = self.manager._post_live_migration(self.instance1, 'host1')
 | 
					        ret = self.manager._post_live_migration(self.ctxt, self.instance1, 'host1')
 | 
				
			||||||
        c1 = (ret == None)
 | 
					        c1 = (ret == None)
 | 
				
			||||||
        c2 = (0 <= sys.stderr.buffer.find('floating_ip is not found'))
 | 
					        c2 = (0 <= sys.stderr.buffer.find('floating_ip is not found'))
 | 
				
			||||||
        self.assertEqual(c1 and c2, True)
 | 
					        self.assertEqual(c1 and c2, True)
 | 
				
			||||||
@@ -301,7 +310,7 @@ class LibvirtConnectionTestFunctions(unittest.TestCase):
 | 
				
			|||||||
        """16:  db.instance_get_floating_address raises NotFound. """
 | 
					        """16:  db.instance_get_floating_address raises NotFound. """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        db.instance_get_floating_address = Mock(side_effect=exception.NotFound("ERR"))
 | 
					        db.instance_get_floating_address = Mock(side_effect=exception.NotFound("ERR"))
 | 
				
			||||||
        ret = self.manager._post_live_migration(self.instance1, 'host1')
 | 
					        ret = self.manager._post_live_migration(self.ctxt, self.instance1, 'host1')
 | 
				
			||||||
        c1 = (ret == None)
 | 
					        c1 = (ret == None)
 | 
				
			||||||
        c2 = (0 <= sys.stderr.buffer.find('doesnt have floating_ip'))
 | 
					        c2 = (0 <= sys.stderr.buffer.find('doesnt have floating_ip'))
 | 
				
			||||||
        self.assertEqual(c1 and c2, True)
 | 
					        self.assertEqual(c1 and c2, True)
 | 
				
			||||||
@@ -309,7 +318,7 @@ class LibvirtConnectionTestFunctions(unittest.TestCase):
 | 
				
			|||||||
    def test17(self):
 | 
					    def test17(self):
 | 
				
			||||||
        """17:  db.instance_get_floating_address raises Unknown exception. """
 | 
					        """17:  db.instance_get_floating_address raises Unknown exception. """
 | 
				
			||||||
        db.instance_get_floating_address = Mock(side_effect=TypeError("ERR"))
 | 
					        db.instance_get_floating_address = Mock(side_effect=TypeError("ERR"))
 | 
				
			||||||
        ret = self.manager._post_live_migration(self.instance1, 'host1')
 | 
					        ret = self.manager._post_live_migration(self.ctxt, self.instance1, 'host1')
 | 
				
			||||||
        c1 = (ret == None)
 | 
					        c1 = (ret == None)
 | 
				
			||||||
        c2 = (0 <= sys.stderr.buffer.find('Live migration: Unexpected error'))
 | 
					        c2 = (0 <= sys.stderr.buffer.find('Live migration: Unexpected error'))
 | 
				
			||||||
        self.assertEqual(c1 and c2, True)
 | 
					        self.assertEqual(c1 and c2, True)
 | 
				
			||||||
@@ -319,7 +328,7 @@ class LibvirtConnectionTestFunctions(unittest.TestCase):
 | 
				
			|||||||
        """18: db.floating_ip_get_by_address raises NotFound """
 | 
					        """18: db.floating_ip_get_by_address raises NotFound """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        db.floating_ip_get_by_address = Mock(side_effect=exception.NotFound("ERR"))
 | 
					        db.floating_ip_get_by_address = Mock(side_effect=exception.NotFound("ERR"))
 | 
				
			||||||
        ret = self.manager._post_live_migration(self.instance1, 'host1')
 | 
					        ret = self.manager._post_live_migration(self.ctxt, self.instance1, 'host1')
 | 
				
			||||||
        c1 = (ret == None)
 | 
					        c1 = (ret == None)
 | 
				
			||||||
        c2 = (0 <= sys.stderr.buffer.find('doesnt have floating_ip'))
 | 
					        c2 = (0 <= sys.stderr.buffer.find('doesnt have floating_ip'))
 | 
				
			||||||
        self.assertEqual(c1 and c2, True)
 | 
					        self.assertEqual(c1 and c2, True)
 | 
				
			||||||
@@ -327,7 +336,7 @@ class LibvirtConnectionTestFunctions(unittest.TestCase):
 | 
				
			|||||||
    def test19(self):
 | 
					    def test19(self):
 | 
				
			||||||
        """19:  db.floating_ip_get_by_address raises Unknown exception. """
 | 
					        """19:  db.floating_ip_get_by_address raises Unknown exception. """
 | 
				
			||||||
        db.floating_ip_get_by_address = Mock(side_effect=TypeError("ERR"))
 | 
					        db.floating_ip_get_by_address = Mock(side_effect=TypeError("ERR"))
 | 
				
			||||||
        ret = self.manager._post_live_migration(self.instance1, 'host1')
 | 
					        ret = self.manager._post_live_migration(self.ctxt, self.instance1, 'host1')
 | 
				
			||||||
        c1 = (ret == None)
 | 
					        c1 = (ret == None)
 | 
				
			||||||
        c2 = (0 <= sys.stderr.buffer.find('Live migration: Unexpected error'))
 | 
					        c2 = (0 <= sys.stderr.buffer.find('Live migration: Unexpected error'))
 | 
				
			||||||
        self.assertEqual(c1 and c2, True)
 | 
					        self.assertEqual(c1 and c2, True)
 | 
				
			||||||
@@ -337,7 +346,7 @@ class LibvirtConnectionTestFunctions(unittest.TestCase):
 | 
				
			|||||||
        """20: db.floating_ip_update raises Unknown exception. 
 | 
					        """20: db.floating_ip_update raises Unknown exception. 
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        db.floating_ip_update = Mock(side_effect=TypeError("ERR"))
 | 
					        db.floating_ip_update = Mock(side_effect=TypeError("ERR"))
 | 
				
			||||||
        ret = self.manager._post_live_migration(self.instance1, 'host1')
 | 
					        ret = self.manager._post_live_migration(self.ctxt, self.instance1, 'host1')
 | 
				
			||||||
        c1 = (ret == None)
 | 
					        c1 = (ret == None)
 | 
				
			||||||
        c2 = (0 <= sys.stderr.buffer.find('Live migration: Unexpected error'))
 | 
					        c2 = (0 <= sys.stderr.buffer.find('Live migration: Unexpected error'))
 | 
				
			||||||
        self.assertEqual(c1 and c2, True)
 | 
					        self.assertEqual(c1 and c2, True)
 | 
				
			||||||
@@ -348,6 +357,7 @@ class LibvirtConnectionTestFunctions(unittest.TestCase):
 | 
				
			|||||||
        db.instance_update = Mock(side_effect=TypeError("ERR"))
 | 
					        db.instance_update = Mock(side_effect=TypeError("ERR"))
 | 
				
			||||||
        self.assertRaises(TypeError,
 | 
					        self.assertRaises(TypeError,
 | 
				
			||||||
                         self.manager._post_live_migration,
 | 
					                         self.manager._post_live_migration,
 | 
				
			||||||
 | 
					                         self.ctxt,
 | 
				
			||||||
                         self.instance1,
 | 
					                         self.instance1,
 | 
				
			||||||
                         'host1')
 | 
					                         'host1')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -256,73 +256,35 @@ class NovaManageTestFunctions(unittest.TestCase):
 | 
				
			|||||||
        self.assertRaises(TypeError, self.instanceCmds.live_migration, 'i-xxx' )
 | 
					        self.assertRaises(TypeError, self.instanceCmds.live_migration, 'i-xxx' )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test11(self):
 | 
					    def test11(self):
 | 
				
			||||||
        """11: nova-manage instances live_migration ec2_id host, 
 | 
					        """11: nova-manage instances live_migration ec2_id(invalid id) host"""
 | 
				
			||||||
           where hostname is invalid
 | 
					
 | 
				
			||||||
        """
 | 
					        db.instance_get_by_internal_id = Mock( side_effect=exception.NotFound('ERR') )
 | 
				
			||||||
        db.host_get_by_name = Mock( side_effect=exception.NotFound('ERR') )
 | 
					        try : 
 | 
				
			||||||
        self.assertRaises(exception.NotFound, self.instanceCmds.live_migration, 'i-xxx', 'host1' )
 | 
					            self.instanceCmds.live_migration('i-xxx', 'host1')
 | 
				
			||||||
 | 
					        except exception.NotFound, e: 
 | 
				
			||||||
 | 
					            c1 = (0 < str(e.args).find('is not found') )
 | 
				
			||||||
 | 
					            self.assertTrue(c1, True)
 | 
				
			||||||
 | 
					        return False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test12(self):
 | 
					    def test12(self):
 | 
				
			||||||
        """12: nova-manage instances live_migration ec2_id(invalid id) host"""
 | 
					        """12: nova-manage instances live_migration ec2_id host
 | 
				
			||||||
 | 
					           and db.instance_get_by_internal_id raises unexpected exceptioin.
 | 
				
			||||||
        db.host_get_by_name = Mock(return_value = self.host1)
 | 
					        """
 | 
				
			||||||
        db.instance_get_by_internal_id = Mock( side_effect=exception.NotFound('ERR') )
 | 
					        db.instance_get_by_internal_id = Mock( side_effect=TypeError('ERR') )
 | 
				
			||||||
 | 
					        self.assertRaises(TypeError, self.instanceCmds.live_migration, 'i-xxx' )
 | 
				
			||||||
        self.assertRaises(exception.NotFound, self.instanceCmds.live_migration, 'i-xxx', 'host1' )
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test13(self):
 | 
					    def test13(self):
 | 
				
			||||||
        """13: nova-manage instances live_migration ec2_id host, 
 | 
					        """13: nova-manage instances live_migration ec2_id host, 
 | 
				
			||||||
           but instance specifed by ec2 id is not running (state is not power_state.RUNNING)
 | 
					 | 
				
			||||||
        """
 | 
					 | 
				
			||||||
        db.host_get_by_name = Mock(return_value = self.host1)
 | 
					 | 
				
			||||||
        db.instance_get_by_internal_id = Mock( return_value = self.instance1 )
 | 
					 | 
				
			||||||
        try : 
 | 
					 | 
				
			||||||
            self.instanceCmds.live_migration('i-12345', 'host1')
 | 
					 | 
				
			||||||
        except exception.Invalid, e: 
 | 
					 | 
				
			||||||
            c1 = (0 < e.message.find('is not running') )
 | 
					 | 
				
			||||||
            self.assertTrue(c1, True)
 | 
					 | 
				
			||||||
        return False
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def test14(self):
 | 
					 | 
				
			||||||
        """14: nova-manage instances live_migration ec2_id host, 
 | 
					 | 
				
			||||||
           but instance specifed by ec2 id is not running (state_description is not running)
 | 
					 | 
				
			||||||
        """
 | 
					 | 
				
			||||||
        db.host_get_by_name = Mock(return_value = self.host2)
 | 
					 | 
				
			||||||
        db.instance_get_by_internal_id = Mock( return_value = self.instance1 )
 | 
					 | 
				
			||||||
        try : 
 | 
					 | 
				
			||||||
            self.instanceCmds.live_migration('i-12345', 'host2')
 | 
					 | 
				
			||||||
        except exception.Invalid, e: 
 | 
					 | 
				
			||||||
            c1 = (0 < e.message.find('is not running') )
 | 
					 | 
				
			||||||
            self.assertTrue(c1, True)
 | 
					 | 
				
			||||||
        return False
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def test15(self):
 | 
					 | 
				
			||||||
        """15: nova-manage instances live_migration ec2_id host, 
 | 
					 | 
				
			||||||
           but instance is running at the same host specifed above, so err should be occured.
 | 
					 | 
				
			||||||
        """
 | 
					 | 
				
			||||||
        db.host_get_by_name = Mock(return_value = self.host1)
 | 
					 | 
				
			||||||
        db.instance_get_by_internal_id = Mock( return_value = self.instance3 )
 | 
					 | 
				
			||||||
        try : 
 | 
					 | 
				
			||||||
            self.instanceCmds.live_migration('i-12345', 'host1')
 | 
					 | 
				
			||||||
        except exception.Invalid, e: 
 | 
					 | 
				
			||||||
            c1 = ( 0 <= e.message.find('is running now') )
 | 
					 | 
				
			||||||
            self.assertTrue(c1, True)
 | 
					 | 
				
			||||||
        return False
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def test16(self):
 | 
					 | 
				
			||||||
        """16: nova-manage instances live_migration ec2_id host, 
 | 
					 | 
				
			||||||
           rpc.call raises RemoteError because destination doesnt have enough resource.
 | 
					           rpc.call raises RemoteError because destination doesnt have enough resource.
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        db.host_get_by_name = Mock(return_value = self.host1)
 | 
					        db.host_get_by_name = Mock(return_value = self.host1)
 | 
				
			||||||
        db.instance_get_by_internal_id = Mock( return_value = self.instance3 )
 | 
					        db.instance_get_by_internal_id = Mock( return_value = self.instance3 )
 | 
				
			||||||
        rpc.call = Mock(return_value = rpc.RemoteError(TypeError, 'val', 'traceback'))
 | 
					        rpc.call = Mock(return_value = rpc.RemoteError(TypeError, 'val', 'traceback'))
 | 
				
			||||||
        self.assertRaises(rpc.RemoteError, self.instanceCmds.live_migration, 'i-xxx', 'host2' )
 | 
					        self.assertRaises(rpc.RemoteError, self.instanceCmds.live_migration, 'i-xxx', 'host2' )
 | 
				
			||||||
        
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test17(self):
 | 
					
 | 
				
			||||||
        """17: nova-manage instances live_migration ec2_id host, 
 | 
					    def test14(self):
 | 
				
			||||||
 | 
					        """14: nova-manage instances live_migration ec2_id host, 
 | 
				
			||||||
           everything goes well, ang gets success messages.
 | 
					           everything goes well, ang gets success messages.
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        db.host_get_by_name = Mock(return_value = self.host1)
 | 
					        db.host_get_by_name = Mock(return_value = self.host1)
 | 
				
			||||||
@@ -332,7 +294,7 @@ class NovaManageTestFunctions(unittest.TestCase):
 | 
				
			|||||||
        self.instanceCmds.live_migration('i-12345', 'host2')
 | 
					        self.instanceCmds.live_migration('i-12345', 'host2')
 | 
				
			||||||
        c1 = (0 <= self.stdout.buffer.find('Finished all procedure') )
 | 
					        c1 = (0 <= self.stdout.buffer.find('Finished all procedure') )
 | 
				
			||||||
        self.assertEqual( c1, True )
 | 
					        self.assertEqual( c1, True )
 | 
				
			||||||
        
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def tearDown(self):
 | 
					    def tearDown(self):
 | 
				
			||||||
        """common terminating method. """
 | 
					        """common terminating method. """
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -55,12 +55,15 @@ class tmpStdout:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
class SchedulerTestFunctions(unittest.TestCase):
 | 
					class SchedulerTestFunctions(unittest.TestCase):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    manager = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # 共通の初期化処理
 | 
					    # 共通の初期化処理
 | 
				
			||||||
    def setUp(self):
 | 
					    def setUp(self):
 | 
				
			||||||
        """common init method. """
 | 
					        """common init method. """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.host = 'openstack2-api'
 | 
					        self.host = 'openstack2-api'
 | 
				
			||||||
        self.manager = SchedulerManager(host=self.host)
 | 
					        if self.manager is None: 
 | 
				
			||||||
 | 
					            self.manager = SchedulerManager(host=self.host)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.setTestData()
 | 
					        self.setTestData()
 | 
				
			||||||
        self.setMocks()
 | 
					        self.setMocks()
 | 
				
			||||||
@@ -72,6 +75,7 @@ class SchedulerTestFunctions(unittest.TestCase):
 | 
				
			|||||||
        self.host1.__setitem__('vcpus', 5)
 | 
					        self.host1.__setitem__('vcpus', 5)
 | 
				
			||||||
        self.host1.__setitem__('memory_mb', 20480)
 | 
					        self.host1.__setitem__('memory_mb', 20480)
 | 
				
			||||||
        self.host1.__setitem__('local_gb', 876)
 | 
					        self.host1.__setitem__('local_gb', 876)
 | 
				
			||||||
 | 
					        self.host1.__setitem__('cpu_info', 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.host2 = Host()
 | 
					        self.host2 = Host()
 | 
				
			||||||
        self.host2.__setitem__('name', 'host2')
 | 
					        self.host2.__setitem__('name', 'host2')
 | 
				
			||||||
@@ -86,37 +90,43 @@ class SchedulerTestFunctions(unittest.TestCase):
 | 
				
			|||||||
        self.instance1 = Instance()
 | 
					        self.instance1 = Instance()
 | 
				
			||||||
        for key, val in [ ('id', 1), ('host', 'host1'),   ('hostname', 'i-12345'), 
 | 
					        for key, val in [ ('id', 1), ('host', 'host1'),   ('hostname', 'i-12345'), 
 | 
				
			||||||
                          ('state', power_state.RUNNING), ('project_id', 'testPJ'),
 | 
					                          ('state', power_state.RUNNING), ('project_id', 'testPJ'),
 | 
				
			||||||
                          ('vcpus', 3), ('memory_mb', 1024), ('hdd_gb', 5) ]:
 | 
					                          ('vcpus', 3), ('memory_mb', 1024), ('local_gb', 5) ]:
 | 
				
			||||||
            self.instance1.__setitem__(key, val)
 | 
					            self.instance1.__setitem__(key, val)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.instance2 = Instance()
 | 
					        self.instance2 = Instance()
 | 
				
			||||||
        for key, val in [ ('id', 2), ('host', 'host1'),   ('hostname', 'i-12345'), 
 | 
					        for key, val in [ ('id', 2), ('host', 'host1'),   ('hostname', 'i-12345'), 
 | 
				
			||||||
                          ('state', power_state.RUNNING), ('project_id', 'testPJ'),
 | 
					                          ('state', power_state.RUNNING), ('project_id', 'testPJ'),
 | 
				
			||||||
                          ('vcpus', 3), ('memory_mb', 1024), ('hdd_gb', 5) ]:
 | 
					                          ('vcpus', 3), ('memory_mb', 1024), ('local_gb', 5) ]:
 | 
				
			||||||
            self.instance2.__setitem__(key, val)
 | 
					            self.instance2.__setitem__(key, val)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.instance3 = Instance()
 | 
					        self.instance3 = Instance()
 | 
				
			||||||
        for key, val in [ ('id', 3), ('host', 'host1'),   ('hostname', 'i-12345'), 
 | 
					        for key, val in [ ('id', 3), ('host', 'host1'),   ('hostname', 'i-12345'), 
 | 
				
			||||||
                          ('state', power_state.RUNNING), ('project_id', 'testPJ2'),
 | 
					                          ('state', power_state.RUNNING), ('project_id', 'testPJ2'),
 | 
				
			||||||
                          ('vcpus', 1), ('memory_mb', 1024), ('hdd_gb', 5) ]:
 | 
					                          ('vcpus', 1), ('memory_mb', 1024), ('local_gb', 5),
 | 
				
			||||||
 | 
					                          ('internal_id', 123456), ('state', 1), 
 | 
				
			||||||
 | 
					                          ('state_description', 'running') ]:
 | 
				
			||||||
            self.instance3.__setitem__(key, val)
 | 
					            self.instance3.__setitem__(key, val)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.instance4 = Instance()
 | 
					        self.instance4 = Instance()
 | 
				
			||||||
        for key, val in [ ('id', 4), ('host', 'host2'),   ('hostname', 'i-12345'), 
 | 
					        for key, val in [ ('id', 4), ('host', 'host2'),   ('hostname', 'i-12345'), 
 | 
				
			||||||
                          ('state', power_state.RUNNING), ('project_id', 'testPJ2'),
 | 
					                          ('state', power_state.RUNNING), ('project_id', 'testPJ2'),
 | 
				
			||||||
                          ('vcpus', 1), ('memory_mb', 1024), ('local_gb', 5) ]:
 | 
					                          ('vcpus', 1), ('memory_mb', 1024), ('local_gb', 5),
 | 
				
			||||||
 | 
					                          ('internal_id', 123456), ('state', 0),
 | 
				
			||||||
 | 
					                          ('state_description', 'running') ]:
 | 
				
			||||||
            self.instance4.__setitem__(key, val)
 | 
					            self.instance4.__setitem__(key, val)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.instance5 = Instance()
 | 
					        self.instance5 = Instance()
 | 
				
			||||||
        for key, val in [ ('id', 5), ('host', 'host2'),   ('hostname', 'i-12345'), 
 | 
					        for key, val in [ ('id', 5), ('host', 'host2'),   ('hostname', 'i-12345'), 
 | 
				
			||||||
                          ('state', power_state.RUNNING), ('project_id', 'testPJ2'),
 | 
					                          ('state', power_state.RUNNING), ('project_id', 'testPJ2'),
 | 
				
			||||||
                          ('vcpus', 1), ('memory_mb', 1024), ('local_gb', 5) ]:
 | 
					                          ('vcpus', 1), ('memory_mb', 1024), ('local_gb', 5),
 | 
				
			||||||
 | 
					                          ('internal_id', 123456), ('state', 1),
 | 
				
			||||||
 | 
					                          ('state_description', 'migrating') ]:
 | 
				
			||||||
            self.instance5.__setitem__(key, val)
 | 
					            self.instance5.__setitem__(key, val)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.instance6 = Instance()
 | 
					        self.instance6 = Instance()
 | 
				
			||||||
        for key, val in [ ('id', 6), ('host', 'host1'),   ('hostname', 'i-12345'), 
 | 
					        for key, val in [ ('id', 6), ('host', 'host2'),   ('hostname', 'i-12345'), 
 | 
				
			||||||
                          ('state', power_state.RUNNING), ('project_id', 'testPJ2'),
 | 
					                          ('state', power_state.RUNNING), ('project_id', 'testPJ2'),
 | 
				
			||||||
                          ('vcpus', 3), ('memory_mb', 1024), ('local_gb', 5) ]:
 | 
					                          ('vcpus', 3), ('memory_mb', 1024), ('local_gb', 5) ]:
 | 
				
			||||||
            self.instance6.__setitem__(key, val)
 | 
					            self.instance6.__setitem__(key, val)
 | 
				
			||||||
@@ -129,7 +139,8 @@ class SchedulerTestFunctions(unittest.TestCase):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        self.instance8 = Instance()
 | 
					        self.instance8 = Instance()
 | 
				
			||||||
        for key, val in [ ('id', 8), ('host', 'host1'),   ('hostname', 'i-12345'), 
 | 
					        for key, val in [ ('id', 8), ('host', 'host1'),   ('hostname', 'i-12345'), 
 | 
				
			||||||
                          ('state', power_state.RUNNING), ('project_id', 'testPJ2'),
 | 
					                          ('state', power_state.RUNNING), 
 | 
				
			||||||
 | 
					                          ('state_description', 'running'),('project_id', 'testPJ2'),
 | 
				
			||||||
                          ('vcpus', 1), ('memory_mb', 1024), ('local_gb', 866) ]:
 | 
					                          ('vcpus', 1), ('memory_mb', 1024), ('local_gb', 866) ]:
 | 
				
			||||||
            self.instance8.__setitem__(key, val)
 | 
					            self.instance8.__setitem__(key, val)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -138,6 +149,10 @@ class SchedulerTestFunctions(unittest.TestCase):
 | 
				
			|||||||
                          ('topic', 'compute')]:
 | 
					                          ('topic', 'compute')]:
 | 
				
			||||||
            self.service1.__setitem__(key, val)
 | 
					            self.service1.__setitem__(key, val)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.service2 = Service()
 | 
				
			||||||
 | 
					        for key, val in [ ('id', 2), ('host', 'host2'),  ('binary', 'nova-compute'), 
 | 
				
			||||||
 | 
					                          ('topic', 'compute')]:
 | 
				
			||||||
 | 
					            self.service1.__setitem__(key, val)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def setMocks(self): 
 | 
					    def setMocks(self): 
 | 
				
			||||||
        self.ctxt = context.get_admin_context()
 | 
					        self.ctxt = context.get_admin_context()
 | 
				
			||||||
@@ -147,10 +162,11 @@ class SchedulerTestFunctions(unittest.TestCase):
 | 
				
			|||||||
        db.instance_get_all_by_host = Mock(return_value = [self.instance4, self.instance5] )
 | 
					        db.instance_get_all_by_host = Mock(return_value = [self.instance4, self.instance5] )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Mocks for live_migration
 | 
					        # Mocks for live_migration
 | 
				
			||||||
        db.instance_get_by_internal_id = Mock(return_value = self.instance1)
 | 
					 | 
				
			||||||
        # db.host_get_by_name <- defined above.
 | 
					 | 
				
			||||||
        db.service_get_all_by_topic = Mock(return_value = [self.service1] )
 | 
					        db.service_get_all_by_topic = Mock(return_value = [self.service1] )
 | 
				
			||||||
 | 
					        self.manager.service_ip_up = Mock(return_value = True)
 | 
				
			||||||
        rpc.call = Mock(return_value=1)
 | 
					        rpc.call = Mock(return_value=1)
 | 
				
			||||||
 | 
					        db.instance_set_state = Mock(return_value = True)
 | 
				
			||||||
 | 
					        self.manager.driver.service_is_up = Mock(return_value = True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def check_format(self, val): 
 | 
					    def check_format(self, val): 
 | 
				
			||||||
        """check result format of show_host_resource """
 | 
					        """check result format of show_host_resource """
 | 
				
			||||||
@@ -259,9 +275,12 @@ class SchedulerTestFunctions(unittest.TestCase):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        db.instance_get = Mock(return_value = self.instance6)
 | 
					        db.instance_get = Mock(return_value = self.instance6)
 | 
				
			||||||
        try :
 | 
					        try :
 | 
				
			||||||
            self.manager.has_enough_resource(self.ctxt, 'i-12345', 'host1') 
 | 
					            self.manager.driver.has_enough_resource(self.ctxt, 'i-12345', 'host1') 
 | 
				
			||||||
        except exception.NotEmpty, e:
 | 
					        except exception.NotEmpty, e:
 | 
				
			||||||
            c1 = ( 0 < e.message.find('doesnt have enough resource') )
 | 
					            # dont do e.message.find(), because the below message is occured.
 | 
				
			||||||
 | 
					            # DeprecationWarning: BaseException.message has been deprecated 
 | 
				
			||||||
 | 
					            # as of Python 2.6
 | 
				
			||||||
 | 
					            c1 = ( 0 < str(e.args).find('doesnt have enough resource') )
 | 
				
			||||||
            self.assertTrue(c1, True)
 | 
					            self.assertTrue(c1, True)
 | 
				
			||||||
        return False
 | 
					        return False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -271,9 +290,9 @@ class SchedulerTestFunctions(unittest.TestCase):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        db.instance_get = Mock(return_value = self.instance7)
 | 
					        db.instance_get = Mock(return_value = self.instance7)
 | 
				
			||||||
        try :
 | 
					        try :
 | 
				
			||||||
            self.manager.has_enough_resource(self.ctxt, 'i-12345', 'host1') 
 | 
					            self.manager.driver.has_enough_resource(self.ctxt, 'i-12345', 'host1') 
 | 
				
			||||||
        except exception.NotEmpty, e:
 | 
					        except exception.NotEmpty, e:
 | 
				
			||||||
            c1 = ( 0 <= e.message.find('doesnt have enough resource') )
 | 
					            c1 = ( 0 <= str(e.args).find('doesnt have enough resource') )
 | 
				
			||||||
            self.assertTrue(c1, True)
 | 
					            self.assertTrue(c1, True)
 | 
				
			||||||
        return False
 | 
					        return False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -282,9 +301,9 @@ class SchedulerTestFunctions(unittest.TestCase):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        db.instance_get = Mock(return_value = self.instance8)
 | 
					        db.instance_get = Mock(return_value = self.instance8)
 | 
				
			||||||
        try :
 | 
					        try :
 | 
				
			||||||
            self.manager.has_enough_resource(self.ctxt, 'i-12345', 'host1') 
 | 
					            self.manager.driver.has_enough_resource(self.ctxt, 'i-12345', 'host1') 
 | 
				
			||||||
        except exception.NotEmpty, e:
 | 
					        except exception.NotEmpty, e:
 | 
				
			||||||
            c1 = ( 0 <= e.message.find('doesnt have enough resource') )
 | 
					            c1 = ( 0 <= str(e.args).find('doesnt have enough resource') )
 | 
				
			||||||
            self.assertTrue(c1, True)
 | 
					            self.assertTrue(c1, True)
 | 
				
			||||||
        return False
 | 
					        return False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -292,7 +311,7 @@ class SchedulerTestFunctions(unittest.TestCase):
 | 
				
			|||||||
    def test08(self):
 | 
					    def test08(self):
 | 
				
			||||||
        """08: everything goes well. (instance_get_all_by_host returns list)"""
 | 
					        """08: everything goes well. (instance_get_all_by_host returns list)"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        ret= self.manager.has_enough_resource(self.ctxt, 'i-12345', 'host1') 
 | 
					        ret= self.manager.driver.has_enough_resource(self.ctxt, 'i-12345', 'host1') 
 | 
				
			||||||
        self.assertEqual(ret, None)
 | 
					        self.assertEqual(ret, None)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -300,7 +319,7 @@ class SchedulerTestFunctions(unittest.TestCase):
 | 
				
			|||||||
        """09: everything goes well(instance_get_all_by_host returns[]). """
 | 
					        """09: everything goes well(instance_get_all_by_host returns[]). """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        db.instance_get_all_by_host = Mock(return_value = [] )
 | 
					        db.instance_get_all_by_host = Mock(return_value = [] )
 | 
				
			||||||
        ret= self.manager.has_enough_resource(self.ctxt, 'i-12345', 'host1') 
 | 
					        ret= self.manager.driver.has_enough_resource(self.ctxt, 'i-12345', 'host1') 
 | 
				
			||||||
        self.assertEqual(ret, None)
 | 
					        self.assertEqual(ret, None)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -308,91 +327,120 @@ class SchedulerTestFunctions(unittest.TestCase):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test10(self):
 | 
					    def test10(self):
 | 
				
			||||||
        """10: instance_get_by_internal_id issue NotFound. """
 | 
					        """10: instance_get issues NotFound. """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Mocks for has_enough_resource()
 | 
					        db.instance_get = Mock(side_effect=exception.NotFound("ERR"))
 | 
				
			||||||
        db.instance_get = Mock(return_value = self.instance8)
 | 
					 | 
				
			||||||
        # Mocks for live_migration()db.instance_get_by_internal_id
 | 
					 | 
				
			||||||
        # (any Mock is ok here. important mock is all above)
 | 
					 | 
				
			||||||
        db.instance_get_by_internal_id = Mock(side_effect=exception.NotFound("ERR"))
 | 
					 | 
				
			||||||
 
 | 
					 | 
				
			||||||
        self.assertRaises(exception.NotFound,
 | 
					        self.assertRaises(exception.NotFound,
 | 
				
			||||||
                     self.manager.live_migration,
 | 
					                     self.manager.driver.schedule_live_migration,
 | 
				
			||||||
                     self.ctxt, 
 | 
					                     self.ctxt, 
 | 
				
			||||||
                     'i-12345', 
 | 
					                     'i-12345', 
 | 
				
			||||||
                     'host1') 
 | 
					                     'host1') 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
    def test11(self):
 | 
					    def test11(self):
 | 
				
			||||||
        """11: get NotFound exception when dest host not found on DB """
 | 
					        """11: instance_get issues Unexpected error. """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        db.host_get_by_name = Mock( side_effect=exception.NotFound('ERR') )
 | 
					        db.instance_get = Mock(side_effect=TypeError("ERR"))
 | 
				
			||||||
        self.assertRaises(exception.NotFound,
 | 
					        self.assertRaises(TypeError,
 | 
				
			||||||
                     self.manager.live_migration,
 | 
					                     self.manager.driver.schedule_live_migration,
 | 
				
			||||||
                     self.ctxt, 
 | 
					                     self.ctxt, 
 | 
				
			||||||
                     'i-12345', 
 | 
					                     'i-12345', 
 | 
				
			||||||
                     'host1') 
 | 
					                     'host1') 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
    def test12(self):
 | 
					    def test12(self):
 | 
				
			||||||
        """12: Destination host is not compute node """
 | 
					        """12: instance state is not power_state.RUNNING. """
 | 
				
			||||||
        self.assertRaises(exception.Invalid,
 | 
					 | 
				
			||||||
                     self.manager.live_migration,
 | 
					 | 
				
			||||||
                     self.ctxt, 
 | 
					 | 
				
			||||||
                     'i-12345', 
 | 
					 | 
				
			||||||
                     'host2') 
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        db.instance_get = Mock(return_value=self.instance4)
 | 
				
			||||||
 | 
					        try : 
 | 
				
			||||||
 | 
					            self.manager.driver.schedule_live_migration(self.ctxt, 'i-12345', 'host1')
 | 
				
			||||||
 | 
					        except exception.Invalid, e:
 | 
				
			||||||
 | 
					            c1 = (0 <= str(e.args).find('is not running')) 
 | 
				
			||||||
 | 
					            self.assertTrue(c1, True)
 | 
				
			||||||
 | 
					        return False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # Cannot test the case of hypervisor type difference and hypervisor 
 | 
					 | 
				
			||||||
    # version difference, since we cannot set different mocks to same method..
 | 
					 | 
				
			||||||
 
 | 
					 | 
				
			||||||
    def test13(self):
 | 
					    def test13(self):
 | 
				
			||||||
        """13: rpc.call raises RemoteError(Unexpected error occurs when executing compareCPU) """
 | 
					        """13: instance state_description is not running. """
 | 
				
			||||||
        rpc.call = Mock(return_value = rpc.RemoteError(libvirt.libvirtError, 'val', 'traceback'))
 | 
					
 | 
				
			||||||
        self.assertRaises(rpc.RemoteError,
 | 
					        db.instance_get = Mock(return_value=self.instance5)
 | 
				
			||||||
                     self.manager.live_migration,
 | 
					        try : 
 | 
				
			||||||
                     self.ctxt, 
 | 
					            self.manager.driver.schedule_live_migration(self.ctxt, 'i-12345', 'host1')
 | 
				
			||||||
                     'i-12345', 
 | 
					        except exception.Invalid, e:
 | 
				
			||||||
                     'host1') 
 | 
					            c1 = (0 <= str(e.args).find('is not running')) 
 | 
				
			||||||
 | 
					            self.assertTrue(c1, True)
 | 
				
			||||||
 | 
					        return False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test14(self):
 | 
					    def test14(self):
 | 
				
			||||||
        """14: rpc.call returns 0 (cpu is not compatible between src and dest) """
 | 
					        """14: dest is not compute node.
 | 
				
			||||||
        rpc.call = Mock(return_value = 0)
 | 
					           (dest is not included in the result of db.service_get_all_by_topic)
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
        try : 
 | 
					        try : 
 | 
				
			||||||
            self.manager.live_migration(self.ctxt, 'i-12345', 'host1') 
 | 
					            self.manager.driver.schedule_live_migration(self.ctxt, 'i-12345', 'host2')
 | 
				
			||||||
        except exception.Invalid, e:
 | 
					        except exception.Invalid, e:
 | 
				
			||||||
            c1 =  ( 0 <= e.message.find('doesnt have compatibility to'))
 | 
					            c1 = (0 <= str(e.args).find('must be compute node')) 
 | 
				
			||||||
            self.assertTrue(c1, True)
 | 
					            self.assertTrue(c1, True)
 | 
				
			||||||
        return False
 | 
					        return False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test15(self):
 | 
					    def test15(self):
 | 
				
			||||||
        """15: raise NotEmpty if host doesnt have enough resource. """
 | 
					        """ 15: dest is not alive.(service_is up returns False) """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Mocks for has_enough_resource()
 | 
					        self.manager.driver.service_is_up = Mock(return_value=False)
 | 
				
			||||||
        db.instance_get = Mock(return_value = self.instance8)
 | 
					        try : 
 | 
				
			||||||
 | 
					            self.manager.driver.schedule_live_migration(self.ctxt, 'i-12345', 'host2')
 | 
				
			||||||
 | 
					        except exception.Invalid, e:
 | 
				
			||||||
 | 
					            c1 = (0 <= str(e.args).find('is not alive')) 
 | 
				
			||||||
 | 
					            self.assertTrue(c1, True)
 | 
				
			||||||
 | 
					        return False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Mocks for live_migration()
 | 
					    # Cannot test the case of hypervisor type difference and hypervisor 
 | 
				
			||||||
        db.instance_get_by_internal_id = Mock(return_value = self.instance8)
 | 
					    # version difference, since we cannot set different mocks to same method..
 | 
				
			||||||
        db.instance_set_state = Mock(return_value = True)
 | 
					 | 
				
			||||||
        rpc_cast = Mock(return_value = True)
 | 
					 | 
				
			||||||
 
 | 
					 
 | 
				
			||||||
        try :
 | 
					    def test16(self):
 | 
				
			||||||
            self.manager.live_migration(self.ctxt, 'i-12345', 'host1') 
 | 
					        """ 16: stored "cpuinfo" is not string """
 | 
				
			||||||
        except exception.NotEmpty, e:
 | 
					
 | 
				
			||||||
            c1 = ( 0 <= e.message.find('doesnt have enough resource') )
 | 
					        try : 
 | 
				
			||||||
 | 
					            self.manager.driver.schedule_live_migration(self.ctxt, 'i-12345', 'host2')
 | 
				
			||||||
 | 
					        except exception.Invalid, e:
 | 
				
			||||||
 | 
					            c1 = (0 <= str(e.args).find('Unexpected err') )
 | 
				
			||||||
            self.assertTrue(c1, True)
 | 
					            self.assertTrue(c1, True)
 | 
				
			||||||
        return False
 | 
					        return False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test16(self):
 | 
					    def test17(self):
 | 
				
			||||||
        """16: everything goes well. """
 | 
					        """17: rpc.call raises RemoteError(Unexpected error occurs when executing compareCPU) """
 | 
				
			||||||
 | 
					        rpc.call = Mock(return_value = rpc.RemoteError(libvirt.libvirtError, 'val', 'traceback'))
 | 
				
			||||||
 | 
					        self.assertRaises(rpc.RemoteError,
 | 
				
			||||||
 | 
					                     self.manager.driver.schedule_live_migration,
 | 
				
			||||||
 | 
					                     self.ctxt, 
 | 
				
			||||||
 | 
					                     'i-12345', 
 | 
				
			||||||
 | 
					                     'host2') 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        db.instance_get_by_internal_id = Mock(return_value = self.instance8)
 | 
					    def test18(self):
 | 
				
			||||||
        db.instance_set_state = Mock(return_value = True)
 | 
					        """18: rpc.call returns 0 (cpu is not compatible between src and dest) """
 | 
				
			||||||
        rpc.cast = Mock(return_value = True)
 | 
					        rpc.call = Mock(return_value = 0)
 | 
				
			||||||
 | 
					        try : 
 | 
				
			||||||
 | 
					            self.manager.driver.schedule_live_migration(self.ctxt, 'i-12345', 'host2') 
 | 
				
			||||||
 | 
					        except exception.Invalid, e:
 | 
				
			||||||
 | 
					            c1 =  ( 0 <= str(e.args).find('doesnt have compatibility to'))
 | 
				
			||||||
 | 
					            self.assertTrue(c1, True)
 | 
				
			||||||
 | 
					        return False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        ret= self.manager.live_migration(self.ctxt, 'i-12345', 'host1') 
 | 
					    def test19(self):
 | 
				
			||||||
        self.assertEqual(ret, None)
 | 
					        """19: raise NotEmpty if host doesnt have enough resource. """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        db.instance_get = Mock(return_value = self.instance8)
 | 
				
			||||||
 | 
					        try :
 | 
				
			||||||
 | 
					            self.manager.driver.schedule_live_migration(self.ctxt, 'i-12345', 'host2') 
 | 
				
			||||||
 | 
					        except exception.NotEmpty, e:
 | 
				
			||||||
 | 
					            c1 = ( 0 <= str(e.args).find('doesnt have enough resource') )
 | 
				
			||||||
 | 
					            self.assertTrue(c1, True)
 | 
				
			||||||
 | 
					        return False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test20(self):
 | 
				
			||||||
 | 
					        """20: everything goes well. """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        #db.instance_get = Mock(return_value = self.instance8)
 | 
				
			||||||
 | 
					        ret= self.manager.driver.schedule_live_migration(self.ctxt, 'i-12345', 'host2') 
 | 
				
			||||||
 | 
					        self.assertEqual(ret, self.instance8['host'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def tearDown(self):
 | 
					    def tearDown(self):
 | 
				
			||||||
 
 | 
				
			|||||||
										
											Binary file not shown.
										
									
								
							@@ -55,7 +55,6 @@ from nova import utils
 | 
				
			|||||||
from nova import flags
 | 
					from nova import flags
 | 
				
			||||||
from nova.db import base
 | 
					from nova.db import base
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from twisted.internet import defer
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
FLAGS = flags.FLAGS
 | 
					FLAGS = flags.FLAGS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -67,10 +66,9 @@ class Manager(base.Base):
 | 
				
			|||||||
        self.host = host
 | 
					        self.host = host
 | 
				
			||||||
        super(Manager, self).__init__(db_driver)
 | 
					        super(Manager, self).__init__(db_driver)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @defer.inlineCallbacks
 | 
					 | 
				
			||||||
    def periodic_tasks(self, context=None):
 | 
					    def periodic_tasks(self, context=None):
 | 
				
			||||||
        """Tasks to be run at a periodic interval"""
 | 
					        """Tasks to be run at a periodic interval"""
 | 
				
			||||||
        yield
 | 
					        pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def init_host(self):
 | 
					    def init_host(self):
 | 
				
			||||||
        """Do any initialization that needs to be run if this is a standalone
 | 
					        """Do any initialization that needs to be run if this is a standalone
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										209
									
								
								nova/process.py
									
									
									
									
									
								
							
							
						
						
									
										209
									
								
								nova/process.py
									
									
									
									
									
								
							@@ -1,209 +0,0 @@
 | 
				
			|||||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Copyright 2010 United States Government as represented by the
 | 
					 | 
				
			||||||
# Administrator of the National Aeronautics and Space Administration.
 | 
					 | 
				
			||||||
# Copyright 2010 FathomDB Inc.
 | 
					 | 
				
			||||||
# 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.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
"""
 | 
					 | 
				
			||||||
Process pool using twisted threading
 | 
					 | 
				
			||||||
"""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import logging
 | 
					 | 
				
			||||||
import StringIO
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from twisted.internet import defer
 | 
					 | 
				
			||||||
from twisted.internet import error
 | 
					 | 
				
			||||||
from twisted.internet import protocol
 | 
					 | 
				
			||||||
from twisted.internet import reactor
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from nova import flags
 | 
					 | 
				
			||||||
from nova.exception import ProcessExecutionError
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
FLAGS = flags.FLAGS
 | 
					 | 
				
			||||||
flags.DEFINE_integer('process_pool_size', 4,
 | 
					 | 
				
			||||||
                     'Number of processes to use in the process pool')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# This is based on _BackRelay from twister.internal.utils, but modified to
 | 
					 | 
				
			||||||
#  capture both stdout and stderr, without odd stderr handling, and also to
 | 
					 | 
				
			||||||
#  handle stdin
 | 
					 | 
				
			||||||
class BackRelayWithInput(protocol.ProcessProtocol):
 | 
					 | 
				
			||||||
    """
 | 
					 | 
				
			||||||
    Trivial protocol for communicating with a process and turning its output
 | 
					 | 
				
			||||||
    into the result of a L{Deferred}.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @ivar deferred: A L{Deferred} which will be called back with all of stdout
 | 
					 | 
				
			||||||
        and all of stderr as well (as a tuple).  C{terminate_on_stderr} is true
 | 
					 | 
				
			||||||
        and any bytes are received over stderr, this will fire with an
 | 
					 | 
				
			||||||
        L{_ProcessExecutionError} instance and the attribute will be set to
 | 
					 | 
				
			||||||
        C{None}.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @ivar onProcessEnded: If C{terminate_on_stderr} is false and bytes are
 | 
					 | 
				
			||||||
        received over stderr, this attribute will refer to a L{Deferred} which
 | 
					 | 
				
			||||||
        will be called back when the process ends.  This C{Deferred} is also
 | 
					 | 
				
			||||||
        associated with the L{_ProcessExecutionError} which C{deferred} fires
 | 
					 | 
				
			||||||
        with earlier in this case so that users can determine when the process
 | 
					 | 
				
			||||||
        has actually ended, in addition to knowing when bytes have been
 | 
					 | 
				
			||||||
        received via stderr.
 | 
					 | 
				
			||||||
    """
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def __init__(self, deferred, cmd, started_deferred=None,
 | 
					 | 
				
			||||||
                 terminate_on_stderr=False, check_exit_code=True,
 | 
					 | 
				
			||||||
                 process_input=None):
 | 
					 | 
				
			||||||
        self.deferred = deferred
 | 
					 | 
				
			||||||
        self.cmd = cmd
 | 
					 | 
				
			||||||
        self.stdout = StringIO.StringIO()
 | 
					 | 
				
			||||||
        self.stderr = StringIO.StringIO()
 | 
					 | 
				
			||||||
        self.started_deferred = started_deferred
 | 
					 | 
				
			||||||
        self.terminate_on_stderr = terminate_on_stderr
 | 
					 | 
				
			||||||
        self.check_exit_code = check_exit_code
 | 
					 | 
				
			||||||
        self.process_input = process_input
 | 
					 | 
				
			||||||
        self.on_process_ended = None
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def _build_execution_error(self, exit_code=None):
 | 
					 | 
				
			||||||
        return ProcessExecutionError(cmd=self.cmd,
 | 
					 | 
				
			||||||
                                     exit_code=exit_code,
 | 
					 | 
				
			||||||
                                     stdout=self.stdout.getvalue(),
 | 
					 | 
				
			||||||
                                     stderr=self.stderr.getvalue())
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def errReceived(self, text):
 | 
					 | 
				
			||||||
        self.stderr.write(text)
 | 
					 | 
				
			||||||
        if self.terminate_on_stderr and (self.deferred is not None):
 | 
					 | 
				
			||||||
            self.on_process_ended = defer.Deferred()
 | 
					 | 
				
			||||||
            self.deferred.errback(self._build_execution_error())
 | 
					 | 
				
			||||||
            self.deferred = None
 | 
					 | 
				
			||||||
            self.transport.loseConnection()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def outReceived(self, text):
 | 
					 | 
				
			||||||
        self.stdout.write(text)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def processEnded(self, reason):
 | 
					 | 
				
			||||||
        if self.deferred is not None:
 | 
					 | 
				
			||||||
            stdout, stderr = self.stdout.getvalue(), self.stderr.getvalue()
 | 
					 | 
				
			||||||
            exit_code = reason.value.exitCode
 | 
					 | 
				
			||||||
            if self.check_exit_code and exit_code != 0:
 | 
					 | 
				
			||||||
                self.deferred.errback(self._build_execution_error(exit_code))
 | 
					 | 
				
			||||||
            else:
 | 
					 | 
				
			||||||
                try:
 | 
					 | 
				
			||||||
                    if self.check_exit_code:
 | 
					 | 
				
			||||||
                        reason.trap(error.ProcessDone)
 | 
					 | 
				
			||||||
                    self.deferred.callback((stdout, stderr))
 | 
					 | 
				
			||||||
                except:
 | 
					 | 
				
			||||||
                    # NOTE(justinsb): This logic is a little suspicious to me.
 | 
					 | 
				
			||||||
                    # If the callback throws an exception, then errback will
 | 
					 | 
				
			||||||
                    # be called also. However, this is what the unit tests
 | 
					 | 
				
			||||||
                    # test for.
 | 
					 | 
				
			||||||
                    exec_error = self._build_execution_error(exit_code)
 | 
					 | 
				
			||||||
                    self.deferred.errback(exec_error)
 | 
					 | 
				
			||||||
        elif self.on_process_ended is not None:
 | 
					 | 
				
			||||||
            self.on_process_ended.errback(reason)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def connectionMade(self):
 | 
					 | 
				
			||||||
        if self.started_deferred:
 | 
					 | 
				
			||||||
            self.started_deferred.callback(self)
 | 
					 | 
				
			||||||
        if self.process_input:
 | 
					 | 
				
			||||||
            self.transport.write(str(self.process_input))
 | 
					 | 
				
			||||||
        self.transport.closeStdin()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def get_process_output(executable, args=None, env=None, path=None,
 | 
					 | 
				
			||||||
                       process_reactor=None, check_exit_code=True,
 | 
					 | 
				
			||||||
                       process_input=None, started_deferred=None,
 | 
					 | 
				
			||||||
                       terminate_on_stderr=False):
 | 
					 | 
				
			||||||
    if process_reactor is None:
 | 
					 | 
				
			||||||
        process_reactor = reactor
 | 
					 | 
				
			||||||
    args = args and args or ()
 | 
					 | 
				
			||||||
    env = env and env and {}
 | 
					 | 
				
			||||||
    deferred = defer.Deferred()
 | 
					 | 
				
			||||||
    cmd = executable
 | 
					 | 
				
			||||||
    if args:
 | 
					 | 
				
			||||||
        cmd = " ".join([cmd] + args)
 | 
					 | 
				
			||||||
    logging.debug("Running cmd: %s", cmd)
 | 
					 | 
				
			||||||
    process_handler = BackRelayWithInput(
 | 
					 | 
				
			||||||
            deferred,
 | 
					 | 
				
			||||||
            cmd,
 | 
					 | 
				
			||||||
            started_deferred=started_deferred,
 | 
					 | 
				
			||||||
            check_exit_code=check_exit_code,
 | 
					 | 
				
			||||||
            process_input=process_input,
 | 
					 | 
				
			||||||
            terminate_on_stderr=terminate_on_stderr)
 | 
					 | 
				
			||||||
    # NOTE(vish): commands come in as unicode, but self.executes needs
 | 
					 | 
				
			||||||
    #             strings or process.spawn raises a deprecation warning
 | 
					 | 
				
			||||||
    executable = str(executable)
 | 
					 | 
				
			||||||
    if not args is None:
 | 
					 | 
				
			||||||
        args = [str(x) for x in args]
 | 
					 | 
				
			||||||
    process_reactor.spawnProcess(process_handler, executable,
 | 
					 | 
				
			||||||
                                 (executable,) + tuple(args), env, path)
 | 
					 | 
				
			||||||
    return deferred
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class ProcessPool(object):
 | 
					 | 
				
			||||||
    """ A simple process pool implementation using Twisted's Process bits.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    This is pretty basic right now, but hopefully the API will be the correct
 | 
					 | 
				
			||||||
    one so that it can be optimized later.
 | 
					 | 
				
			||||||
    """
 | 
					 | 
				
			||||||
    def __init__(self, size=None):
 | 
					 | 
				
			||||||
        self.size = size and size or FLAGS.process_pool_size
 | 
					 | 
				
			||||||
        self._pool = defer.DeferredSemaphore(self.size)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def simple_execute(self, cmd, **kw):
 | 
					 | 
				
			||||||
        """ Weak emulation of the old utils.execute() function.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        This only exists as a way to quickly move old execute methods to
 | 
					 | 
				
			||||||
        this new style of code.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        NOTE(termie): This will break on args with spaces in them.
 | 
					 | 
				
			||||||
        """
 | 
					 | 
				
			||||||
        parsed = cmd.split(' ')
 | 
					 | 
				
			||||||
        executable, args = parsed[0], parsed[1:]
 | 
					 | 
				
			||||||
        return self.execute(executable, args, **kw)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def execute(self, *args, **kw):
 | 
					 | 
				
			||||||
        deferred = self._pool.acquire()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        def _associate_process(proto):
 | 
					 | 
				
			||||||
            deferred.process = proto.transport
 | 
					 | 
				
			||||||
            return proto.transport
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        started = defer.Deferred()
 | 
					 | 
				
			||||||
        started.addCallback(_associate_process)
 | 
					 | 
				
			||||||
        kw.setdefault('started_deferred', started)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        deferred.process = None
 | 
					 | 
				
			||||||
        deferred.started = started
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        deferred.addCallback(lambda _: get_process_output(*args, **kw))
 | 
					 | 
				
			||||||
        deferred.addBoth(self._release)
 | 
					 | 
				
			||||||
        return deferred
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def _release(self, retval=None):
 | 
					 | 
				
			||||||
        self._pool.release()
 | 
					 | 
				
			||||||
        return retval
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class SharedPool(object):
 | 
					 | 
				
			||||||
    _instance = None
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def __init__(self):
 | 
					 | 
				
			||||||
        if SharedPool._instance is None:
 | 
					 | 
				
			||||||
            self.__class__._instance = ProcessPool()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def __getattr__(self, key):
 | 
					 | 
				
			||||||
        return getattr(self._instance, key)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def simple_execute(cmd, **kwargs):
 | 
					 | 
				
			||||||
    return SharedPool().simple_execute(cmd, **kwargs)
 | 
					 | 
				
			||||||
							
								
								
									
										119
									
								
								nova/rpc.py
									
									
									
									
									
								
							
							
						
						
									
										119
									
								
								nova/rpc.py
									
									
									
									
									
								
							@@ -25,18 +25,18 @@ import json
 | 
				
			|||||||
import logging
 | 
					import logging
 | 
				
			||||||
import sys
 | 
					import sys
 | 
				
			||||||
import time
 | 
					import time
 | 
				
			||||||
 | 
					import traceback
 | 
				
			||||||
import uuid
 | 
					import uuid
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from carrot import connection as carrot_connection
 | 
					from carrot import connection as carrot_connection
 | 
				
			||||||
from carrot import messaging
 | 
					from carrot import messaging
 | 
				
			||||||
from eventlet import greenthread
 | 
					from eventlet import greenthread
 | 
				
			||||||
from twisted.internet import defer
 | 
					 | 
				
			||||||
from twisted.internet import task
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from nova import context
 | 
				
			||||||
from nova import exception
 | 
					from nova import exception
 | 
				
			||||||
from nova import fakerabbit
 | 
					from nova import fakerabbit
 | 
				
			||||||
from nova import flags
 | 
					from nova import flags
 | 
				
			||||||
from nova import context
 | 
					from nova import utils
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
FLAGS = flags.FLAGS
 | 
					FLAGS = flags.FLAGS
 | 
				
			||||||
@@ -91,15 +91,15 @@ class Consumer(messaging.Consumer):
 | 
				
			|||||||
                self.failed_connection = False
 | 
					                self.failed_connection = False
 | 
				
			||||||
                break
 | 
					                break
 | 
				
			||||||
            except:  # Catching all because carrot sucks
 | 
					            except:  # Catching all because carrot sucks
 | 
				
			||||||
                logging.exception("AMQP server on %s:%d is unreachable." \
 | 
					                logging.exception(_("AMQP server on %s:%d is unreachable."
 | 
				
			||||||
                    " Trying again in %d seconds." % (
 | 
					                    " Trying again in %d seconds.") % (
 | 
				
			||||||
                    FLAGS.rabbit_host,
 | 
					                    FLAGS.rabbit_host,
 | 
				
			||||||
                    FLAGS.rabbit_port,
 | 
					                    FLAGS.rabbit_port,
 | 
				
			||||||
                    FLAGS.rabbit_retry_interval))
 | 
					                    FLAGS.rabbit_retry_interval))
 | 
				
			||||||
                self.failed_connection = True
 | 
					                self.failed_connection = True
 | 
				
			||||||
        if self.failed_connection:
 | 
					        if self.failed_connection:
 | 
				
			||||||
            logging.exception("Unable to connect to AMQP server" \
 | 
					            logging.exception(_("Unable to connect to AMQP server"
 | 
				
			||||||
                " after %d tries. Shutting down." % FLAGS.rabbit_max_retries)
 | 
					                " after %d tries. Shutting down.") % FLAGS.rabbit_max_retries)
 | 
				
			||||||
            sys.exit(1)
 | 
					            sys.exit(1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def fetch(self, no_ack=None, auto_ack=None, enable_callbacks=False):
 | 
					    def fetch(self, no_ack=None, auto_ack=None, enable_callbacks=False):
 | 
				
			||||||
@@ -116,29 +116,21 @@ class Consumer(messaging.Consumer):
 | 
				
			|||||||
                self.declare()
 | 
					                self.declare()
 | 
				
			||||||
            super(Consumer, self).fetch(no_ack, auto_ack, enable_callbacks)
 | 
					            super(Consumer, self).fetch(no_ack, auto_ack, enable_callbacks)
 | 
				
			||||||
            if self.failed_connection:
 | 
					            if self.failed_connection:
 | 
				
			||||||
                logging.error("Reconnected to queue")
 | 
					                logging.error(_("Reconnected to queue"))
 | 
				
			||||||
                self.failed_connection = False
 | 
					                self.failed_connection = False
 | 
				
			||||||
        # NOTE(vish): This is catching all errors because we really don't
 | 
					        # NOTE(vish): This is catching all errors because we really don't
 | 
				
			||||||
        #             exceptions to be logged 10 times a second if some
 | 
					        #             exceptions to be logged 10 times a second if some
 | 
				
			||||||
        #             persistent failure occurs.
 | 
					        #             persistent failure occurs.
 | 
				
			||||||
        except Exception:  # pylint: disable-msg=W0703
 | 
					        except Exception:  # pylint: disable-msg=W0703
 | 
				
			||||||
            if not self.failed_connection:
 | 
					            if not self.failed_connection:
 | 
				
			||||||
                logging.exception("Failed to fetch message from queue")
 | 
					                logging.exception(_("Failed to fetch message from queue"))
 | 
				
			||||||
                self.failed_connection = True
 | 
					                self.failed_connection = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def attach_to_eventlet(self):
 | 
					    def attach_to_eventlet(self):
 | 
				
			||||||
        """Only needed for unit tests!"""
 | 
					        """Only needed for unit tests!"""
 | 
				
			||||||
        def fetch_repeatedly():
 | 
					        timer = utils.LoopingCall(self.fetch, enable_callbacks=True)
 | 
				
			||||||
            while True:
 | 
					        timer.start(0.1)
 | 
				
			||||||
                self.fetch(enable_callbacks=True)
 | 
					        return timer
 | 
				
			||||||
                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)
 | 
					 | 
				
			||||||
        loop.start(interval=0.1)
 | 
					 | 
				
			||||||
        return loop
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Publisher(messaging.Publisher):
 | 
					class Publisher(messaging.Publisher):
 | 
				
			||||||
@@ -161,7 +153,7 @@ class TopicConsumer(Consumer):
 | 
				
			|||||||
class AdapterConsumer(TopicConsumer):
 | 
					class AdapterConsumer(TopicConsumer):
 | 
				
			||||||
    """Calls methods on a proxy object based on method and args"""
 | 
					    """Calls methods on a proxy object based on method and args"""
 | 
				
			||||||
    def __init__(self, connection=None, topic="broadcast", proxy=None):
 | 
					    def __init__(self, connection=None, topic="broadcast", proxy=None):
 | 
				
			||||||
        LOG.debug('Initing the Adapter Consumer for %s' % (topic))
 | 
					        LOG.debug(_('Initing the Adapter Consumer for %s') % (topic))
 | 
				
			||||||
        self.proxy = proxy
 | 
					        self.proxy = proxy
 | 
				
			||||||
        super(AdapterConsumer, self).__init__(connection=connection,
 | 
					        super(AdapterConsumer, self).__init__(connection=connection,
 | 
				
			||||||
                                              topic=topic)
 | 
					                                              topic=topic)
 | 
				
			||||||
@@ -176,7 +168,7 @@ class AdapterConsumer(TopicConsumer):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        Example: {'method': 'echo', 'args': {'value': 42}}
 | 
					        Example: {'method': 'echo', 'args': {'value': 42}}
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        LOG.debug('received %s' % (message_data))
 | 
					        LOG.debug(_('received %s') % (message_data))
 | 
				
			||||||
        msg_id = message_data.pop('_msg_id', None)
 | 
					        msg_id = message_data.pop('_msg_id', None)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        ctxt = _unpack_context(message_data)
 | 
					        ctxt = _unpack_context(message_data)
 | 
				
			||||||
@@ -189,18 +181,20 @@ class AdapterConsumer(TopicConsumer):
 | 
				
			|||||||
            #             messages stay in the queue indefinitely, so for now
 | 
					            #             messages stay in the queue indefinitely, so for now
 | 
				
			||||||
            #             we just log the message and send an error string
 | 
					            #             we just log the message and send an error string
 | 
				
			||||||
            #             back to the caller
 | 
					            #             back to the caller
 | 
				
			||||||
            LOG.warn('no method for message: %s' % (message_data))
 | 
					            LOG.warn(_('no method for message: %s') % (message_data))
 | 
				
			||||||
            msg_reply(msg_id, 'No method for message: %s' % message_data)
 | 
					            msg_reply(msg_id, _('No method for message: %s') % message_data)
 | 
				
			||||||
            return
 | 
					            return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        node_func = getattr(self.proxy, str(method))
 | 
					        node_func = getattr(self.proxy, str(method))
 | 
				
			||||||
        node_args = dict((str(k), v) for k, v in args.iteritems())
 | 
					        node_args = dict((str(k), v) for k, v in args.iteritems())
 | 
				
			||||||
        # NOTE(vish): magic is fun!
 | 
					        # NOTE(vish): magic is fun!
 | 
				
			||||||
        # pylint: disable-msg=W0142
 | 
					        try:
 | 
				
			||||||
        d = defer.maybeDeferred(node_func, context=ctxt, **node_args)
 | 
					            rval = node_func(context=ctxt, **node_args)
 | 
				
			||||||
        if msg_id:
 | 
					            if msg_id:
 | 
				
			||||||
            d.addCallback(lambda rval: msg_reply(msg_id, rval, None))
 | 
					                msg_reply(msg_id, rval, None)
 | 
				
			||||||
            d.addErrback(lambda e: msg_reply(msg_id, None, e))
 | 
					        except Exception as e:
 | 
				
			||||||
 | 
					            if msg_id:
 | 
				
			||||||
 | 
					                msg_reply(msg_id, None, sys.exc_info())
 | 
				
			||||||
        return
 | 
					        return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -242,14 +236,16 @@ class DirectPublisher(Publisher):
 | 
				
			|||||||
def msg_reply(msg_id, reply=None, failure=None):
 | 
					def msg_reply(msg_id, reply=None, failure=None):
 | 
				
			||||||
    """Sends a reply or an error on the channel signified by msg_id
 | 
					    """Sends a reply or an error on the channel signified by msg_id
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    failure should be a twisted failure object"""
 | 
					    failure should be a sys.exc_info() tuple.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
    if failure:
 | 
					    if failure:
 | 
				
			||||||
        message = failure.getErrorMessage()
 | 
					        message = str(failure[1])
 | 
				
			||||||
        traceback = failure.getTraceback()
 | 
					        tb = traceback.format_exception(*failure)
 | 
				
			||||||
        logging.error("Returning exception %s to caller", message)
 | 
					        logging.error(_("Returning exception %s to caller"), message)
 | 
				
			||||||
        logging.error(traceback)
 | 
					        logging.error(tb)
 | 
				
			||||||
        failure = (failure.type.__name__, str(failure.value), traceback)
 | 
					        failure = (failure[0].__name__, str(failure[1]), tb)
 | 
				
			||||||
    conn = Connection.instance()
 | 
					    conn = Connection.instance(True)
 | 
				
			||||||
    publisher = DirectPublisher(connection=conn, msg_id=msg_id)
 | 
					    publisher = DirectPublisher(connection=conn, msg_id=msg_id)
 | 
				
			||||||
    try:
 | 
					    try:
 | 
				
			||||||
        publisher.send({'result': reply, 'failure': failure})
 | 
					        publisher.send({'result': reply, 'failure': failure})
 | 
				
			||||||
@@ -287,7 +283,7 @@ def _unpack_context(msg):
 | 
				
			|||||||
        if key.startswith('_context_'):
 | 
					        if key.startswith('_context_'):
 | 
				
			||||||
            value = msg.pop(key)
 | 
					            value = msg.pop(key)
 | 
				
			||||||
            context_dict[key[9:]] = value
 | 
					            context_dict[key[9:]] = value
 | 
				
			||||||
    LOG.debug('unpacked context: %s', context_dict)
 | 
					    LOG.debug(_('unpacked context: %s'), context_dict)
 | 
				
			||||||
    return context.RequestContext.from_dict(context_dict)
 | 
					    return context.RequestContext.from_dict(context_dict)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -306,14 +302,13 @@ def _pack_context(msg, context):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
def call(context, topic, msg):
 | 
					def call(context, topic, msg):
 | 
				
			||||||
    """Sends a message on a topic and wait for a response"""
 | 
					    """Sends a message on a topic and wait for a response"""
 | 
				
			||||||
    LOG.debug("Making asynchronous call...")
 | 
					    LOG.debug(_("Making asynchronous call..."))
 | 
				
			||||||
    msg_id = uuid.uuid4().hex
 | 
					    msg_id = uuid.uuid4().hex
 | 
				
			||||||
    msg.update({'_msg_id': msg_id})
 | 
					    msg.update({'_msg_id': msg_id})
 | 
				
			||||||
    LOG.debug("MSG_ID is %s" % (msg_id))
 | 
					    LOG.debug(_("MSG_ID is %s") % (msg_id))
 | 
				
			||||||
    _pack_context(msg, context)
 | 
					    _pack_context(msg, context)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    class WaitMessage(object):
 | 
					    class WaitMessage(object):
 | 
				
			||||||
 | 
					 | 
				
			||||||
        def __call__(self, data, message):
 | 
					        def __call__(self, data, message):
 | 
				
			||||||
            """Acks message and sets result."""
 | 
					            """Acks message and sets result."""
 | 
				
			||||||
            message.ack()
 | 
					            message.ack()
 | 
				
			||||||
@@ -337,41 +332,15 @@ def call(context, topic, msg):
 | 
				
			|||||||
    except StopIteration:
 | 
					    except StopIteration:
 | 
				
			||||||
        pass
 | 
					        pass
 | 
				
			||||||
    consumer.close()
 | 
					    consumer.close()
 | 
				
			||||||
 | 
					    # NOTE(termie): this is a little bit of a change from the original
 | 
				
			||||||
 | 
					    #               non-eventlet code where returning a Failure
 | 
				
			||||||
 | 
					    #               instance from a deferred call is very similar to
 | 
				
			||||||
 | 
					    #               raising an exception
 | 
				
			||||||
 | 
					    if isinstance(wait_msg.result, Exception):
 | 
				
			||||||
 | 
					        raise wait_msg.result
 | 
				
			||||||
    return wait_msg.result
 | 
					    return wait_msg.result
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def call_twisted(context, topic, msg):
 | 
					 | 
				
			||||||
    """Sends a message on a topic and wait for a response"""
 | 
					 | 
				
			||||||
    LOG.debug("Making asynchronous call...")
 | 
					 | 
				
			||||||
    msg_id = uuid.uuid4().hex
 | 
					 | 
				
			||||||
    msg.update({'_msg_id': msg_id})
 | 
					 | 
				
			||||||
    LOG.debug("MSG_ID is %s" % (msg_id))
 | 
					 | 
				
			||||||
    _pack_context(msg, context)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    conn = Connection.instance()
 | 
					 | 
				
			||||||
    d = defer.Deferred()
 | 
					 | 
				
			||||||
    consumer = DirectConsumer(connection=conn, msg_id=msg_id)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def deferred_receive(data, message):
 | 
					 | 
				
			||||||
        """Acks message and callbacks or errbacks"""
 | 
					 | 
				
			||||||
        message.ack()
 | 
					 | 
				
			||||||
        if data['failure']:
 | 
					 | 
				
			||||||
            return d.errback(RemoteError(*data['failure']))
 | 
					 | 
				
			||||||
        else:
 | 
					 | 
				
			||||||
            return d.callback(data['result'])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    consumer.register_callback(deferred_receive)
 | 
					 | 
				
			||||||
    injected = consumer.attach_to_twisted()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    # clean up after the injected listened and return x
 | 
					 | 
				
			||||||
    d.addCallback(lambda x: injected.stop() and x or x)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    publisher = TopicPublisher(connection=conn, topic=topic)
 | 
					 | 
				
			||||||
    publisher.send(msg)
 | 
					 | 
				
			||||||
    publisher.close()
 | 
					 | 
				
			||||||
    return d
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def cast(context, topic, msg):
 | 
					def cast(context, topic, msg):
 | 
				
			||||||
    """Sends a message on a topic without waiting for a response"""
 | 
					    """Sends a message on a topic without waiting for a response"""
 | 
				
			||||||
    LOG.debug("Making asynchronous cast...")
 | 
					    LOG.debug("Making asynchronous cast...")
 | 
				
			||||||
@@ -384,7 +353,7 @@ def cast(context, topic, msg):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
def generic_response(message_data, message):
 | 
					def generic_response(message_data, message):
 | 
				
			||||||
    """Logs a result and exits"""
 | 
					    """Logs a result and exits"""
 | 
				
			||||||
    LOG.debug('response %s', message_data)
 | 
					    LOG.debug(_('response %s'), message_data)
 | 
				
			||||||
    message.ack()
 | 
					    message.ack()
 | 
				
			||||||
    sys.exit(0)
 | 
					    sys.exit(0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -393,8 +362,8 @@ def send_message(topic, message, wait=True):
 | 
				
			|||||||
    """Sends a message for testing"""
 | 
					    """Sends a message for testing"""
 | 
				
			||||||
    msg_id = uuid.uuid4().hex
 | 
					    msg_id = uuid.uuid4().hex
 | 
				
			||||||
    message.update({'_msg_id': msg_id})
 | 
					    message.update({'_msg_id': msg_id})
 | 
				
			||||||
    LOG.debug('topic is %s', topic)
 | 
					    LOG.debug(_('topic is %s'), topic)
 | 
				
			||||||
    LOG.debug('message %s', message)
 | 
					    LOG.debug(_('message %s'), message)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if wait:
 | 
					    if wait:
 | 
				
			||||||
        consumer = messaging.Consumer(connection=Connection.instance(),
 | 
					        consumer = messaging.Consumer(connection=Connection.instance(),
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -34,5 +34,5 @@ class ChanceScheduler(driver.Scheduler):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        hosts = self.hosts_up(context, topic)
 | 
					        hosts = self.hosts_up(context, topic)
 | 
				
			||||||
        if not hosts:
 | 
					        if not hosts:
 | 
				
			||||||
            raise driver.NoValidHost("No hosts found")
 | 
					            raise driver.NoValidHost(_("No hosts found"))
 | 
				
			||||||
        return hosts[int(random.random() * len(hosts))]
 | 
					        return hosts[int(random.random() * len(hosts))]
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -22,10 +22,14 @@ Scheduler base class that all Schedulers should inherit from
 | 
				
			|||||||
"""
 | 
					"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import datetime
 | 
					import datetime
 | 
				
			||||||
 | 
					import logging
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from nova import db
 | 
					from nova import db
 | 
				
			||||||
from nova import exception
 | 
					from nova import exception
 | 
				
			||||||
from nova import flags
 | 
					from nova import flags
 | 
				
			||||||
 | 
					from nova import rpc
 | 
				
			||||||
 | 
					from nova.api.ec2 import cloud
 | 
				
			||||||
 | 
					from nova.compute import power_state
 | 
				
			||||||
 | 
					
 | 
				
			||||||
FLAGS = flags.FLAGS
 | 
					FLAGS = flags.FLAGS
 | 
				
			||||||
flags.DEFINE_integer('service_down_time', 60,
 | 
					flags.DEFINE_integer('service_down_time', 60,
 | 
				
			||||||
@@ -58,4 +62,137 @@ class Scheduler(object):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    def schedule(self, context, topic, *_args, **_kwargs):
 | 
					    def schedule(self, context, topic, *_args, **_kwargs):
 | 
				
			||||||
        """Must override at least this method for scheduler to work."""
 | 
					        """Must override at least this method for scheduler to work."""
 | 
				
			||||||
        raise NotImplementedError("Must implement a fallback schedule")
 | 
					        raise NotImplementedError(_("Must implement a fallback schedule"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def schedule_live_migration(self, context, instance_id, dest):
 | 
				
			||||||
 | 
					        """ live migration method """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Whether instance exists and running
 | 
				
			||||||
 | 
					        # try-catch clause is necessary because only internal_id is shown
 | 
				
			||||||
 | 
					        # when NotFound exception occurs. it isnot understandable to admins.
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            instance_ref = db.instance_get(context, instance_id)
 | 
				
			||||||
 | 
					            ec2_id = instance_ref['hostname']
 | 
				
			||||||
 | 
					            internal_id = instance_ref['internal_id']
 | 
				
			||||||
 | 
					        except exception.NotFound, e:
 | 
				
			||||||
 | 
					            msg = _('Unexpected error: instance is not found')
 | 
				
			||||||
 | 
					            e.args += ('\n' + msg, )
 | 
				
			||||||
 | 
					            raise e
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Checking instance state.
 | 
				
			||||||
 | 
					        if power_state.RUNNING != instance_ref['state'] or \
 | 
				
			||||||
 | 
					           'running' != instance_ref['state_description']:
 | 
				
			||||||
 | 
					            msg = _('Instance(%s) is not running')
 | 
				
			||||||
 | 
					            raise exception.Invalid(msg % ec2_id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Checking destination host exists
 | 
				
			||||||
 | 
					        dhost_ref = db.host_get_by_name(context, dest)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Checking whether The host where instance is running
 | 
				
			||||||
 | 
					        # and dest is not same.
 | 
				
			||||||
 | 
					        src = instance_ref['host']
 | 
				
			||||||
 | 
					        if dest == src:
 | 
				
			||||||
 | 
					            msg = _('%s is where %s is running now. choose other host.')
 | 
				
			||||||
 | 
					            raise exception.Invalid(msg % (dest, ec2_id))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Checking dest is compute node.
 | 
				
			||||||
 | 
					        services = db.service_get_all_by_topic(context, 'compute')
 | 
				
			||||||
 | 
					        if dest not in [service.host for service in services]:
 | 
				
			||||||
 | 
					            msg = _('%s must be compute node')
 | 
				
			||||||
 | 
					            raise exception.Invalid(msg % dest)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Checking dest host is alive.
 | 
				
			||||||
 | 
					        service = [service for service in services if service.host == dest]
 | 
				
			||||||
 | 
					        service = service[0]
 | 
				
			||||||
 | 
					        if not self.service_is_up(service):
 | 
				
			||||||
 | 
					            msg = _('%s is not alive(time synchronize problem?)')
 | 
				
			||||||
 | 
					            raise exception.Invalid(msg % dest)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # NOTE(masumotok): Below pre-checkings are followed by
 | 
				
			||||||
 | 
					        # http://wiki.libvirt.org/page/TodoPreMigrationChecks
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Checking hypervisor is same.
 | 
				
			||||||
 | 
					        orighost = instance_ref['launched_on']
 | 
				
			||||||
 | 
					        ohost_ref = db.host_get_by_name(context, orighost)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        otype = ohost_ref['hypervisor_type']
 | 
				
			||||||
 | 
					        dtype = dhost_ref['hypervisor_type']
 | 
				
			||||||
 | 
					        if otype != dtype:
 | 
				
			||||||
 | 
					            msg = _('Different hypervisor type(%s->%s)')
 | 
				
			||||||
 | 
					            raise exception.Invalid(msg % (otype, dtype))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Checkng hypervisor version.
 | 
				
			||||||
 | 
					        oversion = ohost_ref['hypervisor_version']
 | 
				
			||||||
 | 
					        dversion = dhost_ref['hypervisor_version']
 | 
				
			||||||
 | 
					        if oversion > dversion:
 | 
				
			||||||
 | 
					            msg = _('Older hypervisor version(%s->%s)')
 | 
				
			||||||
 | 
					            raise exception.Invalid(msg % (oversion, dversion))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Checking cpuinfo.
 | 
				
			||||||
 | 
					        cpuinfo = ohost_ref['cpu_info']
 | 
				
			||||||
 | 
					        if str != type(cpuinfo):
 | 
				
			||||||
 | 
					            msg = _('Unexpected err: not found cpu_info for %s on DB.hosts')
 | 
				
			||||||
 | 
					            raise exception.Invalid(msg % orighost)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ret = rpc.call(context,
 | 
				
			||||||
 | 
					                       db.queue_get_for(context, FLAGS.compute_topic, dest),
 | 
				
			||||||
 | 
					                       {"method": 'compareCPU',
 | 
				
			||||||
 | 
					                        "args": {'xml': cpuinfo}})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if int != type(ret):
 | 
				
			||||||
 | 
					            raise ret
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if 0 >= ret:
 | 
				
			||||||
 | 
					            u = 'http://libvirt.org/html/libvirt-libvirt.html'
 | 
				
			||||||
 | 
					            u += '#virCPUCompareResult'
 | 
				
			||||||
 | 
					            msg = '%s doesnt have compatibility to %s(where %s launching at)\n'
 | 
				
			||||||
 | 
					            msg += 'result:%d \n'
 | 
				
			||||||
 | 
					            msg += 'Refer to %s'
 | 
				
			||||||
 | 
					            msg = _(msg)
 | 
				
			||||||
 | 
					            raise exception.Invalid(msg % (dest, src, ec2_id, ret, u))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Checking dst host still has enough capacities.
 | 
				
			||||||
 | 
					        self.has_enough_resource(context, instance_id, dest)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Changing instance_state.
 | 
				
			||||||
 | 
					        db.instance_set_state(context,
 | 
				
			||||||
 | 
					                              instance_id,
 | 
				
			||||||
 | 
					                              power_state.PAUSED,
 | 
				
			||||||
 | 
					                              'migrating')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Requesting live migration.
 | 
				
			||||||
 | 
					        return src
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def has_enough_resource(self, context, instance_id, dest):
 | 
				
			||||||
 | 
					        """ Check if destination host has enough resource for live migration"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Getting instance information
 | 
				
			||||||
 | 
					        instance_ref = db.instance_get(context, instance_id)
 | 
				
			||||||
 | 
					        ec2_id = instance_ref['hostname']
 | 
				
			||||||
 | 
					        vcpus = instance_ref['vcpus']
 | 
				
			||||||
 | 
					        mem = instance_ref['memory_mb']
 | 
				
			||||||
 | 
					        hdd = instance_ref['local_gb']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Gettin host information
 | 
				
			||||||
 | 
					        host_ref = db.host_get_by_name(context, dest)
 | 
				
			||||||
 | 
					        total_cpu = int(host_ref['vcpus'])
 | 
				
			||||||
 | 
					        total_mem = int(host_ref['memory_mb'])
 | 
				
			||||||
 | 
					        total_hdd = int(host_ref['local_gb'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        instances_ref = db.instance_get_all_by_host(context, dest)
 | 
				
			||||||
 | 
					        for i_ref in instances_ref:
 | 
				
			||||||
 | 
					            total_cpu -= int(i_ref['vcpus'])
 | 
				
			||||||
 | 
					            total_mem -= int(i_ref['memory_mb'])
 | 
				
			||||||
 | 
					            total_hdd -= int(i_ref['local_gb'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Checking host has enough information
 | 
				
			||||||
 | 
					        logging.debug('host(%s) remains vcpu:%s mem:%s hdd:%s,' %
 | 
				
			||||||
 | 
					                      (dest, total_cpu, total_mem, total_hdd))
 | 
				
			||||||
 | 
					        logging.debug('instance(%s) has vcpu:%s mem:%s hdd:%s,' %
 | 
				
			||||||
 | 
					                      (ec2_id, vcpus, mem, hdd))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if total_cpu <= vcpus or total_mem <= mem or total_hdd <= hdd:
 | 
				
			||||||
 | 
					            msg = '%s doesnt have enough resource for %s' % (dest, ec2_id)
 | 
				
			||||||
 | 
					            raise exception.NotEmpty(msg)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        logging.debug(_('%s has enough resource for %s') % (dest, ec2_id))
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -30,8 +30,6 @@ from nova import manager
 | 
				
			|||||||
from nova import rpc
 | 
					from nova import rpc
 | 
				
			||||||
from nova import utils
 | 
					from nova import utils
 | 
				
			||||||
from nova import exception
 | 
					from nova import exception
 | 
				
			||||||
from nova.api.ec2 import cloud
 | 
					 | 
				
			||||||
from nova.compute import power_state
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
FLAGS = flags.FLAGS
 | 
					FLAGS = flags.FLAGS
 | 
				
			||||||
flags.DEFINE_string('scheduler_driver',
 | 
					flags.DEFINE_string('scheduler_driver',
 | 
				
			||||||
@@ -68,119 +66,11 @@ class SchedulerManager(manager.Manager):
 | 
				
			|||||||
                 db.queue_get_for(context, topic, host),
 | 
					                 db.queue_get_for(context, topic, host),
 | 
				
			||||||
                 {"method": method,
 | 
					                 {"method": method,
 | 
				
			||||||
                  "args": kwargs})
 | 
					                  "args": kwargs})
 | 
				
			||||||
        logging.debug("Casting to %s %s for %s", topic, host, method)
 | 
					        logging.debug(_("Casting to %s %s for %s"), topic, host, method)
 | 
				
			||||||
 | 
					 | 
				
			||||||
    def live_migration(self, context, ec2_id, dest):
 | 
					 | 
				
			||||||
        """ live migration method"""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # (masumotok) below pre-checking is followed by 
 | 
					 | 
				
			||||||
        # http://wiki.libvirt.org/page/TodoPreMigrationChecks
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # 1. get instance id
 | 
					 | 
				
			||||||
        internal_id = cloud.ec2_id_to_internal_id(ec2_id)
 | 
					 | 
				
			||||||
        instance_ref = db.instance_get_by_internal_id(context, internal_id)
 | 
					 | 
				
			||||||
        instance_id = instance_ref['id']
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # 2. get src host and dst host
 | 
					 | 
				
			||||||
        src = instance_ref['launched_on']
 | 
					 | 
				
			||||||
        shost_ref = db.host_get_by_name(context, src )
 | 
					 | 
				
			||||||
        dhost_ref = db.host_get_by_name(context, dest)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # 3. dest should be compute
 | 
					 | 
				
			||||||
        services = db.service_get_all_by_topic(context, 'compute')
 | 
					 | 
				
			||||||
        logging.warn('%s' % [service.host for service in services])
 | 
					 | 
				
			||||||
        if dest not in [service.host for service in services] :
 | 
					 | 
				
			||||||
            raise exception.Invalid('%s must be compute node' % dest)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # 4. check hypervisor is same
 | 
					 | 
				
			||||||
        shypervisor = shost_ref['hypervisor_type'] 
 | 
					 | 
				
			||||||
        dhypervisor = dhost_ref['hypervisor_type']
 | 
					 | 
				
			||||||
        if shypervisor != dhypervisor:
 | 
					 | 
				
			||||||
            msg = 'Different hypervisor type(%s->%s)' % (shypervisor, dhypervisor)
 | 
					 | 
				
			||||||
            raise exception.Invalid(msg)
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        # 5. check hypervisor version 
 | 
					 | 
				
			||||||
        shypervisor = shost_ref['hypervisor_version'] 
 | 
					 | 
				
			||||||
        dhypervisor = dhost_ref['hypervisor_version']
 | 
					 | 
				
			||||||
        if shypervisor > dhypervisor:
 | 
					 | 
				
			||||||
            msg = 'Older hypervisor version(%s->%s)' % (shypervisor, dhypervisor)
 | 
					 | 
				
			||||||
            raise exception.Invalid(msg)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # 6. check cpuinfo
 | 
					 | 
				
			||||||
        cpuinfo = shost_ref['cpu_info']
 | 
					 | 
				
			||||||
        if str != type(cpuinfo): 
 | 
					 | 
				
			||||||
            msg = 'Unexpected err: no cpu_info for %s found on DB.hosts' % src
 | 
					 | 
				
			||||||
            raise exception.Invalid(msg)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        logging.warn('cpuinfo %s %d' % (cpuinfo, len(cpuinfo)))
 | 
					 | 
				
			||||||
        ret = rpc.call(context,
 | 
					 | 
				
			||||||
                       db.queue_get_for(context, FLAGS.compute_topic, dest),
 | 
					 | 
				
			||||||
                       {"method": 'compareCPU',
 | 
					 | 
				
			||||||
                        "args": {'xml': cpuinfo}})
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if int != type(ret): 
 | 
					 | 
				
			||||||
            raise ret
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if 0 >= ret :
 | 
					 | 
				
			||||||
            msg = '%s doesnt have compatibility to %s(where %s launching at)\n' \
 | 
					 | 
				
			||||||
                % (dest, src, ec2_id)
 | 
					 | 
				
			||||||
            msg += 'result:%d \n' % ret
 | 
					 | 
				
			||||||
            msg += 'Refer to %s'  % \
 | 
					 | 
				
			||||||
                'http://libvirt.org/html/libvirt-libvirt.html#virCPUCompareResult'
 | 
					 | 
				
			||||||
            raise exception.Invalid(msg)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # 7. check dst host still has enough capacities
 | 
					 | 
				
			||||||
        self.has_enough_resource(context, instance_id, dest)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # 8. change instance_state
 | 
					 | 
				
			||||||
        db.instance_set_state(context,
 | 
					 | 
				
			||||||
                              instance_id,
 | 
					 | 
				
			||||||
                              power_state.PAUSED,
 | 
					 | 
				
			||||||
                              'migrating')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # 9. request live migration
 | 
					 | 
				
			||||||
        host = instance_ref['host']
 | 
					 | 
				
			||||||
        rpc.cast(context,
 | 
					 | 
				
			||||||
                 db.queue_get_for(context, FLAGS.compute_topic, host),
 | 
					 | 
				
			||||||
                 {"method": 'live_migration',
 | 
					 | 
				
			||||||
                  "args": {'instance_id': instance_id,
 | 
					 | 
				
			||||||
                             'dest': dest}})
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def has_enough_resource(self, context, instance_id, dest):
 | 
					 | 
				
			||||||
        """ check if destination host has enough resource for live migration"""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # get instance information
 | 
					 | 
				
			||||||
        instance_ref = db.instance_get(context, instance_id)
 | 
					 | 
				
			||||||
        ec2_id = instance_ref['hostname']
 | 
					 | 
				
			||||||
        vcpus = instance_ref['vcpus']
 | 
					 | 
				
			||||||
        mem = instance_ref['memory_mb']
 | 
					 | 
				
			||||||
        hdd = instance_ref['local_gb']
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # get host information
 | 
					 | 
				
			||||||
        host_ref = db.host_get_by_name(context, dest)
 | 
					 | 
				
			||||||
        total_cpu = int(host_ref['vcpus'])
 | 
					 | 
				
			||||||
        total_mem = int(host_ref['memory_mb'])
 | 
					 | 
				
			||||||
        total_hdd = int(host_ref['local_gb'])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        instances_ref = db.instance_get_all_by_host(context, dest)
 | 
					 | 
				
			||||||
        for i_ref in instances_ref:
 | 
					 | 
				
			||||||
            total_cpu -= int(i_ref['vcpus'])
 | 
					 | 
				
			||||||
            total_mem -= int(i_ref['memory_mb'])
 | 
					 | 
				
			||||||
            total_hdd -= int(i_ref['local_gb'])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # check host has enough information
 | 
					 | 
				
			||||||
        logging.debug('host(%s) remains vcpu:%s mem:%s hdd:%s,' %
 | 
					 | 
				
			||||||
                      (dest, total_cpu, total_mem, total_hdd))
 | 
					 | 
				
			||||||
        logging.debug('instance(%s) has vcpu:%s mem:%s hdd:%s,' %
 | 
					 | 
				
			||||||
                      (ec2_id, total_cpu, total_mem, total_hdd))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if total_cpu <= vcpus or total_mem <= mem or total_hdd <= hdd:
 | 
					 | 
				
			||||||
            msg = '%s doesnt have enough resource for %s' % (dest, ec2_id)
 | 
					 | 
				
			||||||
            raise exception.NotEmpty(msg)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        logging.debug('%s has enough resource for %s' % (dest, ec2_id))
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # NOTE (masumotok) : This method should be moved to nova.api.ec2.admin.
 | 
				
			||||||
 | 
					    #                    Based on bear design summit discussion,
 | 
				
			||||||
 | 
					    #                    just put this here for bexar release.
 | 
				
			||||||
    def show_host_resource(self, context, host, *args):
 | 
					    def show_host_resource(self, context, host, *args):
 | 
				
			||||||
        """ show the physical/usage resource given by hosts."""
 | 
					        """ show the physical/usage resource given by hosts."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -191,12 +81,12 @@ class SchedulerManager(manager.Manager):
 | 
				
			|||||||
        except:
 | 
					        except:
 | 
				
			||||||
            raise
 | 
					            raise
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # get physical resource information
 | 
					        # Getting physical resource information
 | 
				
			||||||
        h_resource = {'vcpus': host_ref['vcpus'],
 | 
					        h_resource = {'vcpus': host_ref['vcpus'],
 | 
				
			||||||
                     'memory_mb': host_ref['memory_mb'],
 | 
					                     'memory_mb': host_ref['memory_mb'],
 | 
				
			||||||
                     'local_gb': host_ref['local_gb']}
 | 
					                     'local_gb': host_ref['local_gb']}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # get usage resource information
 | 
					        # Getting usage resource information
 | 
				
			||||||
        u_resource = {}
 | 
					        u_resource = {}
 | 
				
			||||||
        instances_ref = db.instance_get_all_by_host(context, host_ref['name'])
 | 
					        instances_ref = db.instance_get_all_by_host(context, host_ref['name'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -215,8 +105,8 @@ class SchedulerManager(manager.Manager):
 | 
				
			|||||||
            hdd = db.instance_get_disk_sum_by_host_and_project(context,
 | 
					            hdd = db.instance_get_disk_sum_by_host_and_project(context,
 | 
				
			||||||
                                                               host,
 | 
					                                                               host,
 | 
				
			||||||
                                                               p_id)
 | 
					                                                               p_id)
 | 
				
			||||||
            u_resource[p_id] = {'vcpus': vcpus, 
 | 
					            u_resource[p_id] = {'vcpus': vcpus,
 | 
				
			||||||
                                'memory_mb': mem, 
 | 
					                                'memory_mb': mem,
 | 
				
			||||||
                                'local_gb': hdd}
 | 
					                                'local_gb': hdd}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return {'ret': True, 'phy_resource': h_resource, 'usage': u_resource}
 | 
					        return {'ret': True, 'phy_resource': h_resource, 'usage': u_resource}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -47,7 +47,7 @@ class SimpleScheduler(chance.ChanceScheduler):
 | 
				
			|||||||
        for result in results:
 | 
					        for result in results:
 | 
				
			||||||
            (service, instance_cores) = result
 | 
					            (service, instance_cores) = result
 | 
				
			||||||
            if instance_cores + instance_ref['vcpus'] > FLAGS.max_cores:
 | 
					            if instance_cores + instance_ref['vcpus'] > FLAGS.max_cores:
 | 
				
			||||||
                raise driver.NoValidHost("All hosts have too many cores")
 | 
					                raise driver.NoValidHost(_("All hosts have too many cores"))
 | 
				
			||||||
            if self.service_is_up(service):
 | 
					            if self.service_is_up(service):
 | 
				
			||||||
                # NOTE(vish): this probably belongs in the manager, if we
 | 
					                # NOTE(vish): this probably belongs in the manager, if we
 | 
				
			||||||
                #             can generalize this somehow
 | 
					                #             can generalize this somehow
 | 
				
			||||||
@@ -57,7 +57,7 @@ class SimpleScheduler(chance.ChanceScheduler):
 | 
				
			|||||||
                                   {'host': service['host'],
 | 
					                                   {'host': service['host'],
 | 
				
			||||||
                                    'scheduled_at': now})
 | 
					                                    'scheduled_at': now})
 | 
				
			||||||
                return service['host']
 | 
					                return service['host']
 | 
				
			||||||
        raise driver.NoValidHost("No hosts found")
 | 
					        raise driver.NoValidHost(_("No hosts found"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def schedule_create_volume(self, context, volume_id, *_args, **_kwargs):
 | 
					    def schedule_create_volume(self, context, volume_id, *_args, **_kwargs):
 | 
				
			||||||
        """Picks a host that is up and has the fewest volumes."""
 | 
					        """Picks a host that is up and has the fewest volumes."""
 | 
				
			||||||
@@ -66,7 +66,8 @@ class SimpleScheduler(chance.ChanceScheduler):
 | 
				
			|||||||
        for result in results:
 | 
					        for result in results:
 | 
				
			||||||
            (service, volume_gigabytes) = result
 | 
					            (service, volume_gigabytes) = result
 | 
				
			||||||
            if volume_gigabytes + volume_ref['size'] > FLAGS.max_gigabytes:
 | 
					            if volume_gigabytes + volume_ref['size'] > FLAGS.max_gigabytes:
 | 
				
			||||||
                raise driver.NoValidHost("All hosts have too many gigabytes")
 | 
					                raise driver.NoValidHost(_("All hosts have too many "
 | 
				
			||||||
 | 
					                                           "gigabytes"))
 | 
				
			||||||
            if self.service_is_up(service):
 | 
					            if self.service_is_up(service):
 | 
				
			||||||
                # NOTE(vish): this probably belongs in the manager, if we
 | 
					                # NOTE(vish): this probably belongs in the manager, if we
 | 
				
			||||||
                #             can generalize this somehow
 | 
					                #             can generalize this somehow
 | 
				
			||||||
@@ -76,7 +77,7 @@ class SimpleScheduler(chance.ChanceScheduler):
 | 
				
			|||||||
                                 {'host': service['host'],
 | 
					                                 {'host': service['host'],
 | 
				
			||||||
                                  'scheduled_at': now})
 | 
					                                  'scheduled_at': now})
 | 
				
			||||||
                return service['host']
 | 
					                return service['host']
 | 
				
			||||||
        raise driver.NoValidHost("No hosts found")
 | 
					        raise driver.NoValidHost(_("No hosts found"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def schedule_set_network_host(self, context, *_args, **_kwargs):
 | 
					    def schedule_set_network_host(self, context, *_args, **_kwargs):
 | 
				
			||||||
        """Picks a host that is up and has the fewest networks."""
 | 
					        """Picks a host that is up and has the fewest networks."""
 | 
				
			||||||
@@ -85,7 +86,7 @@ class SimpleScheduler(chance.ChanceScheduler):
 | 
				
			|||||||
        for result in results:
 | 
					        for result in results:
 | 
				
			||||||
            (service, instance_count) = result
 | 
					            (service, instance_count) = result
 | 
				
			||||||
            if instance_count >= FLAGS.max_networks:
 | 
					            if instance_count >= FLAGS.max_networks:
 | 
				
			||||||
                raise driver.NoValidHost("All hosts have too many networks")
 | 
					                raise driver.NoValidHost(_("All hosts have too many networks"))
 | 
				
			||||||
            if self.service_is_up(service):
 | 
					            if self.service_is_up(service):
 | 
				
			||||||
                return service['host']
 | 
					                return service['host']
 | 
				
			||||||
        raise driver.NoValidHost("No hosts found")
 | 
					        raise driver.NoValidHost(_("No hosts found"))
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										151
									
								
								nova/server.py
									
									
									
									
									
								
							
							
						
						
									
										151
									
								
								nova/server.py
									
									
									
									
									
								
							@@ -1,151 +0,0 @@
 | 
				
			|||||||
# 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.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
"""
 | 
					 | 
				
			||||||
Base functionality for nova daemons - gradually being replaced with twistd.py.
 | 
					 | 
				
			||||||
"""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import daemon
 | 
					 | 
				
			||||||
from daemon import pidlockfile
 | 
					 | 
				
			||||||
import logging
 | 
					 | 
				
			||||||
import logging.handlers
 | 
					 | 
				
			||||||
import os
 | 
					 | 
				
			||||||
import signal
 | 
					 | 
				
			||||||
import sys
 | 
					 | 
				
			||||||
import time
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from nova import flags
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
FLAGS = flags.FLAGS
 | 
					 | 
				
			||||||
flags.DEFINE_bool('daemonize', False, 'daemonize this process')
 | 
					 | 
				
			||||||
# NOTE(termie): right now I am defaulting to using syslog when we daemonize
 | 
					 | 
				
			||||||
#               it may be better to do something else -shrug-
 | 
					 | 
				
			||||||
# NOTE(Devin): I think we should let each process have its own log file
 | 
					 | 
				
			||||||
#              and put it in /var/logs/nova/(appname).log
 | 
					 | 
				
			||||||
#              This makes debugging much easier and cuts down on sys log
 | 
					 | 
				
			||||||
#              clutter.
 | 
					 | 
				
			||||||
flags.DEFINE_bool('use_syslog', True, 'output to syslog when daemonizing')
 | 
					 | 
				
			||||||
flags.DEFINE_string('logfile', None, 'log file to output to')
 | 
					 | 
				
			||||||
flags.DEFINE_string('logdir',  None, 'directory to keep log files in '
 | 
					 | 
				
			||||||
                                     '(will be prepended to $logfile)')
 | 
					 | 
				
			||||||
flags.DEFINE_string('pidfile', None, 'pid file to output to')
 | 
					 | 
				
			||||||
flags.DEFINE_string('working_directory', './', 'working directory...')
 | 
					 | 
				
			||||||
flags.DEFINE_integer('uid', os.getuid(), 'uid under which to run')
 | 
					 | 
				
			||||||
flags.DEFINE_integer('gid', os.getgid(), 'gid under which to run')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def stop(pidfile):
 | 
					 | 
				
			||||||
    """
 | 
					 | 
				
			||||||
    Stop the daemon
 | 
					 | 
				
			||||||
    """
 | 
					 | 
				
			||||||
    # Get the pid from the pidfile
 | 
					 | 
				
			||||||
    try:
 | 
					 | 
				
			||||||
        pid = int(open(pidfile, 'r').read().strip())
 | 
					 | 
				
			||||||
    except IOError:
 | 
					 | 
				
			||||||
        message = "pidfile %s does not exist. Daemon not running?\n"
 | 
					 | 
				
			||||||
        sys.stderr.write(message % pidfile)
 | 
					 | 
				
			||||||
        return
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    # Try killing the daemon process
 | 
					 | 
				
			||||||
    try:
 | 
					 | 
				
			||||||
        while 1:
 | 
					 | 
				
			||||||
            os.kill(pid, signal.SIGTERM)
 | 
					 | 
				
			||||||
            time.sleep(0.1)
 | 
					 | 
				
			||||||
    except OSError, err:
 | 
					 | 
				
			||||||
        err = str(err)
 | 
					 | 
				
			||||||
        if err.find("No such process") > 0:
 | 
					 | 
				
			||||||
            if os.path.exists(pidfile):
 | 
					 | 
				
			||||||
                os.remove(pidfile)
 | 
					 | 
				
			||||||
        else:
 | 
					 | 
				
			||||||
            print str(err)
 | 
					 | 
				
			||||||
            sys.exit(1)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def serve(name, main):
 | 
					 | 
				
			||||||
    """Controller for server"""
 | 
					 | 
				
			||||||
    argv = FLAGS(sys.argv)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if not FLAGS.pidfile:
 | 
					 | 
				
			||||||
        FLAGS.pidfile = '%s.pid' % name
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    logging.debug("Full set of FLAGS: \n\n\n")
 | 
					 | 
				
			||||||
    for flag in FLAGS:
 | 
					 | 
				
			||||||
        logging.debug("%s : %s", flag, FLAGS.get(flag, None))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    action = 'start'
 | 
					 | 
				
			||||||
    if len(argv) > 1:
 | 
					 | 
				
			||||||
        action = argv.pop()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if action == 'stop':
 | 
					 | 
				
			||||||
        stop(FLAGS.pidfile)
 | 
					 | 
				
			||||||
        sys.exit()
 | 
					 | 
				
			||||||
    elif action == 'restart':
 | 
					 | 
				
			||||||
        stop(FLAGS.pidfile)
 | 
					 | 
				
			||||||
    elif action == 'start':
 | 
					 | 
				
			||||||
        pass
 | 
					 | 
				
			||||||
    else:
 | 
					 | 
				
			||||||
        print 'usage: %s [options] [start|stop|restart]' % argv[0]
 | 
					 | 
				
			||||||
        sys.exit(1)
 | 
					 | 
				
			||||||
    daemonize(argv, 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(
 | 
					 | 
				
			||||||
                name + '(%(name)s): %(levelname)s %(message)s')
 | 
					 | 
				
			||||||
        if FLAGS.use_syslog and not FLAGS.logfile:
 | 
					 | 
				
			||||||
            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
 | 
					 | 
				
			||||||
            if FLAGS.logdir:
 | 
					 | 
				
			||||||
                FLAGS.logfile = os.path.join(FLAGS.logdir, FLAGS.logfile)
 | 
					 | 
				
			||||||
            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
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if FLAGS.verbose:
 | 
					 | 
				
			||||||
        logging.getLogger().setLevel(logging.DEBUG)
 | 
					 | 
				
			||||||
    else:
 | 
					 | 
				
			||||||
        logging.getLogger().setLevel(logging.WARNING)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    with daemon.DaemonContext(
 | 
					 | 
				
			||||||
            detach_process=FLAGS.daemonize,
 | 
					 | 
				
			||||||
            working_directory=FLAGS.working_directory,
 | 
					 | 
				
			||||||
            pidfile=pidlockfile.TimeoutPIDLockFile(FLAGS.pidfile,
 | 
					 | 
				
			||||||
                                                   acquire_timeout=1,
 | 
					 | 
				
			||||||
                                                   threaded=False),
 | 
					 | 
				
			||||||
            stdin=stdin,
 | 
					 | 
				
			||||||
            stdout=stdout,
 | 
					 | 
				
			||||||
            stderr=stderr,
 | 
					 | 
				
			||||||
            uid=FLAGS.uid,
 | 
					 | 
				
			||||||
            gid=FLAGS.gid,
 | 
					 | 
				
			||||||
            files_preserve=files_to_keep):
 | 
					 | 
				
			||||||
        main(args)
 | 
					 | 
				
			||||||
							
								
								
									
										107
									
								
								nova/service.py
									
									
									
									
									
								
							
							
						
						
									
										107
									
								
								nova/service.py
									
									
									
									
									
								
							@@ -17,21 +17,17 @@
 | 
				
			|||||||
#    under the License.
 | 
					#    under the License.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
"""
 | 
					"""
 | 
				
			||||||
A service is a very thin wrapper around a Manager object.  It exposes the
 | 
					Generic Node baseclass for all workers that run on hosts
 | 
				
			||||||
manager's public methods to other components of the system via rpc.  It will
 | 
					 | 
				
			||||||
report state periodically to the database and is responsible for initiating
 | 
					 | 
				
			||||||
any periodic tasts that need to be executed on a given host.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
This module contains Service, a generic baseclass for all workers.
 | 
					 | 
				
			||||||
"""
 | 
					"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import inspect
 | 
					import inspect
 | 
				
			||||||
import logging
 | 
					import logging
 | 
				
			||||||
import os
 | 
					import os
 | 
				
			||||||
 | 
					import sys
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from twisted.internet import defer
 | 
					from eventlet import event
 | 
				
			||||||
from twisted.internet import task
 | 
					from eventlet import greenthread
 | 
				
			||||||
from twisted.application import service
 | 
					from eventlet import greenpool
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from nova import context
 | 
					from nova import context
 | 
				
			||||||
from nova import db
 | 
					from nova import db
 | 
				
			||||||
@@ -50,8 +46,16 @@ flags.DEFINE_integer('periodic_interval', 60,
 | 
				
			|||||||
                     'seconds between running periodic tasks',
 | 
					                     'seconds between running periodic tasks',
 | 
				
			||||||
                     lower_bound=1)
 | 
					                     lower_bound=1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					flags.DEFINE_string('pidfile', None,
 | 
				
			||||||
 | 
					                    'pidfile to use for this service')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Service(object, service.Service):
 | 
					
 | 
				
			||||||
 | 
					flags.DEFINE_flag(flags.HelpFlag())
 | 
				
			||||||
 | 
					flags.DEFINE_flag(flags.HelpshortFlag())
 | 
				
			||||||
 | 
					flags.DEFINE_flag(flags.HelpXMLFlag())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Service(object):
 | 
				
			||||||
    """Base class for workers that run on hosts."""
 | 
					    """Base class for workers that run on hosts."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __init__(self, host, binary, topic, manager, report_interval=None,
 | 
					    def __init__(self, host, binary, topic, manager, report_interval=None,
 | 
				
			||||||
@@ -64,8 +68,9 @@ class Service(object, service.Service):
 | 
				
			|||||||
        self.periodic_interval = periodic_interval
 | 
					        self.periodic_interval = periodic_interval
 | 
				
			||||||
        super(Service, self).__init__(*args, **kwargs)
 | 
					        super(Service, self).__init__(*args, **kwargs)
 | 
				
			||||||
        self.saved_args, self.saved_kwargs = args, kwargs
 | 
					        self.saved_args, self.saved_kwargs = args, kwargs
 | 
				
			||||||
 | 
					        self.timers = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def startService(self):  # pylint: disable-msg C0103
 | 
					    def start(self):
 | 
				
			||||||
        manager_class = utils.import_class(self.manager_class_name)
 | 
					        manager_class = utils.import_class(self.manager_class_name)
 | 
				
			||||||
        self.manager = manager_class(host=self.host, *self.saved_args,
 | 
					        self.manager = manager_class(host=self.host, *self.saved_args,
 | 
				
			||||||
                                                     **self.saved_kwargs)
 | 
					                                                     **self.saved_kwargs)
 | 
				
			||||||
@@ -87,26 +92,29 @@ class Service(object, service.Service):
 | 
				
			|||||||
        except exception.NotFound:
 | 
					        except exception.NotFound:
 | 
				
			||||||
            self._create_service_ref(ctxt)
 | 
					            self._create_service_ref(ctxt)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        conn = rpc.Connection.instance()
 | 
					        conn1 = rpc.Connection.instance(new=True)
 | 
				
			||||||
 | 
					        conn2 = rpc.Connection.instance(new=True)
 | 
				
			||||||
        if self.report_interval:
 | 
					        if self.report_interval:
 | 
				
			||||||
            consumer_all = rpc.AdapterConsumer(
 | 
					            consumer_all = rpc.AdapterConsumer(
 | 
				
			||||||
                    connection=conn,
 | 
					                    connection=conn1,
 | 
				
			||||||
                    topic=self.topic,
 | 
					                    topic=self.topic,
 | 
				
			||||||
                    proxy=self)
 | 
					                    proxy=self)
 | 
				
			||||||
            consumer_node = rpc.AdapterConsumer(
 | 
					            consumer_node = rpc.AdapterConsumer(
 | 
				
			||||||
                    connection=conn,
 | 
					                    connection=conn2,
 | 
				
			||||||
                    topic='%s.%s' % (self.topic, self.host),
 | 
					                    topic='%s.%s' % (self.topic, self.host),
 | 
				
			||||||
                    proxy=self)
 | 
					                    proxy=self)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            consumer_all.attach_to_twisted()
 | 
					            self.timers.append(consumer_all.attach_to_eventlet())
 | 
				
			||||||
            consumer_node.attach_to_twisted()
 | 
					            self.timers.append(consumer_node.attach_to_eventlet())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            pulse = task.LoopingCall(self.report_state)
 | 
					            pulse = utils.LoopingCall(self.report_state)
 | 
				
			||||||
            pulse.start(interval=self.report_interval, now=False)
 | 
					            pulse.start(interval=self.report_interval, now=False)
 | 
				
			||||||
 | 
					            self.timers.append(pulse)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if self.periodic_interval:
 | 
					        if self.periodic_interval:
 | 
				
			||||||
            pulse = task.LoopingCall(self.periodic_tasks)
 | 
					            periodic = utils.LoopingCall(self.periodic_tasks)
 | 
				
			||||||
            pulse.start(interval=self.periodic_interval, now=False)
 | 
					            periodic.start(interval=self.periodic_interval, now=False)
 | 
				
			||||||
 | 
					            self.timers.append(periodic)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def _create_service_ref(self, context):
 | 
					    def _create_service_ref(self, context):
 | 
				
			||||||
        service_ref = db.service_create(context,
 | 
					        service_ref = db.service_create(context,
 | 
				
			||||||
@@ -170,29 +178,32 @@ class Service(object, service.Service):
 | 
				
			|||||||
            report_interval = FLAGS.report_interval
 | 
					            report_interval = FLAGS.report_interval
 | 
				
			||||||
        if not periodic_interval:
 | 
					        if not periodic_interval:
 | 
				
			||||||
            periodic_interval = FLAGS.periodic_interval
 | 
					            periodic_interval = FLAGS.periodic_interval
 | 
				
			||||||
        logging.warn("Starting %s node", topic)
 | 
					        logging.warn(_("Starting %s node"), topic)
 | 
				
			||||||
        service_obj = cls(host, binary, topic, manager,
 | 
					        service_obj = cls(host, binary, topic, manager,
 | 
				
			||||||
                          report_interval, periodic_interval)
 | 
					                          report_interval, periodic_interval)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # This is the parent service that twistd will be looking for when it
 | 
					        return service_obj
 | 
				
			||||||
        # parses this file, return it so that we can get it into globals.
 | 
					 | 
				
			||||||
        application = service.Application(binary)
 | 
					 | 
				
			||||||
        service_obj.setServiceParent(application)
 | 
					 | 
				
			||||||
        return application
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def kill(self):
 | 
					    def kill(self):
 | 
				
			||||||
        """Destroy the service object in the datastore"""
 | 
					        """Destroy the service object in the datastore"""
 | 
				
			||||||
 | 
					        self.stop()
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
            db.service_destroy(context.get_admin_context(), self.service_id)
 | 
					            db.service_destroy(context.get_admin_context(), self.service_id)
 | 
				
			||||||
        except exception.NotFound:
 | 
					        except exception.NotFound:
 | 
				
			||||||
            logging.warn("Service killed that has no database entry")
 | 
					            logging.warn(_("Service killed that has no database entry"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def stop(self):
 | 
				
			||||||
 | 
					        for x in self.timers:
 | 
				
			||||||
 | 
					            try:
 | 
				
			||||||
 | 
					                x.stop()
 | 
				
			||||||
 | 
					            except Exception:
 | 
				
			||||||
 | 
					                pass
 | 
				
			||||||
 | 
					        self.timers = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @defer.inlineCallbacks
 | 
					 | 
				
			||||||
    def periodic_tasks(self):
 | 
					    def periodic_tasks(self):
 | 
				
			||||||
        """Tasks to be run at a periodic interval"""
 | 
					        """Tasks to be run at a periodic interval"""
 | 
				
			||||||
        yield self.manager.periodic_tasks(context.get_admin_context())
 | 
					        self.manager.periodic_tasks(context.get_admin_context())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @defer.inlineCallbacks
 | 
					 | 
				
			||||||
    def report_state(self):
 | 
					    def report_state(self):
 | 
				
			||||||
        """Update the state of this service in the datastore."""
 | 
					        """Update the state of this service in the datastore."""
 | 
				
			||||||
        ctxt = context.get_admin_context()
 | 
					        ctxt = context.get_admin_context()
 | 
				
			||||||
@@ -200,8 +211,8 @@ class Service(object, service.Service):
 | 
				
			|||||||
            try:
 | 
					            try:
 | 
				
			||||||
                service_ref = db.service_get(ctxt, self.service_id)
 | 
					                service_ref = db.service_get(ctxt, self.service_id)
 | 
				
			||||||
            except exception.NotFound:
 | 
					            except exception.NotFound:
 | 
				
			||||||
                logging.debug("The service database object disappeared, "
 | 
					                logging.debug(_("The service database object disappeared, "
 | 
				
			||||||
                              "Recreating it.")
 | 
					                                "Recreating it."))
 | 
				
			||||||
                self._create_service_ref(ctxt)
 | 
					                self._create_service_ref(ctxt)
 | 
				
			||||||
                service_ref = db.service_get(ctxt, self.service_id)
 | 
					                service_ref = db.service_get(ctxt, self.service_id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -212,11 +223,39 @@ class Service(object, service.Service):
 | 
				
			|||||||
            # TODO(termie): make this pattern be more elegant.
 | 
					            # TODO(termie): make this pattern be more elegant.
 | 
				
			||||||
            if getattr(self, "model_disconnected", False):
 | 
					            if getattr(self, "model_disconnected", False):
 | 
				
			||||||
                self.model_disconnected = False
 | 
					                self.model_disconnected = False
 | 
				
			||||||
                logging.error("Recovered model server connection!")
 | 
					                logging.error(_("Recovered model server connection!"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # TODO(vish): this should probably only catch connection errors
 | 
					        # TODO(vish): this should probably only catch connection errors
 | 
				
			||||||
        except Exception:  # pylint: disable-msg=W0702
 | 
					        except Exception:  # pylint: disable-msg=W0702
 | 
				
			||||||
            if not getattr(self, "model_disconnected", False):
 | 
					            if not getattr(self, "model_disconnected", False):
 | 
				
			||||||
                self.model_disconnected = True
 | 
					                self.model_disconnected = True
 | 
				
			||||||
                logging.exception("model server went away")
 | 
					                logging.exception(_("model server went away"))
 | 
				
			||||||
        yield
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def serve(*services):
 | 
				
			||||||
 | 
					    argv = FLAGS(sys.argv)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if not services:
 | 
				
			||||||
 | 
					        services = [Service.create()]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    name = '_'.join(x.binary for x in services)
 | 
				
			||||||
 | 
					    logging.debug("Serving %s" % name)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    logging.getLogger('amqplib').setLevel(logging.WARN)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if FLAGS.verbose:
 | 
				
			||||||
 | 
					        logging.getLogger().setLevel(logging.DEBUG)
 | 
				
			||||||
 | 
					    else:
 | 
				
			||||||
 | 
					        logging.getLogger().setLevel(logging.WARNING)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    logging.debug(_("Full set of FLAGS:"))
 | 
				
			||||||
 | 
					    for flag in FLAGS:
 | 
				
			||||||
 | 
					        logging.debug("%s : %s" % (flag, FLAGS.get(flag, None)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for x in services:
 | 
				
			||||||
 | 
					        x.start()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def wait():
 | 
				
			||||||
 | 
					    while True:
 | 
				
			||||||
 | 
					        greenthread.sleep(5)
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										222
									
								
								nova/service.py.THIS
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										222
									
								
								nova/service.py.THIS
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,222 @@
 | 
				
			|||||||
 | 
					# 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.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					A service is a very thin wrapper around a Manager object.  It exposes the
 | 
				
			||||||
 | 
					manager's public methods to other components of the system via rpc.  It will
 | 
				
			||||||
 | 
					report state periodically to the database and is responsible for initiating
 | 
				
			||||||
 | 
					any periodic tasts that need to be executed on a given host.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This module contains Service, a generic baseclass for all workers.
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import inspect
 | 
				
			||||||
 | 
					import logging
 | 
				
			||||||
 | 
					import os
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from twisted.internet import defer
 | 
				
			||||||
 | 
					from twisted.internet import task
 | 
				
			||||||
 | 
					from twisted.application import service
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from nova import context
 | 
				
			||||||
 | 
					from nova import db
 | 
				
			||||||
 | 
					from nova import exception
 | 
				
			||||||
 | 
					from nova import flags
 | 
				
			||||||
 | 
					from nova import rpc
 | 
				
			||||||
 | 
					from nova import utils
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					FLAGS = flags.FLAGS
 | 
				
			||||||
 | 
					flags.DEFINE_integer('report_interval', 10,
 | 
				
			||||||
 | 
					                     'seconds between nodes reporting state to datastore',
 | 
				
			||||||
 | 
					                     lower_bound=1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					flags.DEFINE_integer('periodic_interval', 60,
 | 
				
			||||||
 | 
					                     'seconds between running periodic tasks',
 | 
				
			||||||
 | 
					                     lower_bound=1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Service(object, service.Service):
 | 
				
			||||||
 | 
					    """Base class for workers that run on hosts."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, host, binary, topic, manager, report_interval=None,
 | 
				
			||||||
 | 
					                 periodic_interval=None, *args, **kwargs):
 | 
				
			||||||
 | 
					        self.host = host
 | 
				
			||||||
 | 
					        self.binary = binary
 | 
				
			||||||
 | 
					        self.topic = topic
 | 
				
			||||||
 | 
					        self.manager_class_name = manager
 | 
				
			||||||
 | 
					        self.report_interval = report_interval
 | 
				
			||||||
 | 
					        self.periodic_interval = periodic_interval
 | 
				
			||||||
 | 
					        super(Service, self).__init__(*args, **kwargs)
 | 
				
			||||||
 | 
					        self.saved_args, self.saved_kwargs = args, kwargs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def startService(self):  # pylint: disable-msg C0103
 | 
				
			||||||
 | 
					        manager_class = utils.import_class(self.manager_class_name)
 | 
				
			||||||
 | 
					        self.manager = manager_class(host=self.host, *self.saved_args,
 | 
				
			||||||
 | 
					                                                     **self.saved_kwargs)
 | 
				
			||||||
 | 
					        self.manager.init_host()
 | 
				
			||||||
 | 
					        self.model_disconnected = False
 | 
				
			||||||
 | 
					        ctxt = context.get_admin_context()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            host_ref = db.host_get_by_name(ctxt, self.host)
 | 
				
			||||||
 | 
					        except exception.NotFound:
 | 
				
			||||||
 | 
					            host_ref = db.host_create(ctxt, {'name': self.host})
 | 
				
			||||||
 | 
					        host_ref = self._update_host_ref(ctxt, host_ref)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            service_ref = db.service_get_by_args(ctxt,
 | 
				
			||||||
 | 
					                                                 self.host,
 | 
				
			||||||
 | 
					                                                 self.binary)
 | 
				
			||||||
 | 
					            self.service_id = service_ref['id']
 | 
				
			||||||
 | 
					        except exception.NotFound:
 | 
				
			||||||
 | 
					            self._create_service_ref(ctxt)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        conn = rpc.Connection.instance()
 | 
				
			||||||
 | 
					        if self.report_interval:
 | 
				
			||||||
 | 
					            consumer_all = rpc.AdapterConsumer(
 | 
				
			||||||
 | 
					                    connection=conn,
 | 
				
			||||||
 | 
					                    topic=self.topic,
 | 
				
			||||||
 | 
					                    proxy=self)
 | 
				
			||||||
 | 
					            consumer_node = rpc.AdapterConsumer(
 | 
				
			||||||
 | 
					                    connection=conn,
 | 
				
			||||||
 | 
					                    topic='%s.%s' % (self.topic, self.host),
 | 
				
			||||||
 | 
					                    proxy=self)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            consumer_all.attach_to_twisted()
 | 
				
			||||||
 | 
					            consumer_node.attach_to_twisted()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            pulse = task.LoopingCall(self.report_state)
 | 
				
			||||||
 | 
					            pulse.start(interval=self.report_interval, now=False)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if self.periodic_interval:
 | 
				
			||||||
 | 
					            pulse = task.LoopingCall(self.periodic_tasks)
 | 
				
			||||||
 | 
					            pulse.start(interval=self.periodic_interval, now=False)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _create_service_ref(self, context):
 | 
				
			||||||
 | 
					        service_ref = db.service_create(context,
 | 
				
			||||||
 | 
					                                        {'host': self.host,
 | 
				
			||||||
 | 
					                                         'binary': self.binary,
 | 
				
			||||||
 | 
					                                         'topic': self.topic,
 | 
				
			||||||
 | 
					                                         'report_count': 0})
 | 
				
			||||||
 | 
					        self.service_id = service_ref['id']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _update_host_ref(self, context, host_ref):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if 0 <= self.manager_class_name.find('ComputeManager'):
 | 
				
			||||||
 | 
					            vcpu = self.manager.driver.get_vcpu_number()
 | 
				
			||||||
 | 
					            memory_mb = self.manager.get_memory_mb()
 | 
				
			||||||
 | 
					            local_gb = self.manager.get_local_gb()
 | 
				
			||||||
 | 
					            hypervisor = self.manager.driver.get_hypervisor_type()
 | 
				
			||||||
 | 
					            version = self.manager.driver.get_hypervisor_version()
 | 
				
			||||||
 | 
					            cpu_xml = self.manager.driver.get_cpu_xml()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            db.host_update(context,
 | 
				
			||||||
 | 
					                           host_ref['id'],
 | 
				
			||||||
 | 
					                           {'vcpus': vcpu,
 | 
				
			||||||
 | 
					                           'memory_mb': memory_mb,
 | 
				
			||||||
 | 
					                           'local_gb': local_gb,
 | 
				
			||||||
 | 
					                           'hypervisor_type': hypervisor,
 | 
				
			||||||
 | 
					                           'hypervisor_version': version,
 | 
				
			||||||
 | 
					                           'cpu_info':cpu_xml })
 | 
				
			||||||
 | 
					        return host_ref
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __getattr__(self, key):
 | 
				
			||||||
 | 
					        manager = self.__dict__.get('manager', None)
 | 
				
			||||||
 | 
					        return getattr(manager, key)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @classmethod
 | 
				
			||||||
 | 
					    def create(cls,
 | 
				
			||||||
 | 
					               host=None,
 | 
				
			||||||
 | 
					               binary=None,
 | 
				
			||||||
 | 
					               topic=None,
 | 
				
			||||||
 | 
					               manager=None,
 | 
				
			||||||
 | 
					               report_interval=None,
 | 
				
			||||||
 | 
					               periodic_interval=None):
 | 
				
			||||||
 | 
					        """Instantiates class and passes back application object.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Args:
 | 
				
			||||||
 | 
					            host, defaults to FLAGS.host
 | 
				
			||||||
 | 
					            binary, defaults to basename of executable
 | 
				
			||||||
 | 
					            topic, defaults to bin_name - "nova-" part
 | 
				
			||||||
 | 
					            manager, defaults to FLAGS.<topic>_manager
 | 
				
			||||||
 | 
					            report_interval, defaults to FLAGS.report_interval
 | 
				
			||||||
 | 
					            periodic_interval, defaults to FLAGS.periodic_interval
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        if not host:
 | 
				
			||||||
 | 
					            host = FLAGS.host
 | 
				
			||||||
 | 
					        if not binary:
 | 
				
			||||||
 | 
					            binary = os.path.basename(inspect.stack()[-1][1])
 | 
				
			||||||
 | 
					        if not topic:
 | 
				
			||||||
 | 
					            topic = binary.rpartition("nova-")[2]
 | 
				
			||||||
 | 
					        if not manager:
 | 
				
			||||||
 | 
					            manager = FLAGS.get('%s_manager' % topic, None)
 | 
				
			||||||
 | 
					        if not report_interval:
 | 
				
			||||||
 | 
					            report_interval = FLAGS.report_interval
 | 
				
			||||||
 | 
					        if not periodic_interval:
 | 
				
			||||||
 | 
					            periodic_interval = FLAGS.periodic_interval
 | 
				
			||||||
 | 
					        logging.warn("Starting %s node", topic)
 | 
				
			||||||
 | 
					        service_obj = cls(host, binary, topic, manager,
 | 
				
			||||||
 | 
					                          report_interval, periodic_interval)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # This is the parent service that twistd will be looking for when it
 | 
				
			||||||
 | 
					        # parses this file, return it so that we can get it into globals.
 | 
				
			||||||
 | 
					        application = service.Application(binary)
 | 
				
			||||||
 | 
					        service_obj.setServiceParent(application)
 | 
				
			||||||
 | 
					        return application
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def kill(self):
 | 
				
			||||||
 | 
					        """Destroy the service object in the datastore"""
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            db.service_destroy(context.get_admin_context(), self.service_id)
 | 
				
			||||||
 | 
					        except exception.NotFound:
 | 
				
			||||||
 | 
					            logging.warn("Service killed that has no database entry")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @defer.inlineCallbacks
 | 
				
			||||||
 | 
					    def periodic_tasks(self):
 | 
				
			||||||
 | 
					        """Tasks to be run at a periodic interval"""
 | 
				
			||||||
 | 
					        yield self.manager.periodic_tasks(context.get_admin_context())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @defer.inlineCallbacks
 | 
				
			||||||
 | 
					    def report_state(self):
 | 
				
			||||||
 | 
					        """Update the state of this service in the datastore."""
 | 
				
			||||||
 | 
					        ctxt = context.get_admin_context()
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            try:
 | 
				
			||||||
 | 
					                service_ref = db.service_get(ctxt, self.service_id)
 | 
				
			||||||
 | 
					            except exception.NotFound:
 | 
				
			||||||
 | 
					                logging.debug("The service database object disappeared, "
 | 
				
			||||||
 | 
					                              "Recreating it.")
 | 
				
			||||||
 | 
					                self._create_service_ref(ctxt)
 | 
				
			||||||
 | 
					                service_ref = db.service_get(ctxt, self.service_id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            db.service_update(ctxt,
 | 
				
			||||||
 | 
					                             self.service_id,
 | 
				
			||||||
 | 
					                             {'report_count': service_ref['report_count'] + 1})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            # TODO(termie): make this pattern be more elegant.
 | 
				
			||||||
 | 
					            if getattr(self, "model_disconnected", False):
 | 
				
			||||||
 | 
					                self.model_disconnected = False
 | 
				
			||||||
 | 
					                logging.error("Recovered model server connection!")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # TODO(vish): this should probably only catch connection errors
 | 
				
			||||||
 | 
					        except Exception:  # pylint: disable-msg=W0702
 | 
				
			||||||
 | 
					            if not getattr(self, "model_disconnected", False):
 | 
				
			||||||
 | 
					                self.model_disconnected = True
 | 
				
			||||||
 | 
					                logging.exception("model server went away")
 | 
				
			||||||
 | 
					        yield
 | 
				
			||||||
							
								
								
									
										103
									
								
								nova/test.py
									
									
									
									
									
								
							
							
						
						
									
										103
									
								
								nova/test.py
									
									
									
									
									
								
							@@ -25,11 +25,12 @@ and some black magic for inline callbacks.
 | 
				
			|||||||
import datetime
 | 
					import datetime
 | 
				
			||||||
import sys
 | 
					import sys
 | 
				
			||||||
import time
 | 
					import time
 | 
				
			||||||
 | 
					import unittest
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import mox
 | 
					import mox
 | 
				
			||||||
import stubout
 | 
					import stubout
 | 
				
			||||||
from twisted.internet import defer
 | 
					from twisted.internet import defer
 | 
				
			||||||
from twisted.trial import unittest
 | 
					from twisted.trial import unittest as trial_unittest
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from nova import context
 | 
					from nova import context
 | 
				
			||||||
from nova import db
 | 
					from nova import db
 | 
				
			||||||
@@ -37,9 +38,12 @@ from nova import fakerabbit
 | 
				
			|||||||
from nova import flags
 | 
					from nova import flags
 | 
				
			||||||
from nova import rpc
 | 
					from nova import rpc
 | 
				
			||||||
from nova.network import manager as network_manager
 | 
					from nova.network import manager as network_manager
 | 
				
			||||||
 | 
					from nova.tests import fake_flags
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
FLAGS = flags.FLAGS
 | 
					FLAGS = flags.FLAGS
 | 
				
			||||||
 | 
					flags.DEFINE_bool('flush_db', True,
 | 
				
			||||||
 | 
					                  'Flush the database before running fake tests')
 | 
				
			||||||
flags.DEFINE_bool('fake_tests', True,
 | 
					flags.DEFINE_bool('fake_tests', True,
 | 
				
			||||||
                  'should we use everything for testing')
 | 
					                  'should we use everything for testing')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -55,11 +59,11 @@ def skip_if_fake(func):
 | 
				
			|||||||
    return _skipper
 | 
					    return _skipper
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class TrialTestCase(unittest.TestCase):
 | 
					class TestCase(unittest.TestCase):
 | 
				
			||||||
    """Test case base class for all unit tests"""
 | 
					    """Test case base class for all unit tests"""
 | 
				
			||||||
    def setUp(self):
 | 
					    def setUp(self):
 | 
				
			||||||
        """Run before each test method to initialize test environment"""
 | 
					        """Run before each test method to initialize test environment"""
 | 
				
			||||||
        super(TrialTestCase, self).setUp()
 | 
					        super(TestCase, self).setUp()
 | 
				
			||||||
        # NOTE(vish): We need a better method for creating fixtures for tests
 | 
					        # NOTE(vish): We need a better method for creating fixtures for tests
 | 
				
			||||||
        #             now that we have some required db setup for the system
 | 
					        #             now that we have some required db setup for the system
 | 
				
			||||||
        #             to work properly.
 | 
					        #             to work properly.
 | 
				
			||||||
@@ -94,7 +98,87 @@ class TrialTestCase(unittest.TestCase):
 | 
				
			|||||||
            db.fixed_ip_disassociate_all_by_timeout(ctxt, FLAGS.host,
 | 
					            db.fixed_ip_disassociate_all_by_timeout(ctxt, FLAGS.host,
 | 
				
			||||||
                                                    self.start)
 | 
					                                                    self.start)
 | 
				
			||||||
            db.network_disassociate_all(ctxt)
 | 
					            db.network_disassociate_all(ctxt)
 | 
				
			||||||
            rpc.Consumer.attach_to_twisted = self.originalAttach
 | 
					            rpc.Consumer.attach_to_eventlet = self.originalAttach
 | 
				
			||||||
 | 
					            for x in self.injected:
 | 
				
			||||||
 | 
					                try:
 | 
				
			||||||
 | 
					                    x.stop()
 | 
				
			||||||
 | 
					                except AssertionError:
 | 
				
			||||||
 | 
					                    pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if FLAGS.fake_rabbit:
 | 
				
			||||||
 | 
					                fakerabbit.reset_all()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            db.security_group_destroy_all(ctxt)
 | 
				
			||||||
 | 
					            super(TestCase, self).tearDown()
 | 
				
			||||||
 | 
					        finally:
 | 
				
			||||||
 | 
					            self.reset_flags()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def flags(self, **kw):
 | 
				
			||||||
 | 
					        """Override flag variables for a test"""
 | 
				
			||||||
 | 
					        for k, v in kw.iteritems():
 | 
				
			||||||
 | 
					            if k in self.flag_overrides:
 | 
				
			||||||
 | 
					                self.reset_flags()
 | 
				
			||||||
 | 
					                raise Exception(
 | 
				
			||||||
 | 
					                        'trying to override already overriden flag: %s' % k)
 | 
				
			||||||
 | 
					            self.flag_overrides[k] = getattr(FLAGS, k)
 | 
				
			||||||
 | 
					            setattr(FLAGS, k, v)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def reset_flags(self):
 | 
				
			||||||
 | 
					        """Resets all flag variables for the test.  Runs after each test"""
 | 
				
			||||||
 | 
					        FLAGS.Reset()
 | 
				
			||||||
 | 
					        for k, v in self._original_flags.iteritems():
 | 
				
			||||||
 | 
					            setattr(FLAGS, k, v)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _monkey_patch_attach(self):
 | 
				
			||||||
 | 
					        self.originalAttach = rpc.Consumer.attach_to_eventlet
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        def _wrapped(innerSelf):
 | 
				
			||||||
 | 
					            rv = self.originalAttach(innerSelf)
 | 
				
			||||||
 | 
					            self.injected.append(rv)
 | 
				
			||||||
 | 
					            return rv
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        _wrapped.func_name = self.originalAttach.func_name
 | 
				
			||||||
 | 
					        rpc.Consumer.attach_to_eventlet = _wrapped
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class TrialTestCase(trial_unittest.TestCase):
 | 
				
			||||||
 | 
					    """Test case base class for all unit tests"""
 | 
				
			||||||
 | 
					    def setUp(self):
 | 
				
			||||||
 | 
					        """Run before each test method to initialize test environment"""
 | 
				
			||||||
 | 
					        super(TrialTestCase, self).setUp()
 | 
				
			||||||
 | 
					        # NOTE(vish): We need a better method for creating fixtures for tests
 | 
				
			||||||
 | 
					        #             now that we have some required db setup for the system
 | 
				
			||||||
 | 
					        #             to work properly.
 | 
				
			||||||
 | 
					        self.start = datetime.datetime.utcnow()
 | 
				
			||||||
 | 
					        ctxt = context.get_admin_context()
 | 
				
			||||||
 | 
					        if db.network_count(ctxt) != 5:
 | 
				
			||||||
 | 
					            network_manager.VlanManager().create_networks(ctxt,
 | 
				
			||||||
 | 
					                                                          FLAGS.fixed_range,
 | 
				
			||||||
 | 
					                                                          5, 16,
 | 
				
			||||||
 | 
					                                                          FLAGS.vlan_start,
 | 
				
			||||||
 | 
					                                                          FLAGS.vpn_start)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # emulate some of the mox stuff, we can't use the metaclass
 | 
				
			||||||
 | 
					        # because it screws with our generators
 | 
				
			||||||
 | 
					        self.mox = mox.Mox()
 | 
				
			||||||
 | 
					        self.stubs = stubout.StubOutForTesting()
 | 
				
			||||||
 | 
					        self.flag_overrides = {}
 | 
				
			||||||
 | 
					        self.injected = []
 | 
				
			||||||
 | 
					        self._original_flags = FLAGS.FlagValuesDict()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def tearDown(self):
 | 
				
			||||||
 | 
					        """Runs after each test method to finalize/tear down test
 | 
				
			||||||
 | 
					        environment."""
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            self.mox.UnsetStubs()
 | 
				
			||||||
 | 
					            self.stubs.UnsetAll()
 | 
				
			||||||
 | 
					            self.stubs.SmartUnsetAll()
 | 
				
			||||||
 | 
					            self.mox.VerifyAll()
 | 
				
			||||||
 | 
					            # NOTE(vish): Clean up any ips associated during the test.
 | 
				
			||||||
 | 
					            ctxt = context.get_admin_context()
 | 
				
			||||||
 | 
					            db.fixed_ip_disassociate_all_by_timeout(ctxt, FLAGS.host,
 | 
				
			||||||
 | 
					                                                    self.start)
 | 
				
			||||||
 | 
					            db.network_disassociate_all(ctxt)
 | 
				
			||||||
            for x in self.injected:
 | 
					            for x in self.injected:
 | 
				
			||||||
                try:
 | 
					                try:
 | 
				
			||||||
                    x.stop()
 | 
					                    x.stop()
 | 
				
			||||||
@@ -147,14 +231,3 @@ class TrialTestCase(unittest.TestCase):
 | 
				
			|||||||
            return d
 | 
					            return d
 | 
				
			||||||
        _wrapped.func_name = func.func_name
 | 
					        _wrapped.func_name = func.func_name
 | 
				
			||||||
        return _wrapped
 | 
					        return _wrapped
 | 
				
			||||||
 | 
					 | 
				
			||||||
    def _monkey_patch_attach(self):
 | 
					 | 
				
			||||||
        self.originalAttach = rpc.Consumer.attach_to_twisted
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        def _wrapped(innerSelf):
 | 
					 | 
				
			||||||
            rv = self.originalAttach(innerSelf)
 | 
					 | 
				
			||||||
            self.injected.append(rv)
 | 
					 | 
				
			||||||
            return rv
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        _wrapped.func_name = self.originalAttach.func_name
 | 
					 | 
				
			||||||
        rpc.Consumer.attach_to_twisted = _wrapped
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -29,3 +29,8 @@
 | 
				
			|||||||
.. moduleauthor:: Manish Singh <yosh@gimp.org>
 | 
					.. moduleauthor:: Manish Singh <yosh@gimp.org>
 | 
				
			||||||
.. moduleauthor:: Andy Smith <andy@anarkystic.com>
 | 
					.. moduleauthor:: Andy Smith <andy@anarkystic.com>
 | 
				
			||||||
"""
 | 
					"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# See http://code.google.com/p/python-nose/issues/detail?id=373
 | 
				
			||||||
 | 
					# The code below enables nosetests to work with i18n _() blocks
 | 
				
			||||||
 | 
					import __builtin__
 | 
				
			||||||
 | 
					setattr(__builtin__, '_', lambda x: x)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,54 +0,0 @@
 | 
				
			|||||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Copyright 2010 United States Government as represented by the
 | 
					 | 
				
			||||||
# Administrator of the National Aeronautics and Space Administration.
 | 
					 | 
				
			||||||
# All Rights Reserved.
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
 | 
					 | 
				
			||||||
#    not use this file except in compliance with the License. You may obtain
 | 
					 | 
				
			||||||
#    a copy of the License at
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
#         http://www.apache.org/licenses/LICENSE-2.0
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
#    Unless required by applicable law or agreed to in writing, software
 | 
					 | 
				
			||||||
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
					 | 
				
			||||||
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
					 | 
				
			||||||
#    License for the specific language governing permissions and limitations
 | 
					 | 
				
			||||||
#    under the License.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import boto
 | 
					 | 
				
			||||||
from boto.ec2.regioninfo import RegionInfo
 | 
					 | 
				
			||||||
import unittest
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
ACCESS_KEY = 'fake'
 | 
					 | 
				
			||||||
SECRET_KEY = 'fake'
 | 
					 | 
				
			||||||
CLC_IP = '127.0.0.1'
 | 
					 | 
				
			||||||
CLC_PORT = 8773
 | 
					 | 
				
			||||||
REGION = 'test'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def get_connection():
 | 
					 | 
				
			||||||
    return boto.connect_ec2(
 | 
					 | 
				
			||||||
        aws_access_key_id=ACCESS_KEY,
 | 
					 | 
				
			||||||
        aws_secret_access_key=SECRET_KEY,
 | 
					 | 
				
			||||||
        is_secure=False,
 | 
					 | 
				
			||||||
        region=RegionInfo(None, REGION, CLC_IP),
 | 
					 | 
				
			||||||
        port=CLC_PORT,
 | 
					 | 
				
			||||||
        path='/services/Cloud',
 | 
					 | 
				
			||||||
        debug=99)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class APIIntegrationTests(unittest.TestCase):
 | 
					 | 
				
			||||||
    def test_001_get_all_images(self):
 | 
					 | 
				
			||||||
        conn = get_connection()
 | 
					 | 
				
			||||||
        res = conn.get_all_images()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if __name__ == '__main__':
 | 
					 | 
				
			||||||
    unittest.main()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#print conn.get_all_key_pairs()
 | 
					 | 
				
			||||||
#print conn.create_key_pair
 | 
					 | 
				
			||||||
#print conn.create_security_group('name', 'description')
 | 
					 | 
				
			||||||
@@ -1,48 +0,0 @@
 | 
				
			|||||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#    Copyright 2010 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 os
 | 
					 | 
				
			||||||
import subprocess
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from nova import test
 | 
					 | 
				
			||||||
from nova.utils import parse_mailmap, str_dict_replace
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class ProjectTestCase(test.TrialTestCase):
 | 
					 | 
				
			||||||
    def test_authors_up_to_date(self):
 | 
					 | 
				
			||||||
        if os.path.exists('../.bzr'):
 | 
					 | 
				
			||||||
            log_cmd = subprocess.Popen(["bzr", "log", "-n0"],
 | 
					 | 
				
			||||||
                                       stdout=subprocess.PIPE)
 | 
					 | 
				
			||||||
            changelog = log_cmd.communicate()[0]
 | 
					 | 
				
			||||||
            mailmap = parse_mailmap('../.mailmap')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            contributors = set()
 | 
					 | 
				
			||||||
            for l in changelog.split('\n'):
 | 
					 | 
				
			||||||
                l = l.strip()
 | 
					 | 
				
			||||||
                if (l.startswith('author:') or l.startswith('committer:')
 | 
					 | 
				
			||||||
                         and not l == 'committer: Tarmac'):
 | 
					 | 
				
			||||||
                    email = l.split(' ')[-1]
 | 
					 | 
				
			||||||
                    contributors.add(str_dict_replace(email, mailmap))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            authors_file = open('../Authors', 'r').read()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            missing = set()
 | 
					 | 
				
			||||||
            for contributor in contributors:
 | 
					 | 
				
			||||||
                if not contributor in authors_file:
 | 
					 | 
				
			||||||
                    missing.add(contributor)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            self.assertTrue(len(missing) == 0,
 | 
					 | 
				
			||||||
                            '%r not listed in Authors' % missing)
 | 
					 | 
				
			||||||
@@ -54,7 +54,7 @@ os.makedirs(os.path.join(OSS_TEMPDIR, 'images'))
 | 
				
			|||||||
os.makedirs(os.path.join(OSS_TEMPDIR, 'buckets'))
 | 
					os.makedirs(os.path.join(OSS_TEMPDIR, 'buckets'))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ObjectStoreTestCase(test.TrialTestCase):
 | 
					class ObjectStoreTestCase(test.TestCase):
 | 
				
			||||||
    """Test objectstore API directly."""
 | 
					    """Test objectstore API directly."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def setUp(self):
 | 
					    def setUp(self):
 | 
				
			||||||
@@ -191,7 +191,7 @@ class TestSite(server.Site):
 | 
				
			|||||||
    protocol = TestHTTPChannel
 | 
					    protocol = TestHTTPChannel
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class S3APITestCase(test.TrialTestCase):
 | 
					class S3APITestCase(test.TestCase):
 | 
				
			||||||
    """Test objectstore through S3 API."""
 | 
					    """Test objectstore through S3 API."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def setUp(self):
 | 
					    def setUp(self):
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,132 +0,0 @@
 | 
				
			|||||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Copyright 2010 United States Government as represented by the
 | 
					 | 
				
			||||||
# Administrator of the National Aeronautics and Space Administration.
 | 
					 | 
				
			||||||
# All Rights Reserved.
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
 | 
					 | 
				
			||||||
#    not use this file except in compliance with the License. You may obtain
 | 
					 | 
				
			||||||
#    a copy of the License at
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
#         http://www.apache.org/licenses/LICENSE-2.0
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
#    Unless required by applicable law or agreed to in writing, software
 | 
					 | 
				
			||||||
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
					 | 
				
			||||||
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
					 | 
				
			||||||
#    License for the specific language governing permissions and limitations
 | 
					 | 
				
			||||||
#    under the License.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import logging
 | 
					 | 
				
			||||||
from twisted.internet import defer
 | 
					 | 
				
			||||||
from twisted.internet import reactor
 | 
					 | 
				
			||||||
from xml.etree import ElementTree
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from nova import exception
 | 
					 | 
				
			||||||
from nova import flags
 | 
					 | 
				
			||||||
from nova import process
 | 
					 | 
				
			||||||
from nova import test
 | 
					 | 
				
			||||||
from nova import utils
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
FLAGS = flags.FLAGS
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class ProcessTestCase(test.TrialTestCase):
 | 
					 | 
				
			||||||
    def setUp(self):
 | 
					 | 
				
			||||||
        logging.getLogger().setLevel(logging.DEBUG)
 | 
					 | 
				
			||||||
        super(ProcessTestCase, self).setUp()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def test_execute_stdout(self):
 | 
					 | 
				
			||||||
        pool = process.ProcessPool(2)
 | 
					 | 
				
			||||||
        d = pool.simple_execute('echo test')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        def _check(rv):
 | 
					 | 
				
			||||||
            self.assertEqual(rv[0], 'test\n')
 | 
					 | 
				
			||||||
            self.assertEqual(rv[1], '')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        d.addCallback(_check)
 | 
					 | 
				
			||||||
        d.addErrback(self.fail)
 | 
					 | 
				
			||||||
        return d
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def test_execute_stderr(self):
 | 
					 | 
				
			||||||
        pool = process.ProcessPool(2)
 | 
					 | 
				
			||||||
        d = pool.simple_execute('cat BAD_FILE', check_exit_code=False)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        def _check(rv):
 | 
					 | 
				
			||||||
            self.assertEqual(rv[0], '')
 | 
					 | 
				
			||||||
            self.assert_('No such file' in rv[1])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        d.addCallback(_check)
 | 
					 | 
				
			||||||
        d.addErrback(self.fail)
 | 
					 | 
				
			||||||
        return d
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def test_execute_unexpected_stderr(self):
 | 
					 | 
				
			||||||
        pool = process.ProcessPool(2)
 | 
					 | 
				
			||||||
        d = pool.simple_execute('cat BAD_FILE')
 | 
					 | 
				
			||||||
        d.addCallback(lambda x: self.fail('should have raised an error'))
 | 
					 | 
				
			||||||
        d.addErrback(lambda failure: failure.trap(IOError))
 | 
					 | 
				
			||||||
        return d
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def test_max_processes(self):
 | 
					 | 
				
			||||||
        pool = process.ProcessPool(2)
 | 
					 | 
				
			||||||
        d1 = pool.simple_execute('sleep 0.01')
 | 
					 | 
				
			||||||
        d2 = pool.simple_execute('sleep 0.01')
 | 
					 | 
				
			||||||
        d3 = pool.simple_execute('sleep 0.005')
 | 
					 | 
				
			||||||
        d4 = pool.simple_execute('sleep 0.005')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        called = []
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        def _called(rv, name):
 | 
					 | 
				
			||||||
            called.append(name)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        d1.addCallback(_called, 'd1')
 | 
					 | 
				
			||||||
        d2.addCallback(_called, 'd2')
 | 
					 | 
				
			||||||
        d3.addCallback(_called, 'd3')
 | 
					 | 
				
			||||||
        d4.addCallback(_called, 'd4')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # Make sure that d3 and d4 had to wait on the other two and were called
 | 
					 | 
				
			||||||
        # in order
 | 
					 | 
				
			||||||
        # NOTE(termie): there may be a race condition in this test if for some
 | 
					 | 
				
			||||||
        #               reason one of the sleeps takes longer to complete
 | 
					 | 
				
			||||||
        #               than it should
 | 
					 | 
				
			||||||
        d4.addCallback(lambda x: self.assertEqual(called[2], 'd3'))
 | 
					 | 
				
			||||||
        d4.addCallback(lambda x: self.assertEqual(called[3], 'd4'))
 | 
					 | 
				
			||||||
        d4.addErrback(self.fail)
 | 
					 | 
				
			||||||
        return d4
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def test_kill_long_process(self):
 | 
					 | 
				
			||||||
        pool = process.ProcessPool(2)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        d1 = pool.simple_execute('sleep 1')
 | 
					 | 
				
			||||||
        d2 = pool.simple_execute('sleep 0.005')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        timeout = reactor.callLater(0.1, self.fail, 'should have been killed')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # kill d1 and wait on it to end then cancel the timeout
 | 
					 | 
				
			||||||
        d2.addCallback(lambda _: d1.process.signalProcess('KILL'))
 | 
					 | 
				
			||||||
        d2.addCallback(lambda _: d1)
 | 
					 | 
				
			||||||
        d2.addBoth(lambda _: timeout.active() and timeout.cancel())
 | 
					 | 
				
			||||||
        d2.addErrback(self.fail)
 | 
					 | 
				
			||||||
        return d2
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def test_process_exit_is_contained(self):
 | 
					 | 
				
			||||||
        pool = process.ProcessPool(2)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        d1 = pool.simple_execute('sleep 1')
 | 
					 | 
				
			||||||
        d1.addCallback(lambda x: self.fail('should have errbacked'))
 | 
					 | 
				
			||||||
        d1.addErrback(lambda fail: fail.trap(IOError))
 | 
					 | 
				
			||||||
        reactor.callLater(0.05, d1.process.signalProcess, 'KILL')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return d1
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def test_shared_pool_is_singleton(self):
 | 
					 | 
				
			||||||
        pool1 = process.SharedPool()
 | 
					 | 
				
			||||||
        pool2 = process.SharedPool()
 | 
					 | 
				
			||||||
        self.assertEqual(id(pool1._instance), id(pool2._instance))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def test_shared_pool_works_as_singleton(self):
 | 
					 | 
				
			||||||
        d1 = process.simple_execute('sleep 1')
 | 
					 | 
				
			||||||
        d2 = process.simple_execute('sleep 0.005')
 | 
					 | 
				
			||||||
        # lp609749: would have failed with
 | 
					 | 
				
			||||||
        # exceptions.AssertionError: Someone released me too many times:
 | 
					 | 
				
			||||||
        # too many tokens!
 | 
					 | 
				
			||||||
        return d1
 | 
					 | 
				
			||||||
@@ -1,153 +0,0 @@
 | 
				
			|||||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Copyright 2010 United States Government as represented by the
 | 
					 | 
				
			||||||
# Administrator of the National Aeronautics and Space Administration.
 | 
					 | 
				
			||||||
# All Rights Reserved.
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
 | 
					 | 
				
			||||||
#    not use this file except in compliance with the License. You may obtain
 | 
					 | 
				
			||||||
#    a copy of the License at
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
#         http://www.apache.org/licenses/LICENSE-2.0
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
#    Unless required by applicable law or agreed to in writing, software
 | 
					 | 
				
			||||||
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
					 | 
				
			||||||
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
					 | 
				
			||||||
#    License for the specific language governing permissions and limitations
 | 
					 | 
				
			||||||
#    under the License.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import logging
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from nova import context
 | 
					 | 
				
			||||||
from nova import db
 | 
					 | 
				
			||||||
from nova import exception
 | 
					 | 
				
			||||||
from nova import flags
 | 
					 | 
				
			||||||
from nova import quota
 | 
					 | 
				
			||||||
from nova import test
 | 
					 | 
				
			||||||
from nova import utils
 | 
					 | 
				
			||||||
from nova.auth import manager
 | 
					 | 
				
			||||||
from nova.api.ec2 import cloud
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
FLAGS = flags.FLAGS
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class QuotaTestCase(test.TrialTestCase):
 | 
					 | 
				
			||||||
    def setUp(self):
 | 
					 | 
				
			||||||
        logging.getLogger().setLevel(logging.DEBUG)
 | 
					 | 
				
			||||||
        super(QuotaTestCase, self).setUp()
 | 
					 | 
				
			||||||
        self.flags(connection_type='fake',
 | 
					 | 
				
			||||||
                   quota_instances=2,
 | 
					 | 
				
			||||||
                   quota_cores=4,
 | 
					 | 
				
			||||||
                   quota_volumes=2,
 | 
					 | 
				
			||||||
                   quota_gigabytes=20,
 | 
					 | 
				
			||||||
                   quota_floating_ips=1)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        self.cloud = cloud.CloudController()
 | 
					 | 
				
			||||||
        self.manager = manager.AuthManager()
 | 
					 | 
				
			||||||
        self.user = self.manager.create_user('admin', 'admin', 'admin', True)
 | 
					 | 
				
			||||||
        self.project = self.manager.create_project('admin', 'admin', 'admin')
 | 
					 | 
				
			||||||
        self.network = utils.import_object(FLAGS.network_manager)
 | 
					 | 
				
			||||||
        self.context = context.RequestContext(project=self.project,
 | 
					 | 
				
			||||||
                                              user=self.user)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def tearDown(self):
 | 
					 | 
				
			||||||
        manager.AuthManager().delete_project(self.project)
 | 
					 | 
				
			||||||
        manager.AuthManager().delete_user(self.user)
 | 
					 | 
				
			||||||
        super(QuotaTestCase, self).tearDown()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def _create_instance(self, cores=2):
 | 
					 | 
				
			||||||
        """Create a test instance"""
 | 
					 | 
				
			||||||
        inst = {}
 | 
					 | 
				
			||||||
        inst['image_id'] = 'ami-test'
 | 
					 | 
				
			||||||
        inst['reservation_id'] = 'r-fakeres'
 | 
					 | 
				
			||||||
        inst['user_id'] = self.user.id
 | 
					 | 
				
			||||||
        inst['project_id'] = self.project.id
 | 
					 | 
				
			||||||
        inst['instance_type'] = 'm1.large'
 | 
					 | 
				
			||||||
        inst['vcpus'] = cores
 | 
					 | 
				
			||||||
        inst['mac_address'] = utils.generate_mac()
 | 
					 | 
				
			||||||
        return db.instance_create(self.context, inst)['id']
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def _create_volume(self, size=10):
 | 
					 | 
				
			||||||
        """Create a test volume"""
 | 
					 | 
				
			||||||
        vol = {}
 | 
					 | 
				
			||||||
        vol['user_id'] = self.user.id
 | 
					 | 
				
			||||||
        vol['project_id'] = self.project.id
 | 
					 | 
				
			||||||
        vol['size'] = size
 | 
					 | 
				
			||||||
        return db.volume_create(self.context, vol)['id']
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def test_quota_overrides(self):
 | 
					 | 
				
			||||||
        """Make sure overriding a projects quotas works"""
 | 
					 | 
				
			||||||
        num_instances = quota.allowed_instances(self.context, 100, 'm1.small')
 | 
					 | 
				
			||||||
        self.assertEqual(num_instances, 2)
 | 
					 | 
				
			||||||
        db.quota_create(self.context, {'project_id': self.project.id,
 | 
					 | 
				
			||||||
                                       'instances': 10})
 | 
					 | 
				
			||||||
        num_instances = quota.allowed_instances(self.context, 100, 'm1.small')
 | 
					 | 
				
			||||||
        self.assertEqual(num_instances, 4)
 | 
					 | 
				
			||||||
        db.quota_update(self.context, self.project.id, {'cores': 100})
 | 
					 | 
				
			||||||
        num_instances = quota.allowed_instances(self.context, 100, 'm1.small')
 | 
					 | 
				
			||||||
        self.assertEqual(num_instances, 10)
 | 
					 | 
				
			||||||
        db.quota_destroy(self.context, self.project.id)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def test_too_many_instances(self):
 | 
					 | 
				
			||||||
        instance_ids = []
 | 
					 | 
				
			||||||
        for i in range(FLAGS.quota_instances):
 | 
					 | 
				
			||||||
            instance_id = self._create_instance()
 | 
					 | 
				
			||||||
            instance_ids.append(instance_id)
 | 
					 | 
				
			||||||
        self.assertRaises(quota.QuotaError, self.cloud.run_instances,
 | 
					 | 
				
			||||||
                                            self.context,
 | 
					 | 
				
			||||||
                                            min_count=1,
 | 
					 | 
				
			||||||
                                            max_count=1,
 | 
					 | 
				
			||||||
                                            instance_type='m1.small',
 | 
					 | 
				
			||||||
                                            image_id='fake')
 | 
					 | 
				
			||||||
        for instance_id in instance_ids:
 | 
					 | 
				
			||||||
            db.instance_destroy(self.context, instance_id)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def test_too_many_cores(self):
 | 
					 | 
				
			||||||
        instance_ids = []
 | 
					 | 
				
			||||||
        instance_id = self._create_instance(cores=4)
 | 
					 | 
				
			||||||
        instance_ids.append(instance_id)
 | 
					 | 
				
			||||||
        self.assertRaises(quota.QuotaError, self.cloud.run_instances,
 | 
					 | 
				
			||||||
                                            self.context,
 | 
					 | 
				
			||||||
                                            min_count=1,
 | 
					 | 
				
			||||||
                                            max_count=1,
 | 
					 | 
				
			||||||
                                            instance_type='m1.small',
 | 
					 | 
				
			||||||
                                            image_id='fake')
 | 
					 | 
				
			||||||
        for instance_id in instance_ids:
 | 
					 | 
				
			||||||
            db.instance_destroy(self.context, instance_id)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def test_too_many_volumes(self):
 | 
					 | 
				
			||||||
        volume_ids = []
 | 
					 | 
				
			||||||
        for i in range(FLAGS.quota_volumes):
 | 
					 | 
				
			||||||
            volume_id = self._create_volume()
 | 
					 | 
				
			||||||
            volume_ids.append(volume_id)
 | 
					 | 
				
			||||||
        self.assertRaises(quota.QuotaError, self.cloud.create_volume,
 | 
					 | 
				
			||||||
                                            self.context,
 | 
					 | 
				
			||||||
                                            size=10)
 | 
					 | 
				
			||||||
        for volume_id in volume_ids:
 | 
					 | 
				
			||||||
            db.volume_destroy(self.context, volume_id)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def test_too_many_gigabytes(self):
 | 
					 | 
				
			||||||
        volume_ids = []
 | 
					 | 
				
			||||||
        volume_id = self._create_volume(size=20)
 | 
					 | 
				
			||||||
        volume_ids.append(volume_id)
 | 
					 | 
				
			||||||
        self.assertRaises(quota.QuotaError,
 | 
					 | 
				
			||||||
                          self.cloud.create_volume,
 | 
					 | 
				
			||||||
                          self.context,
 | 
					 | 
				
			||||||
                          size=10)
 | 
					 | 
				
			||||||
        for volume_id in volume_ids:
 | 
					 | 
				
			||||||
            db.volume_destroy(self.context, volume_id)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def test_too_many_addresses(self):
 | 
					 | 
				
			||||||
        address = '192.168.0.100'
 | 
					 | 
				
			||||||
        db.floating_ip_create(context.get_admin_context(),
 | 
					 | 
				
			||||||
                              {'address': address, 'host': FLAGS.host})
 | 
					 | 
				
			||||||
        float_addr = self.network.allocate_floating_ip(self.context,
 | 
					 | 
				
			||||||
                                                       self.project.id)
 | 
					 | 
				
			||||||
        # NOTE(vish): This assert never fails. When cloud attempts to
 | 
					 | 
				
			||||||
        #             make an rpc.call, the test just finishes with OK. It
 | 
					 | 
				
			||||||
        #             appears to be something in the magic inline callbacks
 | 
					 | 
				
			||||||
        #             that is breaking.
 | 
					 | 
				
			||||||
        self.assertRaises(quota.QuotaError, self.cloud.allocate_address,
 | 
					 | 
				
			||||||
                          self.context)
 | 
					 | 
				
			||||||
        db.floating_ip_destroy(context.get_admin_context(), address)
 | 
					 | 
				
			||||||
@@ -1,245 +0,0 @@
 | 
				
			|||||||
# 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.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
"""
 | 
					 | 
				
			||||||
Unit Tests for remote procedure calls using queue
 | 
					 | 
				
			||||||
"""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import mox
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from twisted.application.app import startApplication
 | 
					 | 
				
			||||||
from twisted.internet import defer
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from nova import exception
 | 
					 | 
				
			||||||
from nova import flags
 | 
					 | 
				
			||||||
from nova import rpc
 | 
					 | 
				
			||||||
from nova import test
 | 
					 | 
				
			||||||
from nova import service
 | 
					 | 
				
			||||||
from nova import manager
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
FLAGS = flags.FLAGS
 | 
					 | 
				
			||||||
flags.DEFINE_string("fake_manager", "nova.tests.service_unittest.FakeManager",
 | 
					 | 
				
			||||||
                    "Manager for testing")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class FakeManager(manager.Manager):
 | 
					 | 
				
			||||||
    """Fake manager for tests"""
 | 
					 | 
				
			||||||
    def test_method(self):
 | 
					 | 
				
			||||||
        return 'manager'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class ExtendedService(service.Service):
 | 
					 | 
				
			||||||
    def test_method(self):
 | 
					 | 
				
			||||||
        return 'service'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class ServiceManagerTestCase(test.TrialTestCase):
 | 
					 | 
				
			||||||
    """Test cases for Services"""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def test_attribute_error_for_no_manager(self):
 | 
					 | 
				
			||||||
        serv = service.Service('test',
 | 
					 | 
				
			||||||
                               'test',
 | 
					 | 
				
			||||||
                               'test',
 | 
					 | 
				
			||||||
                               'nova.tests.service_unittest.FakeManager')
 | 
					 | 
				
			||||||
        self.assertRaises(AttributeError, getattr, serv, 'test_method')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def test_message_gets_to_manager(self):
 | 
					 | 
				
			||||||
        serv = service.Service('test',
 | 
					 | 
				
			||||||
                               'test',
 | 
					 | 
				
			||||||
                               'test',
 | 
					 | 
				
			||||||
                               'nova.tests.service_unittest.FakeManager')
 | 
					 | 
				
			||||||
        serv.startService()
 | 
					 | 
				
			||||||
        self.assertEqual(serv.test_method(), 'manager')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def test_override_manager_method(self):
 | 
					 | 
				
			||||||
        serv = ExtendedService('test',
 | 
					 | 
				
			||||||
                               'test',
 | 
					 | 
				
			||||||
                               'test',
 | 
					 | 
				
			||||||
                               'nova.tests.service_unittest.FakeManager')
 | 
					 | 
				
			||||||
        serv.startService()
 | 
					 | 
				
			||||||
        self.assertEqual(serv.test_method(), 'service')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class ServiceTestCase(test.TrialTestCase):
 | 
					 | 
				
			||||||
    """Test cases for Services"""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def setUp(self):
 | 
					 | 
				
			||||||
        super(ServiceTestCase, self).setUp()
 | 
					 | 
				
			||||||
        self.mox.StubOutWithMock(service, 'db')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def test_create(self):
 | 
					 | 
				
			||||||
        host = 'foo'
 | 
					 | 
				
			||||||
        binary = 'nova-fake'
 | 
					 | 
				
			||||||
        topic = 'fake'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # NOTE(vish): Create was moved out of mox replay to make sure that
 | 
					 | 
				
			||||||
        #             the looping calls are created in StartService.
 | 
					 | 
				
			||||||
        app = service.Service.create(host=host, binary=binary)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        self.mox.StubOutWithMock(rpc,
 | 
					 | 
				
			||||||
                                 'AdapterConsumer',
 | 
					 | 
				
			||||||
                                 use_mock_anything=True)
 | 
					 | 
				
			||||||
        self.mox.StubOutWithMock(
 | 
					 | 
				
			||||||
                service.task, 'LoopingCall', use_mock_anything=True)
 | 
					 | 
				
			||||||
        rpc.AdapterConsumer(connection=mox.IgnoreArg(),
 | 
					 | 
				
			||||||
                            topic=topic,
 | 
					 | 
				
			||||||
                            proxy=mox.IsA(service.Service)).AndReturn(
 | 
					 | 
				
			||||||
                                    rpc.AdapterConsumer)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        rpc.AdapterConsumer(connection=mox.IgnoreArg(),
 | 
					 | 
				
			||||||
                            topic='%s.%s' % (topic, host),
 | 
					 | 
				
			||||||
                            proxy=mox.IsA(service.Service)).AndReturn(
 | 
					 | 
				
			||||||
                                    rpc.AdapterConsumer)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        rpc.AdapterConsumer.attach_to_twisted()
 | 
					 | 
				
			||||||
        rpc.AdapterConsumer.attach_to_twisted()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # Stub out looping call a bit needlessly since we don't have an easy
 | 
					 | 
				
			||||||
        # way to cancel it (yet) when the tests finishes
 | 
					 | 
				
			||||||
        service.task.LoopingCall(mox.IgnoreArg()).AndReturn(
 | 
					 | 
				
			||||||
                        service.task.LoopingCall)
 | 
					 | 
				
			||||||
        service.task.LoopingCall.start(interval=mox.IgnoreArg(),
 | 
					 | 
				
			||||||
                                       now=mox.IgnoreArg())
 | 
					 | 
				
			||||||
        service.task.LoopingCall(mox.IgnoreArg()).AndReturn(
 | 
					 | 
				
			||||||
                        service.task.LoopingCall)
 | 
					 | 
				
			||||||
        service.task.LoopingCall.start(interval=mox.IgnoreArg(),
 | 
					 | 
				
			||||||
                                       now=mox.IgnoreArg())
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        service_create = {'host': host,
 | 
					 | 
				
			||||||
                          'binary': binary,
 | 
					 | 
				
			||||||
                          'topic': topic,
 | 
					 | 
				
			||||||
                          'report_count': 0}
 | 
					 | 
				
			||||||
        service_ref = {'host': host,
 | 
					 | 
				
			||||||
                       'binary': binary,
 | 
					 | 
				
			||||||
                       'report_count': 0,
 | 
					 | 
				
			||||||
                       'id': 1}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        service.db.service_get_by_args(mox.IgnoreArg(),
 | 
					 | 
				
			||||||
                                       host,
 | 
					 | 
				
			||||||
                                       binary).AndRaise(exception.NotFound())
 | 
					 | 
				
			||||||
        service.db.service_create(mox.IgnoreArg(),
 | 
					 | 
				
			||||||
                                  service_create).AndReturn(service_ref)
 | 
					 | 
				
			||||||
        self.mox.ReplayAll()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        startApplication(app, False)
 | 
					 | 
				
			||||||
        self.assert_(app)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    # We're testing sort of weird behavior in how report_state decides
 | 
					 | 
				
			||||||
    # whether it is disconnected, it looks for a variable on itself called
 | 
					 | 
				
			||||||
    # 'model_disconnected' and report_state doesn't really do much so this
 | 
					 | 
				
			||||||
    # these are mostly just for coverage
 | 
					 | 
				
			||||||
    @defer.inlineCallbacks
 | 
					 | 
				
			||||||
    def test_report_state_no_service(self):
 | 
					 | 
				
			||||||
        host = 'foo'
 | 
					 | 
				
			||||||
        binary = 'bar'
 | 
					 | 
				
			||||||
        topic = 'test'
 | 
					 | 
				
			||||||
        service_create = {'host': host,
 | 
					 | 
				
			||||||
                          'binary': binary,
 | 
					 | 
				
			||||||
                          'topic': topic,
 | 
					 | 
				
			||||||
                          'report_count': 0}
 | 
					 | 
				
			||||||
        service_ref = {'host': host,
 | 
					 | 
				
			||||||
                          'binary': binary,
 | 
					 | 
				
			||||||
                          'topic': topic,
 | 
					 | 
				
			||||||
                          'report_count': 0,
 | 
					 | 
				
			||||||
                          'id': 1}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        service.db.service_get_by_args(mox.IgnoreArg(),
 | 
					 | 
				
			||||||
                                      host,
 | 
					 | 
				
			||||||
                                      binary).AndRaise(exception.NotFound())
 | 
					 | 
				
			||||||
        service.db.service_create(mox.IgnoreArg(),
 | 
					 | 
				
			||||||
                                  service_create).AndReturn(service_ref)
 | 
					 | 
				
			||||||
        service.db.service_get(mox.IgnoreArg(),
 | 
					 | 
				
			||||||
                               service_ref['id']).AndReturn(service_ref)
 | 
					 | 
				
			||||||
        service.db.service_update(mox.IgnoreArg(), service_ref['id'],
 | 
					 | 
				
			||||||
                                  mox.ContainsKeyValue('report_count', 1))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        self.mox.ReplayAll()
 | 
					 | 
				
			||||||
        serv = service.Service(host,
 | 
					 | 
				
			||||||
                               binary,
 | 
					 | 
				
			||||||
                               topic,
 | 
					 | 
				
			||||||
                               'nova.tests.service_unittest.FakeManager')
 | 
					 | 
				
			||||||
        serv.startService()
 | 
					 | 
				
			||||||
        yield serv.report_state()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @defer.inlineCallbacks
 | 
					 | 
				
			||||||
    def test_report_state_newly_disconnected(self):
 | 
					 | 
				
			||||||
        host = 'foo'
 | 
					 | 
				
			||||||
        binary = 'bar'
 | 
					 | 
				
			||||||
        topic = 'test'
 | 
					 | 
				
			||||||
        service_create = {'host': host,
 | 
					 | 
				
			||||||
                          'binary': binary,
 | 
					 | 
				
			||||||
                          'topic': topic,
 | 
					 | 
				
			||||||
                          'report_count': 0}
 | 
					 | 
				
			||||||
        service_ref = {'host': host,
 | 
					 | 
				
			||||||
                          'binary': binary,
 | 
					 | 
				
			||||||
                          'topic': topic,
 | 
					 | 
				
			||||||
                          'report_count': 0,
 | 
					 | 
				
			||||||
                          'id': 1}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        service.db.service_get_by_args(mox.IgnoreArg(),
 | 
					 | 
				
			||||||
                                      host,
 | 
					 | 
				
			||||||
                                      binary).AndRaise(exception.NotFound())
 | 
					 | 
				
			||||||
        service.db.service_create(mox.IgnoreArg(),
 | 
					 | 
				
			||||||
                                  service_create).AndReturn(service_ref)
 | 
					 | 
				
			||||||
        service.db.service_get(mox.IgnoreArg(),
 | 
					 | 
				
			||||||
                               mox.IgnoreArg()).AndRaise(Exception())
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        self.mox.ReplayAll()
 | 
					 | 
				
			||||||
        serv = service.Service(host,
 | 
					 | 
				
			||||||
                               binary,
 | 
					 | 
				
			||||||
                               topic,
 | 
					 | 
				
			||||||
                               'nova.tests.service_unittest.FakeManager')
 | 
					 | 
				
			||||||
        serv.startService()
 | 
					 | 
				
			||||||
        yield serv.report_state()
 | 
					 | 
				
			||||||
        self.assert_(serv.model_disconnected)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @defer.inlineCallbacks
 | 
					 | 
				
			||||||
    def test_report_state_newly_connected(self):
 | 
					 | 
				
			||||||
        host = 'foo'
 | 
					 | 
				
			||||||
        binary = 'bar'
 | 
					 | 
				
			||||||
        topic = 'test'
 | 
					 | 
				
			||||||
        service_create = {'host': host,
 | 
					 | 
				
			||||||
                          'binary': binary,
 | 
					 | 
				
			||||||
                          'topic': topic,
 | 
					 | 
				
			||||||
                          'report_count': 0}
 | 
					 | 
				
			||||||
        service_ref = {'host': host,
 | 
					 | 
				
			||||||
                          'binary': binary,
 | 
					 | 
				
			||||||
                          'topic': topic,
 | 
					 | 
				
			||||||
                          'report_count': 0,
 | 
					 | 
				
			||||||
                          'id': 1}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        service.db.service_get_by_args(mox.IgnoreArg(),
 | 
					 | 
				
			||||||
                                      host,
 | 
					 | 
				
			||||||
                                      binary).AndRaise(exception.NotFound())
 | 
					 | 
				
			||||||
        service.db.service_create(mox.IgnoreArg(),
 | 
					 | 
				
			||||||
                                  service_create).AndReturn(service_ref)
 | 
					 | 
				
			||||||
        service.db.service_get(mox.IgnoreArg(),
 | 
					 | 
				
			||||||
                               service_ref['id']).AndReturn(service_ref)
 | 
					 | 
				
			||||||
        service.db.service_update(mox.IgnoreArg(), service_ref['id'],
 | 
					 | 
				
			||||||
                                  mox.ContainsKeyValue('report_count', 1))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        self.mox.ReplayAll()
 | 
					 | 
				
			||||||
        serv = service.Service(host,
 | 
					 | 
				
			||||||
                               binary,
 | 
					 | 
				
			||||||
                               topic,
 | 
					 | 
				
			||||||
                               'nova.tests.service_unittest.FakeManager')
 | 
					 | 
				
			||||||
        serv.startService()
 | 
					 | 
				
			||||||
        serv.model_disconnected = True
 | 
					 | 
				
			||||||
        yield serv.report_state()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        self.assert_(not serv.model_disconnected)
 | 
					 | 
				
			||||||
@@ -35,7 +35,7 @@ class Context(object):
 | 
				
			|||||||
    pass
 | 
					    pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class AccessTestCase(test.TrialTestCase):
 | 
					class AccessTestCase(test.TestCase):
 | 
				
			||||||
    def setUp(self):
 | 
					    def setUp(self):
 | 
				
			||||||
        super(AccessTestCase, self).setUp()
 | 
					        super(AccessTestCase, self).setUp()
 | 
				
			||||||
        um = manager.AuthManager()
 | 
					        um = manager.AuthManager()
 | 
				
			||||||
@@ -208,17 +208,13 @@ class AuthManagerTestCase(object):
 | 
				
			|||||||
        #             so it probably belongs in crypto_unittest
 | 
					        #             so it probably belongs in crypto_unittest
 | 
				
			||||||
        #             but I'm leaving it where I found it.
 | 
					        #             but I'm leaving it where I found it.
 | 
				
			||||||
        with user_and_project_generator(self.manager) as (user, project):
 | 
					        with user_and_project_generator(self.manager) as (user, project):
 | 
				
			||||||
            # NOTE(todd): Should mention why we must setup controller first
 | 
					            # NOTE(vish): Setup runs genroot.sh if it hasn't been run
 | 
				
			||||||
            #             (somebody please clue me in)
 | 
					            cloud.CloudController().setup()
 | 
				
			||||||
            cloud_controller = cloud.CloudController()
 | 
					            _key, cert_str = crypto.generate_x509_cert(user.id, project.id)
 | 
				
			||||||
            cloud_controller.setup()
 | 
					 | 
				
			||||||
            _key, cert_str = self.manager._generate_x509_cert('test1',
 | 
					 | 
				
			||||||
                                                              'testproj')
 | 
					 | 
				
			||||||
            logging.debug(cert_str)
 | 
					            logging.debug(cert_str)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            # Need to verify that it's signed by the right intermediate CA
 | 
					            full_chain = crypto.fetch_ca(project_id=project.id, chain=True)
 | 
				
			||||||
            full_chain = crypto.fetch_ca(project_id='testproj', chain=True)
 | 
					            int_cert = crypto.fetch_ca(project_id=project.id, chain=False)
 | 
				
			||||||
            int_cert = crypto.fetch_ca(project_id='testproj', chain=False)
 | 
					 | 
				
			||||||
            cloud_cert = crypto.fetch_ca()
 | 
					            cloud_cert = crypto.fetch_ca()
 | 
				
			||||||
            logging.debug("CA chain:\n\n =====\n%s\n\n=====" % full_chain)
 | 
					            logging.debug("CA chain:\n\n =====\n%s\n\n=====" % full_chain)
 | 
				
			||||||
            signed_cert = X509.load_cert_string(cert_str)
 | 
					            signed_cert = X509.load_cert_string(cert_str)
 | 
				
			||||||
@@ -227,7 +223,8 @@ class AuthManagerTestCase(object):
 | 
				
			|||||||
            cloud_cert = X509.load_cert_string(cloud_cert)
 | 
					            cloud_cert = X509.load_cert_string(cloud_cert)
 | 
				
			||||||
            self.assertTrue(signed_cert.verify(chain_cert.get_pubkey()))
 | 
					            self.assertTrue(signed_cert.verify(chain_cert.get_pubkey()))
 | 
				
			||||||
            self.assertTrue(signed_cert.verify(int_cert.get_pubkey()))
 | 
					            self.assertTrue(signed_cert.verify(int_cert.get_pubkey()))
 | 
				
			||||||
            if not FLAGS.use_intermediate_ca:
 | 
					
 | 
				
			||||||
 | 
					            if not FLAGS.use_project_ca:
 | 
				
			||||||
                self.assertTrue(signed_cert.verify(cloud_cert.get_pubkey()))
 | 
					                self.assertTrue(signed_cert.verify(cloud_cert.get_pubkey()))
 | 
				
			||||||
            else:
 | 
					            else:
 | 
				
			||||||
                self.assertFalse(signed_cert.verify(cloud_cert.get_pubkey()))
 | 
					                self.assertFalse(signed_cert.verify(cloud_cert.get_pubkey()))
 | 
				
			||||||
@@ -326,24 +323,20 @@ class AuthManagerTestCase(object):
 | 
				
			|||||||
            self.assertTrue(user.is_admin())
 | 
					            self.assertTrue(user.is_admin())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class AuthManagerLdapTestCase(AuthManagerTestCase, test.TrialTestCase):
 | 
					class AuthManagerLdapTestCase(AuthManagerTestCase, test.TestCase):
 | 
				
			||||||
    auth_driver = 'nova.auth.ldapdriver.FakeLdapDriver'
 | 
					    auth_driver = 'nova.auth.ldapdriver.FakeLdapDriver'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __init__(self, *args, **kwargs):
 | 
					    def __init__(self, *args, **kwargs):
 | 
				
			||||||
        AuthManagerTestCase.__init__(self)
 | 
					        AuthManagerTestCase.__init__(self)
 | 
				
			||||||
        test.TrialTestCase.__init__(self, *args, **kwargs)
 | 
					        test.TestCase.__init__(self, *args, **kwargs)
 | 
				
			||||||
        import nova.auth.fakeldap as fakeldap
 | 
					        import nova.auth.fakeldap as fakeldap
 | 
				
			||||||
        FLAGS.redis_db = 8
 | 
					 | 
				
			||||||
        if FLAGS.flush_db:
 | 
					        if FLAGS.flush_db:
 | 
				
			||||||
            logging.info("Flushing redis datastore")
 | 
					            logging.info("Flushing datastore")
 | 
				
			||||||
            try:
 | 
					            r = fakeldap.Store.instance()
 | 
				
			||||||
                r = fakeldap.Redis.instance()
 | 
					            r.flushdb()
 | 
				
			||||||
                r.flushdb()
 | 
					 | 
				
			||||||
            except:
 | 
					 | 
				
			||||||
                self.skip = True
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class AuthManagerDbTestCase(AuthManagerTestCase, test.TrialTestCase):
 | 
					class AuthManagerDbTestCase(AuthManagerTestCase, test.TestCase):
 | 
				
			||||||
    auth_driver = 'nova.auth.dbdriver.DbDriver'
 | 
					    auth_driver = 'nova.auth.dbdriver.DbDriver'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -22,22 +22,18 @@ import logging
 | 
				
			|||||||
from M2Crypto import BIO
 | 
					from M2Crypto import BIO
 | 
				
			||||||
from M2Crypto import RSA
 | 
					from M2Crypto import RSA
 | 
				
			||||||
import os
 | 
					import os
 | 
				
			||||||
import StringIO
 | 
					 | 
				
			||||||
import tempfile
 | 
					import tempfile
 | 
				
			||||||
import time
 | 
					import time
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from eventlet import greenthread
 | 
					from eventlet import greenthread
 | 
				
			||||||
from twisted.internet import defer
 | 
					 | 
				
			||||||
import unittest
 | 
					 | 
				
			||||||
from xml.etree import ElementTree
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
from nova import context
 | 
					from nova import context
 | 
				
			||||||
from nova import crypto
 | 
					from nova import crypto
 | 
				
			||||||
from nova import db
 | 
					from nova import db
 | 
				
			||||||
from nova import flags
 | 
					from nova import flags
 | 
				
			||||||
from nova import rpc
 | 
					from nova import rpc
 | 
				
			||||||
 | 
					from nova import service
 | 
				
			||||||
from nova import test
 | 
					from nova import test
 | 
				
			||||||
from nova import utils
 | 
					 | 
				
			||||||
from nova.auth import manager
 | 
					from nova.auth import manager
 | 
				
			||||||
from nova.compute import power_state
 | 
					from nova.compute import power_state
 | 
				
			||||||
from nova.api.ec2 import cloud
 | 
					from nova.api.ec2 import cloud
 | 
				
			||||||
@@ -53,10 +49,11 @@ IMAGES_PATH = os.path.join(OSS_TEMPDIR, 'images')
 | 
				
			|||||||
os.makedirs(IMAGES_PATH)
 | 
					os.makedirs(IMAGES_PATH)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class CloudTestCase(test.TrialTestCase):
 | 
					class CloudTestCase(test.TestCase):
 | 
				
			||||||
    def setUp(self):
 | 
					    def setUp(self):
 | 
				
			||||||
        super(CloudTestCase, self).setUp()
 | 
					        super(CloudTestCase, self).setUp()
 | 
				
			||||||
        self.flags(connection_type='fake', images_path=IMAGES_PATH)
 | 
					        self.flags(connection_type='fake',
 | 
				
			||||||
 | 
					                   images_path=IMAGES_PATH)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.conn = rpc.Connection.instance()
 | 
					        self.conn = rpc.Connection.instance()
 | 
				
			||||||
        logging.getLogger().setLevel(logging.DEBUG)
 | 
					        logging.getLogger().setLevel(logging.DEBUG)
 | 
				
			||||||
@@ -64,27 +61,23 @@ class CloudTestCase(test.TrialTestCase):
 | 
				
			|||||||
        # set up our cloud
 | 
					        # set up our cloud
 | 
				
			||||||
        self.cloud = cloud.CloudController()
 | 
					        self.cloud = cloud.CloudController()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # set up a service
 | 
					        # set up services
 | 
				
			||||||
        self.compute = utils.import_object(FLAGS.compute_manager)
 | 
					        self.compute = service.Service.create(binary='nova-compute')
 | 
				
			||||||
        self.compute_consumer = rpc.AdapterConsumer(connection=self.conn,
 | 
					        self.compute.start()
 | 
				
			||||||
                                                    topic=FLAGS.compute_topic,
 | 
					        self.network = service.Service.create(binary='nova-network')
 | 
				
			||||||
                                                    proxy=self.compute)
 | 
					        self.network.start()
 | 
				
			||||||
        self.compute_consumer.attach_to_eventlet()
 | 
					 | 
				
			||||||
        self.network = utils.import_object(FLAGS.network_manager)
 | 
					 | 
				
			||||||
        self.network_consumer = rpc.AdapterConsumer(connection=self.conn,
 | 
					 | 
				
			||||||
                                                    topic=FLAGS.network_topic,
 | 
					 | 
				
			||||||
                                                    proxy=self.network)
 | 
					 | 
				
			||||||
        self.network_consumer.attach_to_eventlet()
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.manager = manager.AuthManager()
 | 
					        self.manager = manager.AuthManager()
 | 
				
			||||||
        self.user = self.manager.create_user('admin', 'admin', 'admin', True)
 | 
					        self.user = self.manager.create_user('admin', 'admin', 'admin', True)
 | 
				
			||||||
        self.project = self.manager.create_project('proj', 'admin', 'proj')
 | 
					        self.project = self.manager.create_project('proj', 'admin', 'proj')
 | 
				
			||||||
        self.context = context.RequestContext(user=self.user,
 | 
					        self.context = context.RequestContext(user=self.user,
 | 
				
			||||||
                                                 project=self.project)
 | 
					                                              project=self.project)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def tearDown(self):
 | 
					    def tearDown(self):
 | 
				
			||||||
        self.manager.delete_project(self.project)
 | 
					        self.manager.delete_project(self.project)
 | 
				
			||||||
        self.manager.delete_user(self.user)
 | 
					        self.manager.delete_user(self.user)
 | 
				
			||||||
 | 
					        self.compute.kill()
 | 
				
			||||||
 | 
					        self.network.kill()
 | 
				
			||||||
        super(CloudTestCase, self).tearDown()
 | 
					        super(CloudTestCase, self).tearDown()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def _create_key(self, name):
 | 
					    def _create_key(self, name):
 | 
				
			||||||
@@ -111,12 +104,13 @@ class CloudTestCase(test.TrialTestCase):
 | 
				
			|||||||
                              {'address': address,
 | 
					                              {'address': address,
 | 
				
			||||||
                               'host': FLAGS.host})
 | 
					                               'host': FLAGS.host})
 | 
				
			||||||
        self.cloud.allocate_address(self.context)
 | 
					        self.cloud.allocate_address(self.context)
 | 
				
			||||||
        inst = db.instance_create(self.context, {})
 | 
					        inst = db.instance_create(self.context, {'host': FLAGS.host})
 | 
				
			||||||
        fixed = self.network.allocate_fixed_ip(self.context, inst['id'])
 | 
					        fixed = self.network.allocate_fixed_ip(self.context, inst['id'])
 | 
				
			||||||
        ec2_id = cloud.internal_id_to_ec2_id(inst['internal_id'])
 | 
					        ec2_id = cloud.internal_id_to_ec2_id(inst['internal_id'])
 | 
				
			||||||
        self.cloud.associate_address(self.context,
 | 
					        self.cloud.associate_address(self.context,
 | 
				
			||||||
                                     instance_id=ec2_id,
 | 
					                                     instance_id=ec2_id,
 | 
				
			||||||
                                     public_ip=address)
 | 
					                                     public_ip=address)
 | 
				
			||||||
 | 
					        greenthread.sleep(0.3)
 | 
				
			||||||
        self.cloud.disassociate_address(self.context,
 | 
					        self.cloud.disassociate_address(self.context,
 | 
				
			||||||
                                        public_ip=address)
 | 
					                                        public_ip=address)
 | 
				
			||||||
        self.cloud.release_address(self.context,
 | 
					        self.cloud.release_address(self.context,
 | 
				
			||||||
@@ -126,6 +120,19 @@ class CloudTestCase(test.TrialTestCase):
 | 
				
			|||||||
        db.instance_destroy(self.context, inst['id'])
 | 
					        db.instance_destroy(self.context, inst['id'])
 | 
				
			||||||
        db.floating_ip_destroy(self.context, address)
 | 
					        db.floating_ip_destroy(self.context, address)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_describe_volumes(self):
 | 
				
			||||||
 | 
					        """Makes sure describe_volumes works and filters results."""
 | 
				
			||||||
 | 
					        vol1 = db.volume_create(self.context, {})
 | 
				
			||||||
 | 
					        vol2 = db.volume_create(self.context, {})
 | 
				
			||||||
 | 
					        result = self.cloud.describe_volumes(self.context)
 | 
				
			||||||
 | 
					        self.assertEqual(len(result['volumeSet']), 2)
 | 
				
			||||||
 | 
					        result = self.cloud.describe_volumes(self.context,
 | 
				
			||||||
 | 
					                                             volume_id=[vol2['ec2_id']])
 | 
				
			||||||
 | 
					        self.assertEqual(len(result['volumeSet']), 1)
 | 
				
			||||||
 | 
					        self.assertEqual(result['volumeSet'][0]['volumeId'], vol2['ec2_id'])
 | 
				
			||||||
 | 
					        db.volume_destroy(self.context, vol1['id'])
 | 
				
			||||||
 | 
					        db.volume_destroy(self.context, vol2['id'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_console_output(self):
 | 
					    def test_console_output(self):
 | 
				
			||||||
        image_id = FLAGS.default_image
 | 
					        image_id = FLAGS.default_image
 | 
				
			||||||
        instance_type = FLAGS.default_instance_type
 | 
					        instance_type = FLAGS.default_instance_type
 | 
				
			||||||
@@ -186,7 +193,7 @@ class CloudTestCase(test.TrialTestCase):
 | 
				
			|||||||
        logging.debug("Need to watch instance %s until it's running..." %
 | 
					        logging.debug("Need to watch instance %s until it's running..." %
 | 
				
			||||||
                      instance['instance_id'])
 | 
					                      instance['instance_id'])
 | 
				
			||||||
        while True:
 | 
					        while True:
 | 
				
			||||||
            rv = yield defer.succeed(time.sleep(1))
 | 
					            greenthread.sleep(1)
 | 
				
			||||||
            info = self.cloud._get_instance(instance['instance_id'])
 | 
					            info = self.cloud._get_instance(instance['instance_id'])
 | 
				
			||||||
            logging.debug(info['state'])
 | 
					            logging.debug(info['state'])
 | 
				
			||||||
            if info['state'] == power_state.RUNNING:
 | 
					            if info['state'] == power_state.RUNNING:
 | 
				
			||||||
@@ -22,8 +22,6 @@ Tests For Compute
 | 
				
			|||||||
import datetime
 | 
					import datetime
 | 
				
			||||||
import logging
 | 
					import logging
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from twisted.internet import defer
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from nova import context
 | 
					from nova import context
 | 
				
			||||||
from nova import db
 | 
					from nova import db
 | 
				
			||||||
from nova import exception
 | 
					from nova import exception
 | 
				
			||||||
@@ -33,15 +31,17 @@ from nova import utils
 | 
				
			|||||||
from nova.auth import manager
 | 
					from nova.auth import manager
 | 
				
			||||||
from nova.compute import api as compute_api
 | 
					from nova.compute import api as compute_api
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
FLAGS = flags.FLAGS
 | 
					FLAGS = flags.FLAGS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ComputeTestCase(test.TrialTestCase):
 | 
					class ComputeTestCase(test.TestCase):
 | 
				
			||||||
    """Test case for compute"""
 | 
					    """Test case for compute"""
 | 
				
			||||||
    def setUp(self):
 | 
					    def setUp(self):
 | 
				
			||||||
        logging.getLogger().setLevel(logging.DEBUG)
 | 
					        logging.getLogger().setLevel(logging.DEBUG)
 | 
				
			||||||
        super(ComputeTestCase, self).setUp()
 | 
					        super(ComputeTestCase, self).setUp()
 | 
				
			||||||
        self.flags(connection_type='fake',
 | 
					        self.flags(connection_type='fake',
 | 
				
			||||||
 | 
					                   stub_network=True,
 | 
				
			||||||
                   network_manager='nova.network.manager.FlatManager')
 | 
					                   network_manager='nova.network.manager.FlatManager')
 | 
				
			||||||
        self.compute = utils.import_object(FLAGS.compute_manager)
 | 
					        self.compute = utils.import_object(FLAGS.compute_manager)
 | 
				
			||||||
        self.compute_api = compute_api.ComputeAPI()
 | 
					        self.compute_api = compute_api.ComputeAPI()
 | 
				
			||||||
@@ -72,52 +72,44 @@ class ComputeTestCase(test.TrialTestCase):
 | 
				
			|||||||
        """Verify that an instance cannot be created without a display_name."""
 | 
					        """Verify that an instance cannot be created without a display_name."""
 | 
				
			||||||
        cases = [dict(), dict(display_name=None)]
 | 
					        cases = [dict(), dict(display_name=None)]
 | 
				
			||||||
        for instance in cases:
 | 
					        for instance in cases:
 | 
				
			||||||
            ref = self.compute_api.create_instance(self.context, None,
 | 
					            ref = self.compute_api.create_instances(self.context,
 | 
				
			||||||
                                                   **instance)
 | 
					                FLAGS.default_instance_type, None, **instance)
 | 
				
			||||||
            try:
 | 
					            try:
 | 
				
			||||||
                self.assertNotEqual(ref.display_name, None)
 | 
					                self.assertNotEqual(ref[0].display_name, None)
 | 
				
			||||||
            finally:
 | 
					            finally:
 | 
				
			||||||
                db.instance_destroy(self.context, ref['id'])
 | 
					                db.instance_destroy(self.context, ref[0]['id'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_create_instance_associates_security_groups(self):
 | 
					    def test_create_instance_associates_security_groups(self):
 | 
				
			||||||
        """Make sure create_instance associates security groups"""
 | 
					        """Make sure create_instances associates security groups"""
 | 
				
			||||||
        inst = {}
 | 
					 | 
				
			||||||
        inst['user_id'] = self.user.id
 | 
					 | 
				
			||||||
        inst['project_id'] = self.project.id
 | 
					 | 
				
			||||||
        values = {'name': 'default',
 | 
					        values = {'name': 'default',
 | 
				
			||||||
                  'description': 'default',
 | 
					                  'description': 'default',
 | 
				
			||||||
                  'user_id': self.user.id,
 | 
					                  'user_id': self.user.id,
 | 
				
			||||||
                  'project_id': self.project.id}
 | 
					                  'project_id': self.project.id}
 | 
				
			||||||
        group = db.security_group_create(self.context, values)
 | 
					        group = db.security_group_create(self.context, values)
 | 
				
			||||||
        ref = self.compute_api.create_instance(self.context,
 | 
					        ref = self.compute_api.create_instances(self.context,
 | 
				
			||||||
                                               security_groups=[group['id']],
 | 
					            FLAGS.default_instance_type, None, security_group=['default'])
 | 
				
			||||||
                                               **inst)
 | 
					 | 
				
			||||||
        # reload to get groups
 | 
					 | 
				
			||||||
        instance_ref = db.instance_get(self.context, ref['id'])
 | 
					 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
            self.assertEqual(len(instance_ref['security_groups']), 1)
 | 
					            self.assertEqual(len(ref[0]['security_groups']), 1)
 | 
				
			||||||
        finally:
 | 
					        finally:
 | 
				
			||||||
            db.security_group_destroy(self.context, group['id'])
 | 
					            db.security_group_destroy(self.context, group['id'])
 | 
				
			||||||
            db.instance_destroy(self.context, instance_ref['id'])
 | 
					            db.instance_destroy(self.context, ref[0]['id'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @defer.inlineCallbacks
 | 
					 | 
				
			||||||
    def test_run_terminate(self):
 | 
					    def test_run_terminate(self):
 | 
				
			||||||
        """Make sure it is possible to  run and terminate instance"""
 | 
					        """Make sure it is possible to  run and terminate instance"""
 | 
				
			||||||
        instance_id = self._create_instance()
 | 
					        instance_id = self._create_instance()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        yield self.compute.run_instance(self.context, instance_id)
 | 
					        self.compute.run_instance(self.context, instance_id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        instances = db.instance_get_all(context.get_admin_context())
 | 
					        instances = db.instance_get_all(context.get_admin_context())
 | 
				
			||||||
        logging.info("Running instances: %s", instances)
 | 
					        logging.info("Running instances: %s", instances)
 | 
				
			||||||
        self.assertEqual(len(instances), 1)
 | 
					        self.assertEqual(len(instances), 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        yield self.compute.terminate_instance(self.context, instance_id)
 | 
					        self.compute.terminate_instance(self.context, instance_id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        instances = db.instance_get_all(context.get_admin_context())
 | 
					        instances = db.instance_get_all(context.get_admin_context())
 | 
				
			||||||
        logging.info("After terminating instances: %s", instances)
 | 
					        logging.info("After terminating instances: %s", instances)
 | 
				
			||||||
        self.assertEqual(len(instances), 0)
 | 
					        self.assertEqual(len(instances), 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @defer.inlineCallbacks
 | 
					 | 
				
			||||||
    def test_run_terminate_timestamps(self):
 | 
					    def test_run_terminate_timestamps(self):
 | 
				
			||||||
        """Make sure timestamps are set for launched and destroyed"""
 | 
					        """Make sure timestamps are set for launched and destroyed"""
 | 
				
			||||||
        instance_id = self._create_instance()
 | 
					        instance_id = self._create_instance()
 | 
				
			||||||
@@ -125,42 +117,48 @@ class ComputeTestCase(test.TrialTestCase):
 | 
				
			|||||||
        self.assertEqual(instance_ref['launched_at'], None)
 | 
					        self.assertEqual(instance_ref['launched_at'], None)
 | 
				
			||||||
        self.assertEqual(instance_ref['deleted_at'], None)
 | 
					        self.assertEqual(instance_ref['deleted_at'], None)
 | 
				
			||||||
        launch = datetime.datetime.utcnow()
 | 
					        launch = datetime.datetime.utcnow()
 | 
				
			||||||
        yield self.compute.run_instance(self.context, instance_id)
 | 
					        self.compute.run_instance(self.context, instance_id)
 | 
				
			||||||
        instance_ref = db.instance_get(self.context, instance_id)
 | 
					        instance_ref = db.instance_get(self.context, instance_id)
 | 
				
			||||||
        self.assert_(instance_ref['launched_at'] > launch)
 | 
					        self.assert_(instance_ref['launched_at'] > launch)
 | 
				
			||||||
        self.assertEqual(instance_ref['deleted_at'], None)
 | 
					        self.assertEqual(instance_ref['deleted_at'], None)
 | 
				
			||||||
        terminate = datetime.datetime.utcnow()
 | 
					        terminate = datetime.datetime.utcnow()
 | 
				
			||||||
        yield self.compute.terminate_instance(self.context, instance_id)
 | 
					        self.compute.terminate_instance(self.context, instance_id)
 | 
				
			||||||
        self.context = self.context.elevated(True)
 | 
					        self.context = self.context.elevated(True)
 | 
				
			||||||
        instance_ref = db.instance_get(self.context, instance_id)
 | 
					        instance_ref = db.instance_get(self.context, instance_id)
 | 
				
			||||||
        self.assert_(instance_ref['launched_at'] < terminate)
 | 
					        self.assert_(instance_ref['launched_at'] < terminate)
 | 
				
			||||||
        self.assert_(instance_ref['deleted_at'] > terminate)
 | 
					        self.assert_(instance_ref['deleted_at'] > terminate)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @defer.inlineCallbacks
 | 
					    def test_pause(self):
 | 
				
			||||||
 | 
					        """Ensure instance can be paused"""
 | 
				
			||||||
 | 
					        instance_id = self._create_instance()
 | 
				
			||||||
 | 
					        self.compute.run_instance(self.context, instance_id)
 | 
				
			||||||
 | 
					        self.compute.pause_instance(self.context, instance_id)
 | 
				
			||||||
 | 
					        self.compute.unpause_instance(self.context, instance_id)
 | 
				
			||||||
 | 
					        self.compute.terminate_instance(self.context, instance_id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_reboot(self):
 | 
					    def test_reboot(self):
 | 
				
			||||||
        """Ensure instance can be rebooted"""
 | 
					        """Ensure instance can be rebooted"""
 | 
				
			||||||
        instance_id = self._create_instance()
 | 
					        instance_id = self._create_instance()
 | 
				
			||||||
        yield self.compute.run_instance(self.context, instance_id)
 | 
					        self.compute.run_instance(self.context, instance_id)
 | 
				
			||||||
        yield self.compute.reboot_instance(self.context, instance_id)
 | 
					        self.compute.reboot_instance(self.context, instance_id)
 | 
				
			||||||
        yield self.compute.terminate_instance(self.context, instance_id)
 | 
					        self.compute.terminate_instance(self.context, instance_id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @defer.inlineCallbacks
 | 
					 | 
				
			||||||
    def test_console_output(self):
 | 
					    def test_console_output(self):
 | 
				
			||||||
        """Make sure we can get console output from instance"""
 | 
					        """Make sure we can get console output from instance"""
 | 
				
			||||||
        instance_id = self._create_instance()
 | 
					        instance_id = self._create_instance()
 | 
				
			||||||
        yield self.compute.run_instance(self.context, instance_id)
 | 
					        self.compute.run_instance(self.context, instance_id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        console = yield self.compute.get_console_output(self.context,
 | 
					        console = self.compute.get_console_output(self.context,
 | 
				
			||||||
                                                        instance_id)
 | 
					                                                        instance_id)
 | 
				
			||||||
        self.assert_(console)
 | 
					        self.assert_(console)
 | 
				
			||||||
        yield self.compute.terminate_instance(self.context, instance_id)
 | 
					        self.compute.terminate_instance(self.context, instance_id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @defer.inlineCallbacks
 | 
					 | 
				
			||||||
    def test_run_instance_existing(self):
 | 
					    def test_run_instance_existing(self):
 | 
				
			||||||
        """Ensure failure when running an instance that already exists"""
 | 
					        """Ensure failure when running an instance that already exists"""
 | 
				
			||||||
        instance_id = self._create_instance()
 | 
					        instance_id = self._create_instance()
 | 
				
			||||||
        yield self.compute.run_instance(self.context, instance_id)
 | 
					        self.compute.run_instance(self.context, instance_id)
 | 
				
			||||||
        self.assertFailure(self.compute.run_instance(self.context,
 | 
					        self.assertRaises(exception.Error,
 | 
				
			||||||
                                                     instance_id),
 | 
					                          self.compute.run_instance,
 | 
				
			||||||
                           exception.Error)
 | 
					                          self.context,
 | 
				
			||||||
        yield self.compute.terminate_instance(self.context, instance_id)
 | 
					                          instance_id)
 | 
				
			||||||
 | 
					        self.compute.terminate_instance(self.context, instance_id)
 | 
				
			||||||
@@ -24,7 +24,7 @@ FLAGS = flags.FLAGS
 | 
				
			|||||||
flags.DEFINE_string('flags_unittest', 'foo', 'for testing purposes only')
 | 
					flags.DEFINE_string('flags_unittest', 'foo', 'for testing purposes only')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class FlagsTestCase(test.TrialTestCase):
 | 
					class FlagsTestCase(test.TestCase):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def setUp(self):
 | 
					    def setUp(self):
 | 
				
			||||||
        super(FlagsTestCase, self).setUp()
 | 
					        super(FlagsTestCase, self).setUp()
 | 
				
			||||||
							
								
								
									
										86
									
								
								nova/tests/test_middleware.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								nova/tests/test_middleware.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,86 @@
 | 
				
			|||||||
 | 
					# vim: tabstop=4 shiftwidth=4 softtabstop=4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Copyright 2010 United States Government as represented by the
 | 
				
			||||||
 | 
					# Administrator of the National Aeronautics and Space Administration.
 | 
				
			||||||
 | 
					# All Rights Reserved.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					#    Licensed under the Apache License, Version 2.0 (the "License"); you may
 | 
				
			||||||
 | 
					#    not use this file except in compliance with the License. You may obtain
 | 
				
			||||||
 | 
					#    a copy of the License at
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					#         http://www.apache.org/licenses/LICENSE-2.0
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					#    Unless required by applicable law or agreed to in writing, software
 | 
				
			||||||
 | 
					#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
				
			||||||
 | 
					#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
				
			||||||
 | 
					#    License for the specific language governing permissions and limitations
 | 
				
			||||||
 | 
					#    under the License.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import datetime
 | 
				
			||||||
 | 
					import webob
 | 
				
			||||||
 | 
					import webob.dec
 | 
				
			||||||
 | 
					import webob.exc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from nova.api import ec2
 | 
				
			||||||
 | 
					from nova import flags
 | 
				
			||||||
 | 
					from nova import test
 | 
				
			||||||
 | 
					from nova import utils
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					FLAGS = flags.FLAGS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@webob.dec.wsgify
 | 
				
			||||||
 | 
					def conditional_forbid(req):
 | 
				
			||||||
 | 
					    """Helper wsgi app returns 403 if param 'die' is 1."""
 | 
				
			||||||
 | 
					    if 'die' in req.params and req.params['die'] == '1':
 | 
				
			||||||
 | 
					        raise webob.exc.HTTPForbidden()
 | 
				
			||||||
 | 
					    return 'OK'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class LockoutTestCase(test.TrialTestCase):
 | 
				
			||||||
 | 
					    """Test case for the Lockout middleware."""
 | 
				
			||||||
 | 
					    def setUp(self):  # pylint: disable-msg=C0103
 | 
				
			||||||
 | 
					        super(LockoutTestCase, self).setUp()
 | 
				
			||||||
 | 
					        utils.set_time_override()
 | 
				
			||||||
 | 
					        self.lockout = ec2.Lockout(conditional_forbid)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def tearDown(self):  # pylint: disable-msg=C0103
 | 
				
			||||||
 | 
					        utils.clear_time_override()
 | 
				
			||||||
 | 
					        super(LockoutTestCase, self).tearDown()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _send_bad_attempts(self, access_key, num_attempts=1):
 | 
				
			||||||
 | 
					        """Fail x."""
 | 
				
			||||||
 | 
					        for i in xrange(num_attempts):
 | 
				
			||||||
 | 
					            req = webob.Request.blank('/?AWSAccessKeyId=%s&die=1' % access_key)
 | 
				
			||||||
 | 
					            self.assertEqual(req.get_response(self.lockout).status_int, 403)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _is_locked_out(self, access_key):
 | 
				
			||||||
 | 
					        """Sends a test request to see if key is locked out."""
 | 
				
			||||||
 | 
					        req = webob.Request.blank('/?AWSAccessKeyId=%s' % access_key)
 | 
				
			||||||
 | 
					        return (req.get_response(self.lockout).status_int == 403)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_lockout(self):
 | 
				
			||||||
 | 
					        self._send_bad_attempts('test', FLAGS.lockout_attempts)
 | 
				
			||||||
 | 
					        self.assertTrue(self._is_locked_out('test'))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_timeout(self):
 | 
				
			||||||
 | 
					        self._send_bad_attempts('test', FLAGS.lockout_attempts)
 | 
				
			||||||
 | 
					        self.assertTrue(self._is_locked_out('test'))
 | 
				
			||||||
 | 
					        utils.advance_time_seconds(FLAGS.lockout_minutes * 60)
 | 
				
			||||||
 | 
					        self.assertFalse(self._is_locked_out('test'))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_multiple_keys(self):
 | 
				
			||||||
 | 
					        self._send_bad_attempts('test1', FLAGS.lockout_attempts)
 | 
				
			||||||
 | 
					        self.assertTrue(self._is_locked_out('test1'))
 | 
				
			||||||
 | 
					        self.assertFalse(self._is_locked_out('test2'))
 | 
				
			||||||
 | 
					        utils.advance_time_seconds(FLAGS.lockout_minutes * 60)
 | 
				
			||||||
 | 
					        self.assertFalse(self._is_locked_out('test1'))
 | 
				
			||||||
 | 
					        self.assertFalse(self._is_locked_out('test2'))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_window_timeout(self):
 | 
				
			||||||
 | 
					        self._send_bad_attempts('test', FLAGS.lockout_attempts - 1)
 | 
				
			||||||
 | 
					        self.assertFalse(self._is_locked_out('test'))
 | 
				
			||||||
 | 
					        utils.advance_time_seconds(FLAGS.lockout_window * 60)
 | 
				
			||||||
 | 
					        self._send_bad_attempts('test', FLAGS.lockout_attempts - 1)
 | 
				
			||||||
 | 
					        self.assertFalse(self._is_locked_out('test'))
 | 
				
			||||||
							
								
								
									
										55
									
								
								nova/tests/test_misc.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								nova/tests/test_misc.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,55 @@
 | 
				
			|||||||
 | 
					# vim: tabstop=4 shiftwidth=4 softtabstop=4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#    Copyright 2010 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 os
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from nova import test
 | 
				
			||||||
 | 
					from nova.utils import parse_mailmap, str_dict_replace
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ProjectTestCase(test.TestCase):
 | 
				
			||||||
 | 
					    def test_authors_up_to_date(self):
 | 
				
			||||||
 | 
					        if os.path.exists('.bzr'):
 | 
				
			||||||
 | 
					            contributors = set()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            mailmap = parse_mailmap('.mailmap')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            import bzrlib.workingtree
 | 
				
			||||||
 | 
					            tree = bzrlib.workingtree.WorkingTree.open('.')
 | 
				
			||||||
 | 
					            tree.lock_read()
 | 
				
			||||||
 | 
					            try:
 | 
				
			||||||
 | 
					                parents = tree.get_parent_ids()
 | 
				
			||||||
 | 
					                g = tree.branch.repository.get_graph()
 | 
				
			||||||
 | 
					                for p in parents[1:]:
 | 
				
			||||||
 | 
					                    rev_ids = [r for r, _ in g.iter_ancestry(parents)
 | 
				
			||||||
 | 
					                               if r != "null:"]
 | 
				
			||||||
 | 
					                    revs = tree.branch.repository.get_revisions(rev_ids)
 | 
				
			||||||
 | 
					                    for r in revs:
 | 
				
			||||||
 | 
					                        for author in r.get_apparent_authors():
 | 
				
			||||||
 | 
					                            email = author.split(' ')[-1]
 | 
				
			||||||
 | 
					                            contributors.add(str_dict_replace(email, mailmap))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                authors_file = open('Authors', 'r').read()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                missing = set()
 | 
				
			||||||
 | 
					                for contributor in contributors:
 | 
				
			||||||
 | 
					                    if not contributor in authors_file:
 | 
				
			||||||
 | 
					                        missing.add(contributor)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                self.assertTrue(len(missing) == 0,
 | 
				
			||||||
 | 
					                                '%r not listed in Authors' % missing)
 | 
				
			||||||
 | 
					            finally:
 | 
				
			||||||
 | 
					                tree.unlock()
 | 
				
			||||||
@@ -26,6 +26,7 @@ from nova import context
 | 
				
			|||||||
from nova import db
 | 
					from nova import db
 | 
				
			||||||
from nova import exception
 | 
					from nova import exception
 | 
				
			||||||
from nova import flags
 | 
					from nova import flags
 | 
				
			||||||
 | 
					from nova import service
 | 
				
			||||||
from nova import test
 | 
					from nova import test
 | 
				
			||||||
from nova import utils
 | 
					from nova import utils
 | 
				
			||||||
from nova.auth import manager
 | 
					from nova.auth import manager
 | 
				
			||||||
@@ -33,13 +34,14 @@ from nova.auth import manager
 | 
				
			|||||||
FLAGS = flags.FLAGS
 | 
					FLAGS = flags.FLAGS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class NetworkTestCase(test.TrialTestCase):
 | 
					class NetworkTestCase(test.TestCase):
 | 
				
			||||||
    """Test cases for network code"""
 | 
					    """Test cases for network code"""
 | 
				
			||||||
    def setUp(self):
 | 
					    def setUp(self):
 | 
				
			||||||
        super(NetworkTestCase, self).setUp()
 | 
					        super(NetworkTestCase, self).setUp()
 | 
				
			||||||
        # NOTE(vish): if you change these flags, make sure to change the
 | 
					        # NOTE(vish): if you change these flags, make sure to change the
 | 
				
			||||||
        #             flags in the corresponding section in nova-dhcpbridge
 | 
					        #             flags in the corresponding section in nova-dhcpbridge
 | 
				
			||||||
        self.flags(connection_type='fake',
 | 
					        self.flags(connection_type='fake',
 | 
				
			||||||
 | 
					                   fake_call=True,
 | 
				
			||||||
                   fake_network=True,
 | 
					                   fake_network=True,
 | 
				
			||||||
                   network_size=16,
 | 
					                   network_size=16,
 | 
				
			||||||
                   num_networks=5)
 | 
					                   num_networks=5)
 | 
				
			||||||
@@ -56,16 +58,13 @@ class NetworkTestCase(test.TrialTestCase):
 | 
				
			|||||||
            # create the necessary network data for the project
 | 
					            # create the necessary network data for the project
 | 
				
			||||||
            user_context = context.RequestContext(project=self.projects[i],
 | 
					            user_context = context.RequestContext(project=self.projects[i],
 | 
				
			||||||
                                                     user=self.user)
 | 
					                                                     user=self.user)
 | 
				
			||||||
            network_ref = self.network.get_network(user_context)
 | 
					            host = self.network.get_network_host(user_context.elevated())
 | 
				
			||||||
            self.network.set_network_host(context.get_admin_context(),
 | 
					 | 
				
			||||||
                                          network_ref['id'])
 | 
					 | 
				
			||||||
        instance_ref = self._create_instance(0)
 | 
					        instance_ref = self._create_instance(0)
 | 
				
			||||||
        self.instance_id = instance_ref['id']
 | 
					        self.instance_id = instance_ref['id']
 | 
				
			||||||
        instance_ref = self._create_instance(1)
 | 
					        instance_ref = self._create_instance(1)
 | 
				
			||||||
        self.instance2_id = instance_ref['id']
 | 
					        self.instance2_id = instance_ref['id']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def tearDown(self):
 | 
					    def tearDown(self):
 | 
				
			||||||
        super(NetworkTestCase, self).tearDown()
 | 
					 | 
				
			||||||
        # TODO(termie): this should really be instantiating clean datastores
 | 
					        # TODO(termie): this should really be instantiating clean datastores
 | 
				
			||||||
        #               in between runs, one failure kills all the tests
 | 
					        #               in between runs, one failure kills all the tests
 | 
				
			||||||
        db.instance_destroy(context.get_admin_context(), self.instance_id)
 | 
					        db.instance_destroy(context.get_admin_context(), self.instance_id)
 | 
				
			||||||
@@ -73,6 +72,7 @@ class NetworkTestCase(test.TrialTestCase):
 | 
				
			|||||||
        for project in self.projects:
 | 
					        for project in self.projects:
 | 
				
			||||||
            self.manager.delete_project(project)
 | 
					            self.manager.delete_project(project)
 | 
				
			||||||
        self.manager.delete_user(self.user)
 | 
					        self.manager.delete_user(self.user)
 | 
				
			||||||
 | 
					        super(NetworkTestCase, self).tearDown()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def _create_instance(self, project_num, mac=None):
 | 
					    def _create_instance(self, project_num, mac=None):
 | 
				
			||||||
        if not mac:
 | 
					        if not mac:
 | 
				
			||||||
@@ -20,8 +20,6 @@ Unit Tests for remote procedure calls using queue
 | 
				
			|||||||
"""
 | 
					"""
 | 
				
			||||||
import logging
 | 
					import logging
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from twisted.internet import defer
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from nova import context
 | 
					from nova import context
 | 
				
			||||||
from nova import flags
 | 
					from nova import flags
 | 
				
			||||||
from nova import rpc
 | 
					from nova import rpc
 | 
				
			||||||
@@ -31,32 +29,31 @@ from nova import test
 | 
				
			|||||||
FLAGS = flags.FLAGS
 | 
					FLAGS = flags.FLAGS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class RpcTestCase(test.TrialTestCase):
 | 
					class RpcTestCase(test.TestCase):
 | 
				
			||||||
    """Test cases for rpc"""
 | 
					    """Test cases for rpc"""
 | 
				
			||||||
    def setUp(self):
 | 
					    def setUp(self):
 | 
				
			||||||
        super(RpcTestCase, self).setUp()
 | 
					        super(RpcTestCase, self).setUp()
 | 
				
			||||||
        self.conn = rpc.Connection.instance()
 | 
					        self.conn = rpc.Connection.instance(True)
 | 
				
			||||||
        self.receiver = TestReceiver()
 | 
					        self.receiver = TestReceiver()
 | 
				
			||||||
        self.consumer = rpc.AdapterConsumer(connection=self.conn,
 | 
					        self.consumer = rpc.AdapterConsumer(connection=self.conn,
 | 
				
			||||||
                                            topic='test',
 | 
					                                            topic='test',
 | 
				
			||||||
                                            proxy=self.receiver)
 | 
					                                            proxy=self.receiver)
 | 
				
			||||||
        self.consumer.attach_to_twisted()
 | 
					        self.consumer.attach_to_eventlet()
 | 
				
			||||||
        self.context = context.get_admin_context()
 | 
					        self.context = context.get_admin_context()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_call_succeed(self):
 | 
					    def test_call_succeed(self):
 | 
				
			||||||
        """Get a value through rpc call"""
 | 
					        """Get a value through rpc call"""
 | 
				
			||||||
        value = 42
 | 
					        value = 42
 | 
				
			||||||
        result = yield rpc.call_twisted(self.context,
 | 
					        result = rpc.call(self.context, 'test', {"method": "echo",
 | 
				
			||||||
                                        'test', {"method": "echo",
 | 
					 | 
				
			||||||
                                                 "args": {"value": value}})
 | 
					                                                 "args": {"value": value}})
 | 
				
			||||||
        self.assertEqual(value, result)
 | 
					        self.assertEqual(value, result)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_context_passed(self):
 | 
					    def test_context_passed(self):
 | 
				
			||||||
        """Makes sure a context is passed through rpc call"""
 | 
					        """Makes sure a context is passed through rpc call"""
 | 
				
			||||||
        value = 42
 | 
					        value = 42
 | 
				
			||||||
        result = yield rpc.call_twisted(self.context,
 | 
					        result = rpc.call(self.context,
 | 
				
			||||||
                                        'test', {"method": "context",
 | 
					                          'test', {"method": "context",
 | 
				
			||||||
                                                 "args": {"value": value}})
 | 
					                                   "args": {"value": value}})
 | 
				
			||||||
        self.assertEqual(self.context.to_dict(), result)
 | 
					        self.assertEqual(self.context.to_dict(), result)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_call_exception(self):
 | 
					    def test_call_exception(self):
 | 
				
			||||||
@@ -67,18 +64,48 @@ class RpcTestCase(test.TrialTestCase):
 | 
				
			|||||||
        to an int in the test.
 | 
					        to an int in the test.
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        value = 42
 | 
					        value = 42
 | 
				
			||||||
        self.assertFailure(rpc.call_twisted(self.context, 'test',
 | 
					        self.assertRaises(rpc.RemoteError,
 | 
				
			||||||
                                            {"method": "fail",
 | 
					                          rpc.call,
 | 
				
			||||||
                                             "args": {"value": value}}),
 | 
					                          self.context,
 | 
				
			||||||
                           rpc.RemoteError)
 | 
					                          'test',
 | 
				
			||||||
 | 
					                          {"method": "fail",
 | 
				
			||||||
 | 
					                           "args": {"value": value}})
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
            yield rpc.call_twisted(self.context,
 | 
					            rpc.call(self.context,
 | 
				
			||||||
                                   'test', {"method": "fail",
 | 
					                     'test',
 | 
				
			||||||
                                            "args": {"value": value}})
 | 
					                     {"method": "fail",
 | 
				
			||||||
 | 
					                      "args": {"value": value}})
 | 
				
			||||||
            self.fail("should have thrown rpc.RemoteError")
 | 
					            self.fail("should have thrown rpc.RemoteError")
 | 
				
			||||||
        except rpc.RemoteError as exc:
 | 
					        except rpc.RemoteError as exc:
 | 
				
			||||||
            self.assertEqual(int(exc.value), value)
 | 
					            self.assertEqual(int(exc.value), value)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_nested_calls(self):
 | 
				
			||||||
 | 
					        """Test that we can do an rpc.call inside another call"""
 | 
				
			||||||
 | 
					        class Nested(object):
 | 
				
			||||||
 | 
					            @staticmethod
 | 
				
			||||||
 | 
					            def echo(context, queue, value):
 | 
				
			||||||
 | 
					                """Calls echo in the passed queue"""
 | 
				
			||||||
 | 
					                logging.debug("Nested received %s, %s", queue, value)
 | 
				
			||||||
 | 
					                ret = rpc.call(context,
 | 
				
			||||||
 | 
					                               queue,
 | 
				
			||||||
 | 
					                               {"method": "echo",
 | 
				
			||||||
 | 
					                                "args": {"value": value}})
 | 
				
			||||||
 | 
					                logging.debug("Nested return %s", ret)
 | 
				
			||||||
 | 
					                return value
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        nested = Nested()
 | 
				
			||||||
 | 
					        conn = rpc.Connection.instance(True)
 | 
				
			||||||
 | 
					        consumer = rpc.AdapterConsumer(connection=conn,
 | 
				
			||||||
 | 
					                                       topic='nested',
 | 
				
			||||||
 | 
					                                       proxy=nested)
 | 
				
			||||||
 | 
					        consumer.attach_to_eventlet()
 | 
				
			||||||
 | 
					        value = 42
 | 
				
			||||||
 | 
					        result = rpc.call(self.context,
 | 
				
			||||||
 | 
					                          'nested', {"method": "echo",
 | 
				
			||||||
 | 
					                                     "args": {"queue": "test",
 | 
				
			||||||
 | 
					                                              "value": value}})
 | 
				
			||||||
 | 
					        self.assertEqual(value, result)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class TestReceiver(object):
 | 
					class TestReceiver(object):
 | 
				
			||||||
    """Simple Proxy class so the consumer has methods to call
 | 
					    """Simple Proxy class so the consumer has methods to call
 | 
				
			||||||
@@ -89,13 +116,13 @@ class TestReceiver(object):
 | 
				
			|||||||
    def echo(context, value):
 | 
					    def echo(context, value):
 | 
				
			||||||
        """Simply returns whatever value is sent in"""
 | 
					        """Simply returns whatever value is sent in"""
 | 
				
			||||||
        logging.debug("Received %s", value)
 | 
					        logging.debug("Received %s", value)
 | 
				
			||||||
        return defer.succeed(value)
 | 
					        return value
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @staticmethod
 | 
					    @staticmethod
 | 
				
			||||||
    def context(context, value):
 | 
					    def context(context, value):
 | 
				
			||||||
        """Returns dictionary version of context"""
 | 
					        """Returns dictionary version of context"""
 | 
				
			||||||
        logging.debug("Received %s", context)
 | 
					        logging.debug("Received %s", context)
 | 
				
			||||||
        return defer.succeed(context.to_dict())
 | 
					        return context.to_dict()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @staticmethod
 | 
					    @staticmethod
 | 
				
			||||||
    def fail(context, value):
 | 
					    def fail(context, value):
 | 
				
			||||||
@@ -44,11 +44,11 @@ class TestDriver(driver.Scheduler):
 | 
				
			|||||||
        return 'named_host'
 | 
					        return 'named_host'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class SchedulerTestCase(test.TrialTestCase):
 | 
					class SchedulerTestCase(test.TestCase):
 | 
				
			||||||
    """Test case for scheduler"""
 | 
					    """Test case for scheduler"""
 | 
				
			||||||
    def setUp(self):
 | 
					    def setUp(self):
 | 
				
			||||||
        super(SchedulerTestCase, self).setUp()
 | 
					        super(SchedulerTestCase, self).setUp()
 | 
				
			||||||
        self.flags(scheduler_driver='nova.tests.scheduler_unittest.TestDriver')
 | 
					        self.flags(scheduler_driver='nova.tests.test_scheduler.TestDriver')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_fallback(self):
 | 
					    def test_fallback(self):
 | 
				
			||||||
        scheduler = manager.SchedulerManager()
 | 
					        scheduler = manager.SchedulerManager()
 | 
				
			||||||
@@ -73,11 +73,12 @@ class SchedulerTestCase(test.TrialTestCase):
 | 
				
			|||||||
        scheduler.named_method(ctxt, 'topic', num=7)
 | 
					        scheduler.named_method(ctxt, 'topic', num=7)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class SimpleDriverTestCase(test.TrialTestCase):
 | 
					class SimpleDriverTestCase(test.TestCase):
 | 
				
			||||||
    """Test case for simple driver"""
 | 
					    """Test case for simple driver"""
 | 
				
			||||||
    def setUp(self):
 | 
					    def setUp(self):
 | 
				
			||||||
        super(SimpleDriverTestCase, self).setUp()
 | 
					        super(SimpleDriverTestCase, self).setUp()
 | 
				
			||||||
        self.flags(connection_type='fake',
 | 
					        self.flags(connection_type='fake',
 | 
				
			||||||
 | 
					                   stub_network=True,
 | 
				
			||||||
                   max_cores=4,
 | 
					                   max_cores=4,
 | 
				
			||||||
                   max_gigabytes=4,
 | 
					                   max_gigabytes=4,
 | 
				
			||||||
                   network_manager='nova.network.manager.FlatManager',
 | 
					                   network_manager='nova.network.manager.FlatManager',
 | 
				
			||||||
@@ -122,12 +123,12 @@ class SimpleDriverTestCase(test.TrialTestCase):
 | 
				
			|||||||
                                   'nova-compute',
 | 
					                                   'nova-compute',
 | 
				
			||||||
                                   'compute',
 | 
					                                   'compute',
 | 
				
			||||||
                                   FLAGS.compute_manager)
 | 
					                                   FLAGS.compute_manager)
 | 
				
			||||||
        compute1.startService()
 | 
					        compute1.start()
 | 
				
			||||||
        compute2 = service.Service('host2',
 | 
					        compute2 = service.Service('host2',
 | 
				
			||||||
                                   'nova-compute',
 | 
					                                   'nova-compute',
 | 
				
			||||||
                                   'compute',
 | 
					                                   'compute',
 | 
				
			||||||
                                   FLAGS.compute_manager)
 | 
					                                   FLAGS.compute_manager)
 | 
				
			||||||
        compute2.startService()
 | 
					        compute2.start()
 | 
				
			||||||
        hosts = self.scheduler.driver.hosts_up(self.context, 'compute')
 | 
					        hosts = self.scheduler.driver.hosts_up(self.context, 'compute')
 | 
				
			||||||
        self.assertEqual(len(hosts), 2)
 | 
					        self.assertEqual(len(hosts), 2)
 | 
				
			||||||
        compute1.kill()
 | 
					        compute1.kill()
 | 
				
			||||||
@@ -139,12 +140,12 @@ class SimpleDriverTestCase(test.TrialTestCase):
 | 
				
			|||||||
                                   'nova-compute',
 | 
					                                   'nova-compute',
 | 
				
			||||||
                                   'compute',
 | 
					                                   'compute',
 | 
				
			||||||
                                   FLAGS.compute_manager)
 | 
					                                   FLAGS.compute_manager)
 | 
				
			||||||
        compute1.startService()
 | 
					        compute1.start()
 | 
				
			||||||
        compute2 = service.Service('host2',
 | 
					        compute2 = service.Service('host2',
 | 
				
			||||||
                                   'nova-compute',
 | 
					                                   'nova-compute',
 | 
				
			||||||
                                   'compute',
 | 
					                                   'compute',
 | 
				
			||||||
                                   FLAGS.compute_manager)
 | 
					                                   FLAGS.compute_manager)
 | 
				
			||||||
        compute2.startService()
 | 
					        compute2.start()
 | 
				
			||||||
        instance_id1 = self._create_instance()
 | 
					        instance_id1 = self._create_instance()
 | 
				
			||||||
        compute1.run_instance(self.context, instance_id1)
 | 
					        compute1.run_instance(self.context, instance_id1)
 | 
				
			||||||
        instance_id2 = self._create_instance()
 | 
					        instance_id2 = self._create_instance()
 | 
				
			||||||
@@ -162,12 +163,12 @@ class SimpleDriverTestCase(test.TrialTestCase):
 | 
				
			|||||||
                                   'nova-compute',
 | 
					                                   'nova-compute',
 | 
				
			||||||
                                   'compute',
 | 
					                                   'compute',
 | 
				
			||||||
                                   FLAGS.compute_manager)
 | 
					                                   FLAGS.compute_manager)
 | 
				
			||||||
        compute1.startService()
 | 
					        compute1.start()
 | 
				
			||||||
        compute2 = service.Service('host2',
 | 
					        compute2 = service.Service('host2',
 | 
				
			||||||
                                   'nova-compute',
 | 
					                                   'nova-compute',
 | 
				
			||||||
                                   'compute',
 | 
					                                   'compute',
 | 
				
			||||||
                                   FLAGS.compute_manager)
 | 
					                                   FLAGS.compute_manager)
 | 
				
			||||||
        compute2.startService()
 | 
					        compute2.start()
 | 
				
			||||||
        instance_ids1 = []
 | 
					        instance_ids1 = []
 | 
				
			||||||
        instance_ids2 = []
 | 
					        instance_ids2 = []
 | 
				
			||||||
        for index in xrange(FLAGS.max_cores):
 | 
					        for index in xrange(FLAGS.max_cores):
 | 
				
			||||||
@@ -195,12 +196,12 @@ class SimpleDriverTestCase(test.TrialTestCase):
 | 
				
			|||||||
                                   'nova-volume',
 | 
					                                   'nova-volume',
 | 
				
			||||||
                                   'volume',
 | 
					                                   'volume',
 | 
				
			||||||
                                   FLAGS.volume_manager)
 | 
					                                   FLAGS.volume_manager)
 | 
				
			||||||
        volume1.startService()
 | 
					        volume1.start()
 | 
				
			||||||
        volume2 = service.Service('host2',
 | 
					        volume2 = service.Service('host2',
 | 
				
			||||||
                                   'nova-volume',
 | 
					                                   'nova-volume',
 | 
				
			||||||
                                   'volume',
 | 
					                                   'volume',
 | 
				
			||||||
                                   FLAGS.volume_manager)
 | 
					                                   FLAGS.volume_manager)
 | 
				
			||||||
        volume2.startService()
 | 
					        volume2.start()
 | 
				
			||||||
        volume_id1 = self._create_volume()
 | 
					        volume_id1 = self._create_volume()
 | 
				
			||||||
        volume1.create_volume(self.context, volume_id1)
 | 
					        volume1.create_volume(self.context, volume_id1)
 | 
				
			||||||
        volume_id2 = self._create_volume()
 | 
					        volume_id2 = self._create_volume()
 | 
				
			||||||
@@ -218,12 +219,12 @@ class SimpleDriverTestCase(test.TrialTestCase):
 | 
				
			|||||||
                                   'nova-volume',
 | 
					                                   'nova-volume',
 | 
				
			||||||
                                   'volume',
 | 
					                                   'volume',
 | 
				
			||||||
                                   FLAGS.volume_manager)
 | 
					                                   FLAGS.volume_manager)
 | 
				
			||||||
        volume1.startService()
 | 
					        volume1.start()
 | 
				
			||||||
        volume2 = service.Service('host2',
 | 
					        volume2 = service.Service('host2',
 | 
				
			||||||
                                   'nova-volume',
 | 
					                                   'nova-volume',
 | 
				
			||||||
                                   'volume',
 | 
					                                   'volume',
 | 
				
			||||||
                                   FLAGS.volume_manager)
 | 
					                                   FLAGS.volume_manager)
 | 
				
			||||||
        volume2.startService()
 | 
					        volume2.start()
 | 
				
			||||||
        volume_ids1 = []
 | 
					        volume_ids1 = []
 | 
				
			||||||
        volume_ids2 = []
 | 
					        volume_ids2 = []
 | 
				
			||||||
        for index in xrange(FLAGS.max_gigabytes):
 | 
					        for index in xrange(FLAGS.max_gigabytes):
 | 
				
			||||||
@@ -30,9 +30,10 @@ FLAGS = flags.FLAGS
 | 
				
			|||||||
flags.DECLARE('instances_path', 'nova.compute.manager')
 | 
					flags.DECLARE('instances_path', 'nova.compute.manager')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class LibvirtConnTestCase(test.TrialTestCase):
 | 
					class LibvirtConnTestCase(test.TestCase):
 | 
				
			||||||
    def setUp(self):
 | 
					    def setUp(self):
 | 
				
			||||||
        super(LibvirtConnTestCase, self).setUp()
 | 
					        super(LibvirtConnTestCase, self).setUp()
 | 
				
			||||||
 | 
					        self.flags(fake_call=True)
 | 
				
			||||||
        self.manager = manager.AuthManager()
 | 
					        self.manager = manager.AuthManager()
 | 
				
			||||||
        self.user = self.manager.create_user('fake', 'fake', 'fake',
 | 
					        self.user = self.manager.create_user('fake', 'fake', 'fake',
 | 
				
			||||||
                                             admin=True)
 | 
					                                             admin=True)
 | 
				
			||||||
@@ -40,33 +41,64 @@ class LibvirtConnTestCase(test.TrialTestCase):
 | 
				
			|||||||
        self.network = utils.import_object(FLAGS.network_manager)
 | 
					        self.network = utils.import_object(FLAGS.network_manager)
 | 
				
			||||||
        FLAGS.instances_path = ''
 | 
					        FLAGS.instances_path = ''
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_get_uri_and_template(self):
 | 
					    test_ip = '10.11.12.13'
 | 
				
			||||||
        ip = '10.11.12.13'
 | 
					    test_instance = {'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 = {'internal_id': 1,
 | 
					    def test_xml_and_uri_no_ramdisk_no_kernel(self):
 | 
				
			||||||
                    'memory_kb': '1024000',
 | 
					        instance_data = dict(self.test_instance)
 | 
				
			||||||
                    'basepath': '/some/path',
 | 
					        self._check_xml_and_uri(instance_data,
 | 
				
			||||||
                    'bridge_name': 'br100',
 | 
					                                expect_kernel=False, expect_ramdisk=False)
 | 
				
			||||||
                    'mac_address': '02:12:34:46:56:67',
 | 
					 | 
				
			||||||
                    'vcpus': 2,
 | 
					 | 
				
			||||||
                    'project_id': 'fake',
 | 
					 | 
				
			||||||
                    'bridge': 'br101',
 | 
					 | 
				
			||||||
                    'instance_type': 'm1.small'}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_xml_and_uri_no_ramdisk(self):
 | 
				
			||||||
 | 
					        instance_data = dict(self.test_instance)
 | 
				
			||||||
 | 
					        instance_data['kernel_id'] = 'aki-deadbeef'
 | 
				
			||||||
 | 
					        self._check_xml_and_uri(instance_data,
 | 
				
			||||||
 | 
					                                expect_kernel=True, expect_ramdisk=False)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_xml_and_uri_no_kernel(self):
 | 
				
			||||||
 | 
					        instance_data = dict(self.test_instance)
 | 
				
			||||||
 | 
					        instance_data['ramdisk_id'] = 'ari-deadbeef'
 | 
				
			||||||
 | 
					        self._check_xml_and_uri(instance_data,
 | 
				
			||||||
 | 
					                                expect_kernel=False, expect_ramdisk=False)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_xml_and_uri(self):
 | 
				
			||||||
 | 
					        instance_data = dict(self.test_instance)
 | 
				
			||||||
 | 
					        instance_data['ramdisk_id'] = 'ari-deadbeef'
 | 
				
			||||||
 | 
					        instance_data['kernel_id'] = 'aki-deadbeef'
 | 
				
			||||||
 | 
					        self._check_xml_and_uri(instance_data,
 | 
				
			||||||
 | 
					                                expect_kernel=True, expect_ramdisk=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_xml_and_uri_rescue(self):
 | 
				
			||||||
 | 
					        instance_data = dict(self.test_instance)
 | 
				
			||||||
 | 
					        instance_data['ramdisk_id'] = 'ari-deadbeef'
 | 
				
			||||||
 | 
					        instance_data['kernel_id'] = 'aki-deadbeef'
 | 
				
			||||||
 | 
					        self._check_xml_and_uri(instance_data, expect_kernel=True,
 | 
				
			||||||
 | 
					                                expect_ramdisk=True, rescue=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _check_xml_and_uri(self, instance, expect_ramdisk, expect_kernel,
 | 
				
			||||||
 | 
					                           rescue=False):
 | 
				
			||||||
        user_context = context.RequestContext(project=self.project,
 | 
					        user_context = context.RequestContext(project=self.project,
 | 
				
			||||||
                                              user=self.user)
 | 
					                                              user=self.user)
 | 
				
			||||||
        instance_ref = db.instance_create(user_context, instance)
 | 
					        instance_ref = db.instance_create(user_context, instance)
 | 
				
			||||||
        network_ref = self.network.get_network(user_context)
 | 
					        host = self.network.get_network_host(user_context.elevated())
 | 
				
			||||||
        self.network.set_network_host(context.get_admin_context(),
 | 
					        network_ref = db.project_get_network(context.get_admin_context(),
 | 
				
			||||||
                                      network_ref['id'])
 | 
					                                             self.project.id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        fixed_ip = {'address': ip,
 | 
					        fixed_ip = {'address':    self.test_ip,
 | 
				
			||||||
                    'network_id': network_ref['id']}
 | 
					                    'network_id': network_ref['id']}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        ctxt = context.get_admin_context()
 | 
					        ctxt = context.get_admin_context()
 | 
				
			||||||
        fixed_ip_ref = db.fixed_ip_create(ctxt, fixed_ip)
 | 
					        fixed_ip_ref = db.fixed_ip_create(ctxt, fixed_ip)
 | 
				
			||||||
        db.fixed_ip_update(ctxt, ip, {'allocated': True,
 | 
					        db.fixed_ip_update(ctxt, self.test_ip,
 | 
				
			||||||
                                      'instance_id': instance_ref['id']})
 | 
					                                 {'allocated':   True,
 | 
				
			||||||
 | 
					                                  'instance_id': instance_ref['id']})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        type_uri_map = {'qemu': ('qemu:///system',
 | 
					        type_uri_map = {'qemu': ('qemu:///system',
 | 
				
			||||||
                             [(lambda t: t.find('.').get('type'), 'qemu'),
 | 
					                             [(lambda t: t.find('.').get('type'), 'qemu'),
 | 
				
			||||||
@@ -78,23 +110,73 @@ class LibvirtConnTestCase(test.TrialTestCase):
 | 
				
			|||||||
                              (lambda t: t.find('./devices/emulator'), None)]),
 | 
					                              (lambda t: t.find('./devices/emulator'), None)]),
 | 
				
			||||||
                        'uml': ('uml:///system',
 | 
					                        'uml': ('uml:///system',
 | 
				
			||||||
                             [(lambda t: t.find('.').get('type'), 'uml'),
 | 
					                             [(lambda t: t.find('.').get('type'), 'uml'),
 | 
				
			||||||
                              (lambda t: t.find('./os/type').text, 'uml')])}
 | 
					                              (lambda t: t.find('./os/type').text, 'uml')]),
 | 
				
			||||||
 | 
					                        'xen': ('xen:///',
 | 
				
			||||||
 | 
					                             [(lambda t: t.find('.').get('type'), 'xen'),
 | 
				
			||||||
 | 
					                              (lambda t: t.find('./os/type').text, 'linux')]),
 | 
				
			||||||
 | 
					                              }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for hypervisor_type in ['qemu', 'kvm', 'xen']:
 | 
				
			||||||
 | 
					            check_list = type_uri_map[hypervisor_type][1]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if rescue:
 | 
				
			||||||
 | 
					                check = (lambda t: t.find('./os/kernel').text.split('/')[1],
 | 
				
			||||||
 | 
					                         'rescue-kernel')
 | 
				
			||||||
 | 
					                check_list.append(check)
 | 
				
			||||||
 | 
					                check = (lambda t: t.find('./os/initrd').text.split('/')[1],
 | 
				
			||||||
 | 
					                         'rescue-ramdisk')
 | 
				
			||||||
 | 
					                check_list.append(check)
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                if expect_kernel:
 | 
				
			||||||
 | 
					                    check = (lambda t: t.find('./os/kernel').text.split(
 | 
				
			||||||
 | 
					                        '/')[1], 'kernel')
 | 
				
			||||||
 | 
					                else:
 | 
				
			||||||
 | 
					                    check = (lambda t: t.find('./os/kernel'), None)
 | 
				
			||||||
 | 
					                check_list.append(check)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if expect_ramdisk:
 | 
				
			||||||
 | 
					                    check = (lambda t: t.find('./os/initrd').text.split(
 | 
				
			||||||
 | 
					                        '/')[1], 'ramdisk')
 | 
				
			||||||
 | 
					                else:
 | 
				
			||||||
 | 
					                    check = (lambda t: t.find('./os/initrd'), None)
 | 
				
			||||||
 | 
					                check_list.append(check)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        common_checks = [
 | 
					        common_checks = [
 | 
				
			||||||
            (lambda t: t.find('.').tag, 'domain'),
 | 
					            (lambda t: t.find('.').tag, 'domain'),
 | 
				
			||||||
            (lambda t: t.find('./devices/interface/filterref/parameter').\
 | 
					            (lambda t: t.find(
 | 
				
			||||||
                         get('name'), 'IP'),
 | 
					                './devices/interface/filterref/parameter').get('name'), 'IP'),
 | 
				
			||||||
            (lambda t: t.find('./devices/interface/filterref/parameter').\
 | 
					            (lambda t: t.find(
 | 
				
			||||||
                         get('value'), '10.11.12.13')]
 | 
					                './devices/interface/filterref/parameter').get(
 | 
				
			||||||
 | 
					                    'value'), '10.11.12.13'),
 | 
				
			||||||
 | 
					            (lambda t: t.findall(
 | 
				
			||||||
 | 
					                './devices/interface/filterref/parameter')[1].get(
 | 
				
			||||||
 | 
					                    'name'), 'DHCPSERVER'),
 | 
				
			||||||
 | 
					            (lambda t: t.findall(
 | 
				
			||||||
 | 
					                './devices/interface/filterref/parameter')[1].get(
 | 
				
			||||||
 | 
					                    'value'), '10.0.0.1'),
 | 
				
			||||||
 | 
					            (lambda t: t.find('./devices/serial/source').get(
 | 
				
			||||||
 | 
					                'path').split('/')[1], 'console.log'),
 | 
				
			||||||
 | 
					            (lambda t: t.find('./memory').text, '2097152')]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if rescue:
 | 
				
			||||||
 | 
					            common_checks += [
 | 
				
			||||||
 | 
					                (lambda t: t.findall('./devices/disk/source')[0].get(
 | 
				
			||||||
 | 
					                    'file').split('/')[1], 'rescue-disk'),
 | 
				
			||||||
 | 
					                (lambda t: t.findall('./devices/disk/source')[1].get(
 | 
				
			||||||
 | 
					                    'file').split('/')[1], 'disk')]
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            common_checks += [(lambda t: t.findall(
 | 
				
			||||||
 | 
					                './devices/disk/source')[0].get('file').split('/')[1],
 | 
				
			||||||
 | 
					                               'disk')]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for (libvirt_type, (expected_uri, checks)) in type_uri_map.iteritems():
 | 
					        for (libvirt_type, (expected_uri, checks)) in type_uri_map.iteritems():
 | 
				
			||||||
            FLAGS.libvirt_type = libvirt_type
 | 
					            FLAGS.libvirt_type = libvirt_type
 | 
				
			||||||
            conn = libvirt_conn.LibvirtConnection(True)
 | 
					            conn = libvirt_conn.LibvirtConnection(True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            uri, _template, _rescue = conn.get_uri_and_templates()
 | 
					            uri = conn.get_uri()
 | 
				
			||||||
            self.assertEquals(uri, expected_uri)
 | 
					            self.assertEquals(uri, expected_uri)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            xml = conn.to_xml(instance_ref)
 | 
					            xml = conn.to_xml(instance_ref, rescue)
 | 
				
			||||||
            tree = xml_to_tree(xml)
 | 
					            tree = xml_to_tree(xml)
 | 
				
			||||||
            for i, (check, expected_result) in enumerate(checks):
 | 
					            for i, (check, expected_result) in enumerate(checks):
 | 
				
			||||||
                self.assertEqual(check(tree),
 | 
					                self.assertEqual(check(tree),
 | 
				
			||||||
@@ -106,6 +188,9 @@ class LibvirtConnTestCase(test.TrialTestCase):
 | 
				
			|||||||
                                 expected_result,
 | 
					                                 expected_result,
 | 
				
			||||||
                                 '%s failed common check %d' % (xml, i))
 | 
					                                 '%s failed common check %d' % (xml, i))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # This test is supposed to make sure we don't override a specifically
 | 
				
			||||||
 | 
					        # set uri
 | 
				
			||||||
 | 
					        #
 | 
				
			||||||
        # Deliberately not just assigning this string to FLAGS.libvirt_uri and
 | 
					        # Deliberately not just assigning this string to FLAGS.libvirt_uri and
 | 
				
			||||||
        # checking against that later on. This way we make sure the
 | 
					        # checking against that later on. This way we make sure the
 | 
				
			||||||
        # implementation doesn't fiddle around with the FLAGS.
 | 
					        # implementation doesn't fiddle around with the FLAGS.
 | 
				
			||||||
@@ -114,7 +199,7 @@ class LibvirtConnTestCase(test.TrialTestCase):
 | 
				
			|||||||
        for (libvirt_type, (expected_uri, checks)) in type_uri_map.iteritems():
 | 
					        for (libvirt_type, (expected_uri, checks)) in type_uri_map.iteritems():
 | 
				
			||||||
            FLAGS.libvirt_type = libvirt_type
 | 
					            FLAGS.libvirt_type = libvirt_type
 | 
				
			||||||
            conn = libvirt_conn.LibvirtConnection(True)
 | 
					            conn = libvirt_conn.LibvirtConnection(True)
 | 
				
			||||||
            uri, _template, _rescue = conn.get_uri_and_templates()
 | 
					            uri = conn.get_uri()
 | 
				
			||||||
            self.assertEquals(uri, testuri)
 | 
					            self.assertEquals(uri, testuri)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def tearDown(self):
 | 
					    def tearDown(self):
 | 
				
			||||||
@@ -123,7 +208,7 @@ class LibvirtConnTestCase(test.TrialTestCase):
 | 
				
			|||||||
        self.manager.delete_user(self.user)
 | 
					        self.manager.delete_user(self.user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class NWFilterTestCase(test.TrialTestCase):
 | 
					class NWFilterTestCase(test.TestCase):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def setUp(self):
 | 
					    def setUp(self):
 | 
				
			||||||
        super(NWFilterTestCase, self).setUp()
 | 
					        super(NWFilterTestCase, self).setUp()
 | 
				
			||||||
@@ -235,7 +320,7 @@ class NWFilterTestCase(test.TrialTestCase):
 | 
				
			|||||||
                                          'project_id': 'fake'})
 | 
					                                          'project_id': 'fake'})
 | 
				
			||||||
        inst_id = instance_ref['id']
 | 
					        inst_id = instance_ref['id']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        def _ensure_all_called(_):
 | 
					        def _ensure_all_called():
 | 
				
			||||||
            instance_filter = 'nova-instance-%s' % instance_ref['name']
 | 
					            instance_filter = 'nova-instance-%s' % instance_ref['name']
 | 
				
			||||||
            secgroup_filter = 'nova-secgroup-%s' % self.security_group['id']
 | 
					            secgroup_filter = 'nova-secgroup-%s' % self.security_group['id']
 | 
				
			||||||
            for required in [secgroup_filter, 'allow-dhcp-server',
 | 
					            for required in [secgroup_filter, 'allow-dhcp-server',
 | 
				
			||||||
@@ -252,8 +337,7 @@ class NWFilterTestCase(test.TrialTestCase):
 | 
				
			|||||||
                                       self.security_group.id)
 | 
					                                       self.security_group.id)
 | 
				
			||||||
        instance = db.instance_get(self.context, inst_id)
 | 
					        instance = db.instance_get(self.context, inst_id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        d = self.fw.setup_nwfilters_for_instance(instance)
 | 
					        self.fw.setup_base_nwfilters()
 | 
				
			||||||
        d.addCallback(_ensure_all_called)
 | 
					        self.fw.setup_nwfilters_for_instance(instance)
 | 
				
			||||||
        d.addCallback(lambda _: self.teardown_security_group())
 | 
					        _ensure_all_called()
 | 
				
			||||||
 | 
					        self.teardown_security_group()
 | 
				
			||||||
        return d
 | 
					 | 
				
			||||||
@@ -21,8 +21,6 @@ Tests for Volume Code.
 | 
				
			|||||||
"""
 | 
					"""
 | 
				
			||||||
import logging
 | 
					import logging
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from twisted.internet import defer
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from nova import context
 | 
					from nova import context
 | 
				
			||||||
from nova import exception
 | 
					from nova import exception
 | 
				
			||||||
from nova import db
 | 
					from nova import db
 | 
				
			||||||
@@ -33,7 +31,7 @@ from nova import utils
 | 
				
			|||||||
FLAGS = flags.FLAGS
 | 
					FLAGS = flags.FLAGS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class VolumeTestCase(test.TrialTestCase):
 | 
					class VolumeTestCase(test.TestCase):
 | 
				
			||||||
    """Test Case for volumes."""
 | 
					    """Test Case for volumes."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def setUp(self):
 | 
					    def setUp(self):
 | 
				
			||||||
@@ -56,51 +54,48 @@ class VolumeTestCase(test.TrialTestCase):
 | 
				
			|||||||
        vol['attach_status'] = "detached"
 | 
					        vol['attach_status'] = "detached"
 | 
				
			||||||
        return db.volume_create(context.get_admin_context(), vol)['id']
 | 
					        return db.volume_create(context.get_admin_context(), vol)['id']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @defer.inlineCallbacks
 | 
					 | 
				
			||||||
    def test_create_delete_volume(self):
 | 
					    def test_create_delete_volume(self):
 | 
				
			||||||
        """Test volume can be created and deleted."""
 | 
					        """Test volume can be created and deleted."""
 | 
				
			||||||
        volume_id = self._create_volume()
 | 
					        volume_id = self._create_volume()
 | 
				
			||||||
        yield self.volume.create_volume(self.context, volume_id)
 | 
					        self.volume.create_volume(self.context, volume_id)
 | 
				
			||||||
        self.assertEqual(volume_id, db.volume_get(context.get_admin_context(),
 | 
					        self.assertEqual(volume_id, db.volume_get(context.get_admin_context(),
 | 
				
			||||||
                         volume_id).id)
 | 
					                         volume_id).id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        yield self.volume.delete_volume(self.context, volume_id)
 | 
					        self.volume.delete_volume(self.context, volume_id)
 | 
				
			||||||
        self.assertRaises(exception.NotFound,
 | 
					        self.assertRaises(exception.NotFound,
 | 
				
			||||||
                          db.volume_get,
 | 
					                          db.volume_get,
 | 
				
			||||||
                          self.context,
 | 
					                          self.context,
 | 
				
			||||||
                          volume_id)
 | 
					                          volume_id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @defer.inlineCallbacks
 | 
					 | 
				
			||||||
    def test_too_big_volume(self):
 | 
					    def test_too_big_volume(self):
 | 
				
			||||||
        """Ensure failure if a too large of a volume is requested."""
 | 
					        """Ensure failure if a too large of a volume is requested."""
 | 
				
			||||||
        # FIXME(vish): validation needs to move into the data layer in
 | 
					        # FIXME(vish): validation needs to move into the data layer in
 | 
				
			||||||
        #              volume_create
 | 
					        #              volume_create
 | 
				
			||||||
        defer.returnValue(True)
 | 
					        return True
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
            volume_id = self._create_volume('1001')
 | 
					            volume_id = self._create_volume('1001')
 | 
				
			||||||
            yield self.volume.create_volume(self.context, volume_id)
 | 
					            self.volume.create_volume(self.context, volume_id)
 | 
				
			||||||
            self.fail("Should have thrown TypeError")
 | 
					            self.fail("Should have thrown TypeError")
 | 
				
			||||||
        except TypeError:
 | 
					        except TypeError:
 | 
				
			||||||
            pass
 | 
					            pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @defer.inlineCallbacks
 | 
					 | 
				
			||||||
    def test_too_many_volumes(self):
 | 
					    def test_too_many_volumes(self):
 | 
				
			||||||
        """Ensure that NoMoreTargets is raised when we run out of volumes."""
 | 
					        """Ensure that NoMoreTargets is raised when we run out of volumes."""
 | 
				
			||||||
        vols = []
 | 
					        vols = []
 | 
				
			||||||
        total_slots = FLAGS.iscsi_num_targets
 | 
					        total_slots = FLAGS.iscsi_num_targets
 | 
				
			||||||
        for _index in xrange(total_slots):
 | 
					        for _index in xrange(total_slots):
 | 
				
			||||||
            volume_id = self._create_volume()
 | 
					            volume_id = self._create_volume()
 | 
				
			||||||
            yield self.volume.create_volume(self.context, volume_id)
 | 
					            self.volume.create_volume(self.context, volume_id)
 | 
				
			||||||
            vols.append(volume_id)
 | 
					            vols.append(volume_id)
 | 
				
			||||||
        volume_id = self._create_volume()
 | 
					        volume_id = self._create_volume()
 | 
				
			||||||
        self.assertFailure(self.volume.create_volume(self.context,
 | 
					        self.assertRaises(db.NoMoreTargets,
 | 
				
			||||||
                                                     volume_id),
 | 
					                          self.volume.create_volume,
 | 
				
			||||||
                           db.NoMoreTargets)
 | 
					                          self.context,
 | 
				
			||||||
 | 
					                          volume_id)
 | 
				
			||||||
        db.volume_destroy(context.get_admin_context(), volume_id)
 | 
					        db.volume_destroy(context.get_admin_context(), volume_id)
 | 
				
			||||||
        for volume_id in vols:
 | 
					        for volume_id in vols:
 | 
				
			||||||
            yield self.volume.delete_volume(self.context, volume_id)
 | 
					            self.volume.delete_volume(self.context, volume_id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @defer.inlineCallbacks
 | 
					 | 
				
			||||||
    def test_run_attach_detach_volume(self):
 | 
					    def test_run_attach_detach_volume(self):
 | 
				
			||||||
        """Make sure volume can be attached and detached from instance."""
 | 
					        """Make sure volume can be attached and detached from instance."""
 | 
				
			||||||
        inst = {}
 | 
					        inst = {}
 | 
				
			||||||
@@ -115,15 +110,15 @@ class VolumeTestCase(test.TrialTestCase):
 | 
				
			|||||||
        instance_id = db.instance_create(self.context, inst)['id']
 | 
					        instance_id = db.instance_create(self.context, inst)['id']
 | 
				
			||||||
        mountpoint = "/dev/sdf"
 | 
					        mountpoint = "/dev/sdf"
 | 
				
			||||||
        volume_id = self._create_volume()
 | 
					        volume_id = self._create_volume()
 | 
				
			||||||
        yield self.volume.create_volume(self.context, volume_id)
 | 
					        self.volume.create_volume(self.context, volume_id)
 | 
				
			||||||
        if FLAGS.fake_tests:
 | 
					        if FLAGS.fake_tests:
 | 
				
			||||||
            db.volume_attached(self.context, volume_id, instance_id,
 | 
					            db.volume_attached(self.context, volume_id, instance_id,
 | 
				
			||||||
                               mountpoint)
 | 
					                               mountpoint)
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            yield self.compute.attach_volume(self.context,
 | 
					            self.compute.attach_volume(self.context,
 | 
				
			||||||
                                             instance_id,
 | 
					                                       instance_id,
 | 
				
			||||||
                                             volume_id,
 | 
					                                       volume_id,
 | 
				
			||||||
                                             mountpoint)
 | 
					                                       mountpoint)
 | 
				
			||||||
        vol = db.volume_get(context.get_admin_context(), volume_id)
 | 
					        vol = db.volume_get(context.get_admin_context(), volume_id)
 | 
				
			||||||
        self.assertEqual(vol['status'], "in-use")
 | 
					        self.assertEqual(vol['status'], "in-use")
 | 
				
			||||||
        self.assertEqual(vol['attach_status'], "attached")
 | 
					        self.assertEqual(vol['attach_status'], "attached")
 | 
				
			||||||
@@ -131,25 +126,26 @@ class VolumeTestCase(test.TrialTestCase):
 | 
				
			|||||||
        instance_ref = db.volume_get_instance(self.context, volume_id)
 | 
					        instance_ref = db.volume_get_instance(self.context, volume_id)
 | 
				
			||||||
        self.assertEqual(instance_ref['id'], instance_id)
 | 
					        self.assertEqual(instance_ref['id'], instance_id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.assertFailure(self.volume.delete_volume(self.context, volume_id),
 | 
					        self.assertRaises(exception.Error,
 | 
				
			||||||
                           exception.Error)
 | 
					                          self.volume.delete_volume,
 | 
				
			||||||
 | 
					                          self.context,
 | 
				
			||||||
 | 
					                          volume_id)
 | 
				
			||||||
        if FLAGS.fake_tests:
 | 
					        if FLAGS.fake_tests:
 | 
				
			||||||
            db.volume_detached(self.context, volume_id)
 | 
					            db.volume_detached(self.context, volume_id)
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            yield self.compute.detach_volume(self.context,
 | 
					            self.compute.detach_volume(self.context,
 | 
				
			||||||
                                             instance_id,
 | 
					                                       instance_id,
 | 
				
			||||||
                                             volume_id)
 | 
					                                       volume_id)
 | 
				
			||||||
        vol = db.volume_get(self.context, volume_id)
 | 
					        vol = db.volume_get(self.context, volume_id)
 | 
				
			||||||
        self.assertEqual(vol['status'], "available")
 | 
					        self.assertEqual(vol['status'], "available")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        yield self.volume.delete_volume(self.context, volume_id)
 | 
					        self.volume.delete_volume(self.context, volume_id)
 | 
				
			||||||
        self.assertRaises(exception.Error,
 | 
					        self.assertRaises(exception.Error,
 | 
				
			||||||
                          db.volume_get,
 | 
					                          db.volume_get,
 | 
				
			||||||
                          self.context,
 | 
					                          self.context,
 | 
				
			||||||
                          volume_id)
 | 
					                          volume_id)
 | 
				
			||||||
        db.instance_destroy(self.context, instance_id)
 | 
					        db.instance_destroy(self.context, instance_id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @defer.inlineCallbacks
 | 
					 | 
				
			||||||
    def test_concurrent_volumes_get_different_targets(self):
 | 
					    def test_concurrent_volumes_get_different_targets(self):
 | 
				
			||||||
        """Ensure multiple concurrent volumes get different targets."""
 | 
					        """Ensure multiple concurrent volumes get different targets."""
 | 
				
			||||||
        volume_ids = []
 | 
					        volume_ids = []
 | 
				
			||||||
@@ -164,15 +160,11 @@ class VolumeTestCase(test.TrialTestCase):
 | 
				
			|||||||
            self.assert_(iscsi_target not in targets)
 | 
					            self.assert_(iscsi_target not in targets)
 | 
				
			||||||
            targets.append(iscsi_target)
 | 
					            targets.append(iscsi_target)
 | 
				
			||||||
            logging.debug("Target %s allocated", iscsi_target)
 | 
					            logging.debug("Target %s allocated", iscsi_target)
 | 
				
			||||||
        deferreds = []
 | 
					 | 
				
			||||||
        total_slots = FLAGS.iscsi_num_targets
 | 
					        total_slots = FLAGS.iscsi_num_targets
 | 
				
			||||||
        for _index in xrange(total_slots):
 | 
					        for _index in xrange(total_slots):
 | 
				
			||||||
            volume_id = self._create_volume()
 | 
					            volume_id = self._create_volume()
 | 
				
			||||||
            d = self.volume.create_volume(self.context, volume_id)
 | 
					            d = self.volume.create_volume(self.context, volume_id)
 | 
				
			||||||
            d.addCallback(_check)
 | 
					            _check(d)
 | 
				
			||||||
            d.addErrback(self.fail)
 | 
					 | 
				
			||||||
            deferreds.append(d)
 | 
					 | 
				
			||||||
        yield defer.DeferredList(deferreds)
 | 
					 | 
				
			||||||
        for volume_id in volume_ids:
 | 
					        for volume_id in volume_ids:
 | 
				
			||||||
            self.volume.delete_volume(self.context, volume_id)
 | 
					            self.volume.delete_volume(self.context, volume_id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										220
									
								
								nova/tests/test_xenapi.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										220
									
								
								nova/tests/test_xenapi.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,220 @@
 | 
				
			|||||||
 | 
					# vim: tabstop=4 shiftwidth=4 softtabstop=4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#    Copyright (c) 2010 Citrix Systems, Inc.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					#    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.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					Test suite for XenAPI
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import stubout
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from nova import db
 | 
				
			||||||
 | 
					from nova import context
 | 
				
			||||||
 | 
					from nova import flags
 | 
				
			||||||
 | 
					from nova import test
 | 
				
			||||||
 | 
					from nova import utils
 | 
				
			||||||
 | 
					from nova.auth import manager
 | 
				
			||||||
 | 
					from nova.compute import instance_types
 | 
				
			||||||
 | 
					from nova.compute import power_state
 | 
				
			||||||
 | 
					from nova.virt import xenapi_conn
 | 
				
			||||||
 | 
					from nova.virt.xenapi import fake
 | 
				
			||||||
 | 
					from nova.virt.xenapi import volume_utils
 | 
				
			||||||
 | 
					from nova.tests.db import fakes
 | 
				
			||||||
 | 
					from nova.tests.xenapi import stubs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					FLAGS = flags.FLAGS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class XenAPIVolumeTestCase(test.TestCase):
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    Unit tests for Volume operations
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    def setUp(self):
 | 
				
			||||||
 | 
					        super(XenAPIVolumeTestCase, self).setUp()
 | 
				
			||||||
 | 
					        self.stubs = stubout.StubOutForTesting()
 | 
				
			||||||
 | 
					        FLAGS.target_host = '127.0.0.1'
 | 
				
			||||||
 | 
					        FLAGS.xenapi_connection_url = 'test_url'
 | 
				
			||||||
 | 
					        FLAGS.xenapi_connection_password = 'test_pass'
 | 
				
			||||||
 | 
					        fakes.stub_out_db_instance_api(self.stubs)
 | 
				
			||||||
 | 
					        stubs.stub_out_get_target(self.stubs)
 | 
				
			||||||
 | 
					        fake.reset()
 | 
				
			||||||
 | 
					        self.values = {'name': 1, 'id': 1,
 | 
				
			||||||
 | 
					                  'project_id': 'fake',
 | 
				
			||||||
 | 
					                  'user_id': 'fake',
 | 
				
			||||||
 | 
					                  'image_id': 1,
 | 
				
			||||||
 | 
					                  'kernel_id': 2,
 | 
				
			||||||
 | 
					                  'ramdisk_id': 3,
 | 
				
			||||||
 | 
					                  'instance_type': 'm1.large',
 | 
				
			||||||
 | 
					                  'mac_address': 'aa:bb:cc:dd:ee:ff',
 | 
				
			||||||
 | 
					                  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _create_volume(self, size='0'):
 | 
				
			||||||
 | 
					        """Create a volume object."""
 | 
				
			||||||
 | 
					        vol = {}
 | 
				
			||||||
 | 
					        vol['size'] = size
 | 
				
			||||||
 | 
					        vol['user_id'] = 'fake'
 | 
				
			||||||
 | 
					        vol['project_id'] = 'fake'
 | 
				
			||||||
 | 
					        vol['host'] = 'localhost'
 | 
				
			||||||
 | 
					        vol['availability_zone'] = FLAGS.storage_availability_zone
 | 
				
			||||||
 | 
					        vol['status'] = "creating"
 | 
				
			||||||
 | 
					        vol['attach_status'] = "detached"
 | 
				
			||||||
 | 
					        return db.volume_create(context.get_admin_context(), vol)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_create_iscsi_storage(self):
 | 
				
			||||||
 | 
					        """ This shows how to test helper classes' methods """
 | 
				
			||||||
 | 
					        stubs.stubout_session(self.stubs, stubs.FakeSessionForVolumeTests)
 | 
				
			||||||
 | 
					        session = xenapi_conn.XenAPISession('test_url', 'root', 'test_pass')
 | 
				
			||||||
 | 
					        helper = volume_utils.VolumeHelper
 | 
				
			||||||
 | 
					        helper.XenAPI = session.get_imported_xenapi()
 | 
				
			||||||
 | 
					        vol = self._create_volume()
 | 
				
			||||||
 | 
					        info = helper.parse_volume_info(vol['ec2_id'], '/dev/sdc')
 | 
				
			||||||
 | 
					        label = 'SR-%s' % vol['ec2_id']
 | 
				
			||||||
 | 
					        description = 'Test-SR'
 | 
				
			||||||
 | 
					        sr_ref = helper.create_iscsi_storage(session, info, label, description)
 | 
				
			||||||
 | 
					        srs = fake.get_all('SR')
 | 
				
			||||||
 | 
					        self.assertEqual(sr_ref, srs[0])
 | 
				
			||||||
 | 
					        db.volume_destroy(context.get_admin_context(), vol['id'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_parse_volume_info_raise_exception(self):
 | 
				
			||||||
 | 
					        """ This shows how to test helper classes' methods """
 | 
				
			||||||
 | 
					        stubs.stubout_session(self.stubs, stubs.FakeSessionForVolumeTests)
 | 
				
			||||||
 | 
					        session = xenapi_conn.XenAPISession('test_url', 'root', 'test_pass')
 | 
				
			||||||
 | 
					        helper = volume_utils.VolumeHelper
 | 
				
			||||||
 | 
					        helper.XenAPI = session.get_imported_xenapi()
 | 
				
			||||||
 | 
					        vol = self._create_volume()
 | 
				
			||||||
 | 
					        # oops, wrong mount point!
 | 
				
			||||||
 | 
					        self.assertRaises(volume_utils.StorageError,
 | 
				
			||||||
 | 
					                          helper.parse_volume_info,
 | 
				
			||||||
 | 
					                          vol['ec2_id'],
 | 
				
			||||||
 | 
					                          '/dev/sd')
 | 
				
			||||||
 | 
					        db.volume_destroy(context.get_admin_context(), vol['id'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_attach_volume(self):
 | 
				
			||||||
 | 
					        """ This shows how to test Ops classes' methods """
 | 
				
			||||||
 | 
					        stubs.stubout_session(self.stubs, stubs.FakeSessionForVolumeTests)
 | 
				
			||||||
 | 
					        conn = xenapi_conn.get_connection(False)
 | 
				
			||||||
 | 
					        volume = self._create_volume()
 | 
				
			||||||
 | 
					        instance = db.instance_create(self.values)
 | 
				
			||||||
 | 
					        fake.create_vm(instance.name, 'Running')
 | 
				
			||||||
 | 
					        result = conn.attach_volume(instance.name, volume['ec2_id'],
 | 
				
			||||||
 | 
					                                    '/dev/sdc')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        def check():
 | 
				
			||||||
 | 
					            # check that the VM has a VBD attached to it
 | 
				
			||||||
 | 
					            # Get XenAPI reference for the VM
 | 
				
			||||||
 | 
					            vms = fake.get_all('VM')
 | 
				
			||||||
 | 
					            # Get XenAPI record for VBD
 | 
				
			||||||
 | 
					            vbds = fake.get_all('VBD')
 | 
				
			||||||
 | 
					            vbd = fake.get_record('VBD', vbds[0])
 | 
				
			||||||
 | 
					            vm_ref = vbd['VM']
 | 
				
			||||||
 | 
					            self.assertEqual(vm_ref, vms[0])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        check()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_attach_volume_raise_exception(self):
 | 
				
			||||||
 | 
					        """ This shows how to test when exceptions are raised """
 | 
				
			||||||
 | 
					        stubs.stubout_session(self.stubs,
 | 
				
			||||||
 | 
					                              stubs.FakeSessionForVolumeFailedTests)
 | 
				
			||||||
 | 
					        conn = xenapi_conn.get_connection(False)
 | 
				
			||||||
 | 
					        volume = self._create_volume()
 | 
				
			||||||
 | 
					        instance = db.instance_create(self.values)
 | 
				
			||||||
 | 
					        fake.create_vm(instance.name, 'Running')
 | 
				
			||||||
 | 
					        self.assertRaises(Exception,
 | 
				
			||||||
 | 
					                          conn.attach_volume,
 | 
				
			||||||
 | 
					                          instance.name,
 | 
				
			||||||
 | 
					                          volume['ec2_id'],
 | 
				
			||||||
 | 
					                          '/dev/sdc')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def tearDown(self):
 | 
				
			||||||
 | 
					        super(XenAPIVolumeTestCase, self).tearDown()
 | 
				
			||||||
 | 
					        self.stubs.UnsetAll()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class XenAPIVMTestCase(test.TestCase):
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    Unit tests for VM operations
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    def setUp(self):
 | 
				
			||||||
 | 
					        super(XenAPIVMTestCase, 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)
 | 
				
			||||||
 | 
					        self.stubs = stubout.StubOutForTesting()
 | 
				
			||||||
 | 
					        FLAGS.xenapi_connection_url = 'test_url'
 | 
				
			||||||
 | 
					        FLAGS.xenapi_connection_password = 'test_pass'
 | 
				
			||||||
 | 
					        fake.reset()
 | 
				
			||||||
 | 
					        fakes.stub_out_db_instance_api(self.stubs)
 | 
				
			||||||
 | 
					        fake.create_network('fake', FLAGS.flat_network_bridge)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_list_instances_0(self):
 | 
				
			||||||
 | 
					        stubs.stubout_session(self.stubs, stubs.FakeSessionForVMTests)
 | 
				
			||||||
 | 
					        conn = xenapi_conn.get_connection(False)
 | 
				
			||||||
 | 
					        instances = conn.list_instances()
 | 
				
			||||||
 | 
					        self.assertEquals(instances, [])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_spawn(self):
 | 
				
			||||||
 | 
					        stubs.stubout_session(self.stubs, stubs.FakeSessionForVMTests)
 | 
				
			||||||
 | 
					        values = {'name': 1, 'id': 1,
 | 
				
			||||||
 | 
					                  'project_id': self.project.id,
 | 
				
			||||||
 | 
					                  'user_id': self.user.id,
 | 
				
			||||||
 | 
					                  'image_id': 1,
 | 
				
			||||||
 | 
					                  'kernel_id': 2,
 | 
				
			||||||
 | 
					                  'ramdisk_id': 3,
 | 
				
			||||||
 | 
					                  'instance_type': 'm1.large',
 | 
				
			||||||
 | 
					                  'mac_address': 'aa:bb:cc:dd:ee:ff',
 | 
				
			||||||
 | 
					                  }
 | 
				
			||||||
 | 
					        conn = xenapi_conn.get_connection(False)
 | 
				
			||||||
 | 
					        instance = db.instance_create(values)
 | 
				
			||||||
 | 
					        conn.spawn(instance)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        def check():
 | 
				
			||||||
 | 
					            instances = conn.list_instances()
 | 
				
			||||||
 | 
					            self.assertEquals(instances, [1])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            # Get Nova record for VM
 | 
				
			||||||
 | 
					            vm_info = conn.get_info(1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            # Get XenAPI record for VM
 | 
				
			||||||
 | 
					            vms = fake.get_all('VM')
 | 
				
			||||||
 | 
					            vm = fake.get_record('VM', vms[0])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            # Check that m1.large above turned into the right thing.
 | 
				
			||||||
 | 
					            instance_type = instance_types.INSTANCE_TYPES['m1.large']
 | 
				
			||||||
 | 
					            mem_kib = long(instance_type['memory_mb']) << 10
 | 
				
			||||||
 | 
					            mem_bytes = str(mem_kib << 10)
 | 
				
			||||||
 | 
					            vcpus = instance_type['vcpus']
 | 
				
			||||||
 | 
					            self.assertEquals(vm_info['max_mem'], mem_kib)
 | 
				
			||||||
 | 
					            self.assertEquals(vm_info['mem'], mem_kib)
 | 
				
			||||||
 | 
					            self.assertEquals(vm['memory_static_max'], mem_bytes)
 | 
				
			||||||
 | 
					            self.assertEquals(vm['memory_dynamic_max'], mem_bytes)
 | 
				
			||||||
 | 
					            self.assertEquals(vm['memory_dynamic_min'], mem_bytes)
 | 
				
			||||||
 | 
					            self.assertEquals(vm['VCPUs_max'], str(vcpus))
 | 
				
			||||||
 | 
					            self.assertEquals(vm['VCPUs_at_startup'], str(vcpus))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            # Check that the VM is running according to Nova
 | 
				
			||||||
 | 
					            self.assertEquals(vm_info['state'], power_state.RUNNING)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            # Check that the VM is running according to XenAPI.
 | 
				
			||||||
 | 
					            self.assertEquals(vm['power_state'], 'Running')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        check()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def tearDown(self):
 | 
				
			||||||
 | 
					        super(XenAPIVMTestCase, self).tearDown()
 | 
				
			||||||
 | 
					        self.manager.delete_project(self.project)
 | 
				
			||||||
 | 
					        self.manager.delete_user(self.user)
 | 
				
			||||||
 | 
					        self.stubs.UnsetAll()
 | 
				
			||||||
							
								
								
									
										20
									
								
								nova/tests/xenapi/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								nova/tests/xenapi/__init__.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,20 @@
 | 
				
			|||||||
 | 
					# vim: tabstop=4 shiftwidth=4 softtabstop=4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#    Copyright (c) 2010 Citrix Systems, Inc.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					#    Licensed under the Apache License, Version 2.0 (the "License"); you may
 | 
				
			||||||
 | 
					#    not use this file except in compliance with the License. You may obtain
 | 
				
			||||||
 | 
					#    a copy of the License at
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					#         http://www.apache.org/licenses/LICENSE-2.0
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					#    Unless required by applicable law or agreed to in writing, software
 | 
				
			||||||
 | 
					#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
				
			||||||
 | 
					#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
				
			||||||
 | 
					#    License for the specific language governing permissions and limitations
 | 
				
			||||||
 | 
					#    under the License.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					:mod:`xenapi` -- Stubs for XenAPI
 | 
				
			||||||
 | 
					=================================
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
							
								
								
									
										103
									
								
								nova/tests/xenapi/stubs.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								nova/tests/xenapi/stubs.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,103 @@
 | 
				
			|||||||
 | 
					# vim: tabstop=4 shiftwidth=4 softtabstop=4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Copyright (c) 2010 Citrix Systems, Inc.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					#    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.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					"""Stubouts, mocks and fixtures for the test suite"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from nova.virt import xenapi_conn
 | 
				
			||||||
 | 
					from nova.virt.xenapi import fake
 | 
				
			||||||
 | 
					from nova.virt.xenapi import volume_utils
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def stubout_session(stubs, cls):
 | 
				
			||||||
 | 
					    """Stubs out two methods from XenAPISession"""
 | 
				
			||||||
 | 
					    def fake_import(self):
 | 
				
			||||||
 | 
					        """Stubs out get_imported_xenapi of XenAPISession"""
 | 
				
			||||||
 | 
					        fake_module = 'nova.virt.xenapi.fake'
 | 
				
			||||||
 | 
					        from_list = ['fake']
 | 
				
			||||||
 | 
					        return __import__(fake_module, globals(), locals(), from_list, -1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    stubs.Set(xenapi_conn.XenAPISession, '_create_session',
 | 
				
			||||||
 | 
					                       lambda s, url: cls(url))
 | 
				
			||||||
 | 
					    stubs.Set(xenapi_conn.XenAPISession, 'get_imported_xenapi',
 | 
				
			||||||
 | 
					                       fake_import)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def stub_out_get_target(stubs):
 | 
				
			||||||
 | 
					    """Stubs out _get_target in volume_utils"""
 | 
				
			||||||
 | 
					    def fake_get_target(volume_id):
 | 
				
			||||||
 | 
					        return (None, None)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    stubs.Set(volume_utils, '_get_target', fake_get_target)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class FakeSessionForVMTests(fake.SessionBase):
 | 
				
			||||||
 | 
					    """ Stubs out a XenAPISession for VM tests """
 | 
				
			||||||
 | 
					    def __init__(self, uri):
 | 
				
			||||||
 | 
					        super(FakeSessionForVMTests, self).__init__(uri)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def network_get_all_records_where(self, _1, _2):
 | 
				
			||||||
 | 
					        return self.xenapi.network.get_all_records()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def host_call_plugin(self, _1, _2, _3, _4, _5):
 | 
				
			||||||
 | 
					        return ''
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def VM_start(self, _1, ref, _2, _3):
 | 
				
			||||||
 | 
					        vm = fake.get_record('VM', ref)
 | 
				
			||||||
 | 
					        if vm['power_state'] != 'Halted':
 | 
				
			||||||
 | 
					            raise fake.Failure(['VM_BAD_POWER_STATE', ref, 'Halted',
 | 
				
			||||||
 | 
					                                  vm['power_state']])
 | 
				
			||||||
 | 
					        vm['power_state'] = 'Running'
 | 
				
			||||||
 | 
					        vm['is_a_template'] = False
 | 
				
			||||||
 | 
					        vm['is_control_domain'] = False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class FakeSessionForVolumeTests(fake.SessionBase):
 | 
				
			||||||
 | 
					    """ Stubs out a XenAPISession for Volume tests """
 | 
				
			||||||
 | 
					    def __init__(self, uri):
 | 
				
			||||||
 | 
					        super(FakeSessionForVolumeTests, self).__init__(uri)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def VBD_plug(self, _1, ref):
 | 
				
			||||||
 | 
					        rec = fake.get_record('VBD', ref)
 | 
				
			||||||
 | 
					        rec['currently-attached'] = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def VDI_introduce(self, _1, uuid, _2, _3, _4, _5,
 | 
				
			||||||
 | 
					                      _6, _7, _8, _9, _10, _11):
 | 
				
			||||||
 | 
					        valid_vdi = False
 | 
				
			||||||
 | 
					        refs = fake.get_all('VDI')
 | 
				
			||||||
 | 
					        for ref in refs:
 | 
				
			||||||
 | 
					            rec = fake.get_record('VDI', ref)
 | 
				
			||||||
 | 
					            if rec['uuid'] == uuid:
 | 
				
			||||||
 | 
					                valid_vdi = True
 | 
				
			||||||
 | 
					        if not valid_vdi:
 | 
				
			||||||
 | 
					            raise fake.Failure([['INVALID_VDI', 'session', self._session]])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class FakeSessionForVolumeFailedTests(FakeSessionForVolumeTests):
 | 
				
			||||||
 | 
					    """ Stubs out a XenAPISession for Volume tests: it injects failures """
 | 
				
			||||||
 | 
					    def __init__(self, uri):
 | 
				
			||||||
 | 
					        super(FakeSessionForVolumeFailedTests, self).__init__(uri)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def VDI_introduce(self, _1, uuid, _2, _3, _4, _5,
 | 
				
			||||||
 | 
					                      _6, _7, _8, _9, _10, _11):
 | 
				
			||||||
 | 
					        # This is for testing failure
 | 
				
			||||||
 | 
					        raise fake.Failure([['INVALID_VDI', 'session', self._session]])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def PBD_unplug(self, _1, ref):
 | 
				
			||||||
 | 
					        rec = fake.get_record('PBD', ref)
 | 
				
			||||||
 | 
					        rec['currently-attached'] = False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def SR_forget(self, _1, ref):
 | 
				
			||||||
 | 
					        pass
 | 
				
			||||||
@@ -43,7 +43,7 @@ else:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
FLAGS = flags.FLAGS
 | 
					FLAGS = flags.FLAGS
 | 
				
			||||||
flags.DEFINE_string('logdir',  None, 'directory to keep log files in '
 | 
					flags.DEFINE_string('logdir', None, 'directory to keep log files in '
 | 
				
			||||||
                                     '(will be prepended to $logfile)')
 | 
					                                     '(will be prepended to $logfile)')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -208,7 +208,7 @@ def stop(pidfile):
 | 
				
			|||||||
        pid = None
 | 
					        pid = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if not pid:
 | 
					    if not pid:
 | 
				
			||||||
        message = "pidfile %s does not exist. Daemon not running?\n"
 | 
					        message = _("pidfile %s does not exist. Daemon not running?\n")
 | 
				
			||||||
        sys.stderr.write(message % pidfile)
 | 
					        sys.stderr.write(message % pidfile)
 | 
				
			||||||
        # Not an error in a restart
 | 
					        # Not an error in a restart
 | 
				
			||||||
        return
 | 
					        return
 | 
				
			||||||
@@ -229,7 +229,7 @@ def stop(pidfile):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def serve(filename):
 | 
					def serve(filename):
 | 
				
			||||||
    logging.debug("Serving %s" % filename)
 | 
					    logging.debug(_("Serving %s") % filename)
 | 
				
			||||||
    name = os.path.basename(filename)
 | 
					    name = os.path.basename(filename)
 | 
				
			||||||
    OptionsClass = WrapTwistedOptions(TwistdServerOptions)
 | 
					    OptionsClass = WrapTwistedOptions(TwistdServerOptions)
 | 
				
			||||||
    options = OptionsClass()
 | 
					    options = OptionsClass()
 | 
				
			||||||
@@ -281,7 +281,7 @@ def serve(filename):
 | 
				
			|||||||
    else:
 | 
					    else:
 | 
				
			||||||
        logging.getLogger().setLevel(logging.WARNING)
 | 
					        logging.getLogger().setLevel(logging.WARNING)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    logging.debug("Full set of FLAGS:")
 | 
					    logging.debug(_("Full set of FLAGS:"))
 | 
				
			||||||
    for flag in FLAGS:
 | 
					    for flag in FLAGS:
 | 
				
			||||||
        logging.debug("%s : %s" % (flag, FLAGS.get(flag, None)))
 | 
					        logging.debug("%s : %s" % (flag, FLAGS.get(flag, None)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										159
									
								
								nova/utils.py
									
									
									
									
									
								
							
							
						
						
									
										159
									
								
								nova/utils.py
									
									
									
									
									
								
							@@ -21,24 +21,24 @@ System-level utilities and helper functions.
 | 
				
			|||||||
"""
 | 
					"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import datetime
 | 
					import datetime
 | 
				
			||||||
import functools
 | 
					 | 
				
			||||||
import inspect
 | 
					import inspect
 | 
				
			||||||
import logging
 | 
					import logging
 | 
				
			||||||
import os
 | 
					import os
 | 
				
			||||||
import random
 | 
					import random
 | 
				
			||||||
import subprocess
 | 
					import subprocess
 | 
				
			||||||
import socket
 | 
					import socket
 | 
				
			||||||
 | 
					import struct
 | 
				
			||||||
import sys
 | 
					import sys
 | 
				
			||||||
 | 
					import time
 | 
				
			||||||
from xml.sax import saxutils
 | 
					from xml.sax import saxutils
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from twisted.internet.threads import deferToThread
 | 
					from eventlet import event
 | 
				
			||||||
 | 
					from eventlet import greenthread
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from nova import exception
 | 
					from nova import exception
 | 
				
			||||||
from nova import flags
 | 
					 | 
				
			||||||
from nova.exception import ProcessExecutionError
 | 
					from nova.exception import ProcessExecutionError
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
FLAGS = flags.FLAGS
 | 
					 | 
				
			||||||
TIME_FORMAT = "%Y-%m-%dT%H:%M:%SZ"
 | 
					TIME_FORMAT = "%Y-%m-%dT%H:%M:%SZ"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -49,7 +49,7 @@ def import_class(import_str):
 | 
				
			|||||||
        __import__(mod_str)
 | 
					        __import__(mod_str)
 | 
				
			||||||
        return getattr(sys.modules[mod_str], class_str)
 | 
					        return getattr(sys.modules[mod_str], class_str)
 | 
				
			||||||
    except (ImportError, ValueError, AttributeError):
 | 
					    except (ImportError, ValueError, AttributeError):
 | 
				
			||||||
        raise exception.NotFound('Class %s cannot be found' % class_str)
 | 
					        raise exception.NotFound(_('Class %s cannot be found') % class_str)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def import_object(import_str):
 | 
					def import_object(import_str):
 | 
				
			||||||
@@ -62,8 +62,53 @@ def import_object(import_str):
 | 
				
			|||||||
        return cls()
 | 
					        return cls()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def vpn_ping(address, port, timeout=0.05, session_id=None):
 | 
				
			||||||
 | 
					    """Sends a vpn negotiation packet and returns the server session.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Returns False on a failure. Basic packet structure is below.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Client packet (14 bytes)::
 | 
				
			||||||
 | 
					     0 1      8 9  13
 | 
				
			||||||
 | 
					    +-+--------+-----+
 | 
				
			||||||
 | 
					    |x| cli_id |?????|
 | 
				
			||||||
 | 
					    +-+--------+-----+
 | 
				
			||||||
 | 
					    x = packet identifier 0x38
 | 
				
			||||||
 | 
					    cli_id = 64 bit identifier
 | 
				
			||||||
 | 
					    ? = unknown, probably flags/padding
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Server packet (26 bytes)::
 | 
				
			||||||
 | 
					     0 1      8 9  13 14    21 2225
 | 
				
			||||||
 | 
					    +-+--------+-----+--------+----+
 | 
				
			||||||
 | 
					    |x| srv_id |?????| cli_id |????|
 | 
				
			||||||
 | 
					    +-+--------+-----+--------+----+
 | 
				
			||||||
 | 
					    x = packet identifier 0x40
 | 
				
			||||||
 | 
					    cli_id = 64 bit identifier
 | 
				
			||||||
 | 
					    ? = unknown, probably flags/padding
 | 
				
			||||||
 | 
					    bit 9 was 1 and the rest were 0 in testing
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    if session_id is None:
 | 
				
			||||||
 | 
					        session_id = random.randint(0, 0xffffffffffffffff)
 | 
				
			||||||
 | 
					    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
 | 
				
			||||||
 | 
					    data = struct.pack("!BQxxxxxx", 0x38, session_id)
 | 
				
			||||||
 | 
					    sock.sendto(data, (address, port))
 | 
				
			||||||
 | 
					    sock.settimeout(timeout)
 | 
				
			||||||
 | 
					    try:
 | 
				
			||||||
 | 
					        received = sock.recv(2048)
 | 
				
			||||||
 | 
					    except socket.timeout:
 | 
				
			||||||
 | 
					        return False
 | 
				
			||||||
 | 
					    finally:
 | 
				
			||||||
 | 
					        sock.close()
 | 
				
			||||||
 | 
					    fmt = "!BQxxxxxQxxxx"
 | 
				
			||||||
 | 
					    if len(received) != struct.calcsize(fmt):
 | 
				
			||||||
 | 
					        print struct.calcsize(fmt)
 | 
				
			||||||
 | 
					        return False
 | 
				
			||||||
 | 
					    (identifier, server_sess, client_sess) = struct.unpack(fmt, received)
 | 
				
			||||||
 | 
					    if identifier == 0x40 and client_sess == session_id:
 | 
				
			||||||
 | 
					        return server_sess
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def fetchfile(url, target):
 | 
					def fetchfile(url, target):
 | 
				
			||||||
    logging.debug("Fetching %s" % url)
 | 
					    logging.debug(_("Fetching %s") % url)
 | 
				
			||||||
#    c = pycurl.Curl()
 | 
					#    c = pycurl.Curl()
 | 
				
			||||||
#    fp = open(target, "wb")
 | 
					#    fp = open(target, "wb")
 | 
				
			||||||
#    c.setopt(c.URL, url)
 | 
					#    c.setopt(c.URL, url)
 | 
				
			||||||
@@ -75,7 +120,7 @@ def fetchfile(url, target):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def execute(cmd, process_input=None, addl_env=None, check_exit_code=True):
 | 
					def execute(cmd, process_input=None, addl_env=None, check_exit_code=True):
 | 
				
			||||||
    logging.debug("Running cmd: %s", cmd)
 | 
					    logging.debug(_("Running cmd (subprocess): %s"), cmd)
 | 
				
			||||||
    env = os.environ.copy()
 | 
					    env = os.environ.copy()
 | 
				
			||||||
    if addl_env:
 | 
					    if addl_env:
 | 
				
			||||||
        env.update(addl_env)
 | 
					        env.update(addl_env)
 | 
				
			||||||
@@ -88,13 +133,16 @@ def execute(cmd, process_input=None, addl_env=None, check_exit_code=True):
 | 
				
			|||||||
        result = obj.communicate()
 | 
					        result = obj.communicate()
 | 
				
			||||||
    obj.stdin.close()
 | 
					    obj.stdin.close()
 | 
				
			||||||
    if obj.returncode:
 | 
					    if obj.returncode:
 | 
				
			||||||
        logging.debug("Result was %s" % (obj.returncode))
 | 
					 | 
				
			||||||
        if check_exit_code and obj.returncode != 0:
 | 
					        if check_exit_code and obj.returncode != 0:
 | 
				
			||||||
            (stdout, stderr) = result
 | 
					            (stdout, stderr) = result
 | 
				
			||||||
            raise ProcessExecutionError(exit_code=obj.returncode,
 | 
					            raise ProcessExecutionError(exit_code=obj.returncode,
 | 
				
			||||||
                                        stdout=stdout,
 | 
					                                        stdout=stdout,
 | 
				
			||||||
                                        stderr=stderr,
 | 
					                                        stderr=stderr,
 | 
				
			||||||
                                        cmd=cmd)
 | 
					                                        cmd=cmd)
 | 
				
			||||||
 | 
					    # NOTE(termie): this appears to be necessary to let the subprocess call
 | 
				
			||||||
 | 
					    #               clean something up in between calls, without it two
 | 
				
			||||||
 | 
					    #               execute calls in a row hangs the second one
 | 
				
			||||||
 | 
					    greenthread.sleep(0)
 | 
				
			||||||
    return result
 | 
					    return result
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -122,14 +170,8 @@ def debug(arg):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def runthis(prompt, cmd, check_exit_code=True):
 | 
					def runthis(prompt, cmd, check_exit_code=True):
 | 
				
			||||||
    logging.debug("Running %s" % (cmd))
 | 
					    logging.debug(_("Running %s") % (cmd))
 | 
				
			||||||
    exit_code = subprocess.call(cmd.split(" "))
 | 
					    rv, err = execute(cmd, check_exit_code=check_exit_code)
 | 
				
			||||||
    logging.debug(prompt % (exit_code))
 | 
					 | 
				
			||||||
    if check_exit_code and exit_code != 0:
 | 
					 | 
				
			||||||
        raise ProcessExecutionError(exit_code=exit_code,
 | 
					 | 
				
			||||||
                                    stdout=None,
 | 
					 | 
				
			||||||
                                    stderr=None,
 | 
					 | 
				
			||||||
                                    cmd=cmd)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def generate_uid(topic, size=8):
 | 
					def generate_uid(topic, size=8):
 | 
				
			||||||
@@ -159,8 +201,6 @@ def last_octet(address):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
def get_my_ip():
 | 
					def get_my_ip():
 | 
				
			||||||
    """Returns the actual ip of the local machine."""
 | 
					    """Returns the actual ip of the local machine."""
 | 
				
			||||||
    if getattr(FLAGS, 'fake_tests', None):
 | 
					 | 
				
			||||||
        return '127.0.0.1'
 | 
					 | 
				
			||||||
    try:
 | 
					    try:
 | 
				
			||||||
        csock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
 | 
					        csock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
 | 
				
			||||||
        csock.connect(('8.8.8.8', 80))
 | 
					        csock.connect(('8.8.8.8', 80))
 | 
				
			||||||
@@ -168,17 +208,55 @@ def get_my_ip():
 | 
				
			|||||||
        csock.close()
 | 
					        csock.close()
 | 
				
			||||||
        return addr
 | 
					        return addr
 | 
				
			||||||
    except socket.gaierror as ex:
 | 
					    except socket.gaierror as ex:
 | 
				
			||||||
        logging.warn("Couldn't get IP, using 127.0.0.1 %s", ex)
 | 
					        logging.warn(_("Couldn't get IP, using 127.0.0.1 %s"), ex)
 | 
				
			||||||
        return "127.0.0.1"
 | 
					        return "127.0.0.1"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def utcnow():
 | 
				
			||||||
 | 
					    """Overridable version of datetime.datetime.utcnow."""
 | 
				
			||||||
 | 
					    if utcnow.override_time:
 | 
				
			||||||
 | 
					        return utcnow.override_time
 | 
				
			||||||
 | 
					    return datetime.datetime.utcnow()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					utcnow.override_time = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def utcnow_ts():
 | 
				
			||||||
 | 
					    """Timestamp version of our utcnow function."""
 | 
				
			||||||
 | 
					    return time.mktime(utcnow().timetuple())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def set_time_override(override_time=datetime.datetime.utcnow()):
 | 
				
			||||||
 | 
					    """Override utils.utcnow to return a constant time."""
 | 
				
			||||||
 | 
					    utcnow.override_time = override_time
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def advance_time_delta(timedelta):
 | 
				
			||||||
 | 
					    """Advance overriden time using a datetime.timedelta."""
 | 
				
			||||||
 | 
					    assert(not utcnow.override_time is None)
 | 
				
			||||||
 | 
					    utcnow.override_time += timedelta
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def advance_time_seconds(seconds):
 | 
				
			||||||
 | 
					    """Advance overriden time by seconds."""
 | 
				
			||||||
 | 
					    advance_time_delta(datetime.timedelta(0, seconds))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def clear_time_override():
 | 
				
			||||||
 | 
					    """Remove the overridden time."""
 | 
				
			||||||
 | 
					    utcnow.override_time = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def isotime(at=None):
 | 
					def isotime(at=None):
 | 
				
			||||||
 | 
					    """Returns iso formatted utcnow."""
 | 
				
			||||||
    if not at:
 | 
					    if not at:
 | 
				
			||||||
        at = datetime.datetime.utcnow()
 | 
					        at = utcnow()
 | 
				
			||||||
    return at.strftime(TIME_FORMAT)
 | 
					    return at.strftime(TIME_FORMAT)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def parse_isotime(timestr):
 | 
					def parse_isotime(timestr):
 | 
				
			||||||
 | 
					    """Turn an iso formatted time back into a datetime"""
 | 
				
			||||||
    return datetime.datetime.strptime(timestr, TIME_FORMAT)
 | 
					    return datetime.datetime.strptime(timestr, TIME_FORMAT)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -212,7 +290,7 @@ class LazyPluggable(object):
 | 
				
			|||||||
        if not self.__backend:
 | 
					        if not self.__backend:
 | 
				
			||||||
            backend_name = self.__pivot.value
 | 
					            backend_name = self.__pivot.value
 | 
				
			||||||
            if backend_name not in self.__backends:
 | 
					            if backend_name not in self.__backends:
 | 
				
			||||||
                raise exception.Error('Invalid backend: %s' % backend_name)
 | 
					                raise exception.Error(_('Invalid backend: %s') % backend_name)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            backend = self.__backends[backend_name]
 | 
					            backend = self.__backends[backend_name]
 | 
				
			||||||
            if type(backend) == type(tuple()):
 | 
					            if type(backend) == type(tuple()):
 | 
				
			||||||
@@ -231,10 +309,41 @@ class LazyPluggable(object):
 | 
				
			|||||||
        return getattr(backend, key)
 | 
					        return getattr(backend, key)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def deferredToThread(f):
 | 
					class LoopingCall(object):
 | 
				
			||||||
    def g(*args, **kwargs):
 | 
					    def __init__(self, f=None, *args, **kw):
 | 
				
			||||||
        return deferToThread(f, *args, **kwargs)
 | 
					        self.args = args
 | 
				
			||||||
    return g
 | 
					        self.kw = kw
 | 
				
			||||||
 | 
					        self.f = f
 | 
				
			||||||
 | 
					        self._running = False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def start(self, interval, now=True):
 | 
				
			||||||
 | 
					        self._running = True
 | 
				
			||||||
 | 
					        done = event.Event()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        def _inner():
 | 
				
			||||||
 | 
					            if not now:
 | 
				
			||||||
 | 
					                greenthread.sleep(interval)
 | 
				
			||||||
 | 
					            try:
 | 
				
			||||||
 | 
					                while self._running:
 | 
				
			||||||
 | 
					                    self.f(*self.args, **self.kw)
 | 
				
			||||||
 | 
					                    greenthread.sleep(interval)
 | 
				
			||||||
 | 
					            except Exception:
 | 
				
			||||||
 | 
					                logging.exception('in looping call')
 | 
				
			||||||
 | 
					                done.send_exception(*sys.exc_info())
 | 
				
			||||||
 | 
					                return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            done.send(True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.done = done
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        greenthread.spawn(_inner)
 | 
				
			||||||
 | 
					        return self.done
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def stop(self):
 | 
				
			||||||
 | 
					        self._running = False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def wait(self):
 | 
				
			||||||
 | 
					        return self.done.wait()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def xhtml_escape(value):
 | 
					def xhtml_escape(value):
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,94 +0,0 @@
 | 
				
			|||||||
# 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.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
"""Decorators for argument validation, courtesy of
 | 
					 | 
				
			||||||
http://rmi.net/~lutz/rangetest.html"""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def rangetest(**argchecks):
 | 
					 | 
				
			||||||
    """Validate ranges for both + defaults"""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def onDecorator(func):
 | 
					 | 
				
			||||||
        """onCall remembers func and argchecks"""
 | 
					 | 
				
			||||||
        import sys
 | 
					 | 
				
			||||||
        code = func.__code__ if sys.version_info[0] == 3 else func.func_code
 | 
					 | 
				
			||||||
        allargs = code.co_varnames[:code.co_argcount]
 | 
					 | 
				
			||||||
        funcname = func.__name__
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        def onCall(*pargs, **kargs):
 | 
					 | 
				
			||||||
            # all pargs match first N args by position
 | 
					 | 
				
			||||||
            # the rest must be in kargs or omitted defaults
 | 
					 | 
				
			||||||
            positionals = list(allargs)
 | 
					 | 
				
			||||||
            positionals = positionals[:len(pargs)]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            for (argname, (low, high)) in argchecks.items():
 | 
					 | 
				
			||||||
                # for all args to be checked
 | 
					 | 
				
			||||||
                if argname in kargs:
 | 
					 | 
				
			||||||
                    # was passed by name
 | 
					 | 
				
			||||||
                    if float(kargs[argname]) < low or \
 | 
					 | 
				
			||||||
                       float(kargs[argname]) > high:
 | 
					 | 
				
			||||||
                        errmsg = '{0} argument "{1}" not in {2}..{3}'
 | 
					 | 
				
			||||||
                        errmsg = errmsg.format(funcname, argname, low, high)
 | 
					 | 
				
			||||||
                        raise TypeError(errmsg)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                elif argname in positionals:
 | 
					 | 
				
			||||||
                    # was passed by position
 | 
					 | 
				
			||||||
                    position = positionals.index(argname)
 | 
					 | 
				
			||||||
                    if float(pargs[position]) < low or \
 | 
					 | 
				
			||||||
                       float(pargs[position]) > high:
 | 
					 | 
				
			||||||
                        errmsg = '{0} argument "{1}" with value of {4} ' \
 | 
					 | 
				
			||||||
                                 'not in {2}..{3}'
 | 
					 | 
				
			||||||
                        errmsg = errmsg.format(funcname, argname, low, high,
 | 
					 | 
				
			||||||
                                               pargs[position])
 | 
					 | 
				
			||||||
                        raise TypeError(errmsg)
 | 
					 | 
				
			||||||
                else:
 | 
					 | 
				
			||||||
                    pass
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            return func(*pargs, **kargs)    # okay: run original call
 | 
					 | 
				
			||||||
        return onCall
 | 
					 | 
				
			||||||
    return onDecorator
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def typetest(**argchecks):
 | 
					 | 
				
			||||||
    def onDecorator(func):
 | 
					 | 
				
			||||||
        import sys
 | 
					 | 
				
			||||||
        code = func.__code__ if sys.version_info[0] == 3 else func.func_code
 | 
					 | 
				
			||||||
        allargs = code.co_varnames[:code.co_argcount]
 | 
					 | 
				
			||||||
        funcname = func.__name__
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        def onCall(*pargs, **kargs):
 | 
					 | 
				
			||||||
            positionals = list(allargs)[:len(pargs)]
 | 
					 | 
				
			||||||
            for (argname, typeof) in argchecks.items():
 | 
					 | 
				
			||||||
                if argname in kargs:
 | 
					 | 
				
			||||||
                    if not isinstance(kargs[argname], typeof):
 | 
					 | 
				
			||||||
                        errmsg = '{0} argument "{1}" not of type {2}'
 | 
					 | 
				
			||||||
                        errmsg = errmsg.format(funcname, argname, typeof)
 | 
					 | 
				
			||||||
                        raise TypeError(errmsg)
 | 
					 | 
				
			||||||
                elif argname in positionals:
 | 
					 | 
				
			||||||
                    position = positionals.index(argname)
 | 
					 | 
				
			||||||
                    if not isinstance(pargs[position], typeof):
 | 
					 | 
				
			||||||
                        errmsg = '{0} argument "{1}" with value of {2} ' \
 | 
					 | 
				
			||||||
                                 'not of type {3}'
 | 
					 | 
				
			||||||
                        errmsg = errmsg.format(funcname, argname,
 | 
					 | 
				
			||||||
                                               pargs[position], typeof)
 | 
					 | 
				
			||||||
                        raise TypeError(errmsg)
 | 
					 | 
				
			||||||
                else:
 | 
					 | 
				
			||||||
                    pass
 | 
					 | 
				
			||||||
            return func(*pargs, **kargs)
 | 
					 | 
				
			||||||
        return onCall
 | 
					 | 
				
			||||||
    return onDecorator
 | 
					 | 
				
			||||||
							
								
								
									
										122
									
								
								run_tests.py
									
									
									
									
									
								
							
							
						
						
									
										122
									
								
								run_tests.py
									
									
									
									
									
								
							@@ -1,122 +0,0 @@
 | 
				
			|||||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Copyright 2010 United States Government as represented by the
 | 
					 | 
				
			||||||
# Administrator of the National Aeronautics and Space Administration.
 | 
					 | 
				
			||||||
# All Rights Reserved.
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
 | 
					 | 
				
			||||||
#    not use this file except in compliance with the License. You may obtain
 | 
					 | 
				
			||||||
#    a copy of the License at
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
#         http://www.apache.org/licenses/LICENSE-2.0
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
#    Unless required by applicable law or agreed to in writing, software
 | 
					 | 
				
			||||||
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
					 | 
				
			||||||
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
					 | 
				
			||||||
#    License for the specific language governing permissions and limitations
 | 
					 | 
				
			||||||
#    under the License.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
"""
 | 
					 | 
				
			||||||
This is our basic test running framework based on Twisted's Trial.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Usage Examples:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    # to run all the tests
 | 
					 | 
				
			||||||
    python run_tests.py
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    # to run a specific test suite imported here
 | 
					 | 
				
			||||||
    python run_tests.py NodeConnectionTestCase
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    # to run a specific test imported here
 | 
					 | 
				
			||||||
    python run_tests.py NodeConnectionTestCase.test_reboot
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    # to run some test suites elsewhere
 | 
					 | 
				
			||||||
    python run_tests.py nova.tests.node_unittest
 | 
					 | 
				
			||||||
    python run_tests.py nova.tests.node_unittest.NodeConnectionTestCase
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Due to our use of multiprocessing it we frequently get some ignorable
 | 
					 | 
				
			||||||
'Interrupted system call' exceptions after test completion.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
"""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import __main__
 | 
					 | 
				
			||||||
import os
 | 
					 | 
				
			||||||
import sys
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from twisted.scripts import trial as trial_script
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from nova import flags
 | 
					 | 
				
			||||||
from nova import twistd
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from nova.tests.access_unittest import *
 | 
					 | 
				
			||||||
from nova.tests.api_unittest import *
 | 
					 | 
				
			||||||
from nova.tests.auth_unittest import *
 | 
					 | 
				
			||||||
from nova.tests.cloud_unittest import *
 | 
					 | 
				
			||||||
from nova.tests.compute_unittest import *
 | 
					 | 
				
			||||||
from nova.tests.flags_unittest import *
 | 
					 | 
				
			||||||
from nova.tests.misc_unittest import *
 | 
					 | 
				
			||||||
from nova.tests.network_unittest import *
 | 
					 | 
				
			||||||
from nova.tests.objectstore_unittest import *
 | 
					 | 
				
			||||||
from nova.tests.process_unittest import *
 | 
					 | 
				
			||||||
from nova.tests.quota_unittest import *
 | 
					 | 
				
			||||||
from nova.tests.rpc_unittest import *
 | 
					 | 
				
			||||||
from nova.tests.scheduler_unittest import *
 | 
					 | 
				
			||||||
from nova.tests.service_unittest import *
 | 
					 | 
				
			||||||
from nova.tests.twistd_unittest import *
 | 
					 | 
				
			||||||
from nova.tests.validator_unittest import *
 | 
					 | 
				
			||||||
from nova.tests.virt_unittest import *
 | 
					 | 
				
			||||||
from nova.tests.virt_unittest import *
 | 
					 | 
				
			||||||
from nova.tests.volume_unittest import *
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
FLAGS = flags.FLAGS
 | 
					 | 
				
			||||||
flags.DEFINE_bool('flush_db', True,
 | 
					 | 
				
			||||||
                  'Flush the database before running fake tests')
 | 
					 | 
				
			||||||
flags.DEFINE_string('tests_stderr', 'run_tests.err.log',
 | 
					 | 
				
			||||||
                    'Path to where to pipe STDERR during test runs.'
 | 
					 | 
				
			||||||
                    ' Default = "run_tests.err.log"')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if __name__ == '__main__':
 | 
					 | 
				
			||||||
    OptionsClass = twistd.WrapTwistedOptions(trial_script.Options)
 | 
					 | 
				
			||||||
    config = OptionsClass()
 | 
					 | 
				
			||||||
    argv = config.parseOptions()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    FLAGS.verbose = True
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    # TODO(termie): these should make a call instead of doing work on import
 | 
					 | 
				
			||||||
    if FLAGS.fake_tests:
 | 
					 | 
				
			||||||
        from nova.tests.fake_flags import *
 | 
					 | 
				
			||||||
    else:
 | 
					 | 
				
			||||||
        from nova.tests.real_flags import *
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    # Establish redirect for STDERR
 | 
					 | 
				
			||||||
    sys.stderr.flush()
 | 
					 | 
				
			||||||
    err = open(FLAGS.tests_stderr, 'w+', 0)
 | 
					 | 
				
			||||||
    os.dup2(err.fileno(), sys.stderr.fileno())
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if len(argv) == 1 and len(config['tests']) == 0:
 | 
					 | 
				
			||||||
        # If no tests were specified run the ones imported in this file
 | 
					 | 
				
			||||||
        # NOTE(termie): "tests" is not a flag, just some Trial related stuff
 | 
					 | 
				
			||||||
        config['tests'].update(['__main__'])
 | 
					 | 
				
			||||||
    elif len(config['tests']):
 | 
					 | 
				
			||||||
        # If we specified tests check first whether they are in __main__
 | 
					 | 
				
			||||||
        for arg in config['tests']:
 | 
					 | 
				
			||||||
            key = arg.split('.')[0]
 | 
					 | 
				
			||||||
            if hasattr(__main__, key):
 | 
					 | 
				
			||||||
                config['tests'].remove(arg)
 | 
					 | 
				
			||||||
                config['tests'].add('__main__.%s' % arg)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    trial_script._initialDebugSetup(config)
 | 
					 | 
				
			||||||
    trialRunner = trial_script._makeRunner(config)
 | 
					 | 
				
			||||||
    suite = trial_script._getSuite(config)
 | 
					 | 
				
			||||||
    if config['until-failure']:
 | 
					 | 
				
			||||||
        test_result = trialRunner.runUntilFailure(suite)
 | 
					 | 
				
			||||||
    else:
 | 
					 | 
				
			||||||
        test_result = trialRunner.run(suite)
 | 
					 | 
				
			||||||
    if config.tracer:
 | 
					 | 
				
			||||||
        sys.settrace(None)
 | 
					 | 
				
			||||||
        results = config.tracer.results()
 | 
					 | 
				
			||||||
        results.write_results(show_missing=1, summary=False,
 | 
					 | 
				
			||||||
                              coverdir=config.coverdir)
 | 
					 | 
				
			||||||
    sys.exit(not test_result.wasSuccessful())
 | 
					 | 
				
			||||||
							
								
								
									
										12
									
								
								run_tests.sh
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								run_tests.sh
									
									
									
									
									
								
							@@ -36,7 +36,8 @@ done
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
if [ $never_venv -eq 1 ]; then
 | 
					if [ $never_venv -eq 1 ]; then
 | 
				
			||||||
  # Just run the test suites in current environment
 | 
					  # Just run the test suites in current environment
 | 
				
			||||||
  python run_tests.py
 | 
					  rm -f nova.sqlite
 | 
				
			||||||
 | 
					  nosetests -v
 | 
				
			||||||
  exit
 | 
					  exit
 | 
				
			||||||
fi
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -47,7 +48,8 @@ if [ $force -eq 1 ]; then
 | 
				
			|||||||
fi
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if [ -e ${venv} ]; then
 | 
					if [ -e ${venv} ]; then
 | 
				
			||||||
  ${with_venv} python run_tests.py $@
 | 
					  ${with_venv} rm -f nova.sqlite
 | 
				
			||||||
 | 
					  ${with_venv} nosetests -v $@
 | 
				
			||||||
else  
 | 
					else  
 | 
				
			||||||
  if [ $always_venv -eq 1 ]; then
 | 
					  if [ $always_venv -eq 1 ]; then
 | 
				
			||||||
    # Automatically install the virtualenv
 | 
					    # Automatically install the virtualenv
 | 
				
			||||||
@@ -59,9 +61,11 @@ else
 | 
				
			|||||||
      # Install the virtualenv and run the test suite in it
 | 
					      # Install the virtualenv and run the test suite in it
 | 
				
			||||||
      python tools/install_venv.py
 | 
					      python tools/install_venv.py
 | 
				
			||||||
    else
 | 
					    else
 | 
				
			||||||
      python run_tests.py
 | 
					      rm -f nova.sqlite
 | 
				
			||||||
 | 
					      nosetests -v
 | 
				
			||||||
      exit
 | 
					      exit
 | 
				
			||||||
    fi
 | 
					    fi
 | 
				
			||||||
  fi
 | 
					  fi
 | 
				
			||||||
  ${with_venv} python run_tests.py $@
 | 
					  ${with_venv} rm -f nova.sqlite
 | 
				
			||||||
 | 
					  ${with_venv} nosetests -v $@
 | 
				
			||||||
fi
 | 
					fi
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										1
									
								
								setup.py
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								setup.py
									
									
									
									
									
								
							@@ -59,6 +59,7 @@ setup(name='nova',
 | 
				
			|||||||
                 'build_sphinx': local_BuildDoc},
 | 
					                 'build_sphinx': local_BuildDoc},
 | 
				
			||||||
      packages=find_packages(exclude=['bin', 'smoketests']),
 | 
					      packages=find_packages(exclude=['bin', 'smoketests']),
 | 
				
			||||||
      include_package_data=True,
 | 
					      include_package_data=True,
 | 
				
			||||||
 | 
					      test_suite='nose.collector',
 | 
				
			||||||
      scripts=['bin/nova-api',
 | 
					      scripts=['bin/nova-api',
 | 
				
			||||||
               'bin/nova-compute',
 | 
					               'bin/nova-compute',
 | 
				
			||||||
               'bin/nova-dhcpbridge',
 | 
					               'bin/nova-dhcpbridge',
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user