merged trunk

This commit is contained in:
Vishvananda Ishaya 2011-04-07 15:54:14 -07:00
commit be1cc1aee1
51 changed files with 571 additions and 225 deletions

View File

@ -878,7 +878,7 @@ class InstanceTypeCommands(object):
elif name == "--all": elif name == "--all":
inst_types = instance_types.get_all_types(True) inst_types = instance_types.get_all_types(True)
else: else:
inst_types = instance_types.get_instance_type(name) inst_types = instance_types.get_instance_type_by_name(name)
except exception.DBError, e: except exception.DBError, e:
_db_error(e) _db_error(e)
if isinstance(inst_types.values()[0], dict): if isinstance(inst_types.values()[0], dict):

View File

@ -206,10 +206,14 @@ class ServiceWrapper(wsgi.Controller):
# NOTE(vish): make sure we have no unicode keys for py2.6. # NOTE(vish): make sure we have no unicode keys for py2.6.
params = dict([(str(k), v) for (k, v) in params.iteritems()]) params = dict([(str(k), v) for (k, v) in params.iteritems()])
result = method(context, **params) result = method(context, **params)
if result is None or type(result) is str or type(result) is unicode: if result is None or type(result) is str or type(result) is unicode:
return result return result
try: try:
return self._serialize(result, req.best_match_content_type()) content_type = req.best_match_content_type()
default_xmlns = self.get_default_xmlns(req)
return self._serialize(result, content_type, default_xmlns)
except: except:
raise exception.Error("returned non-serializable type: %s" raise exception.Error("returned non-serializable type: %s"
% result) % result)

View File

@ -110,7 +110,8 @@ class CloudController(object):
'genrootca.sh') 'genrootca.sh')
start = os.getcwd() start = os.getcwd()
os.makedirs(FLAGS.ca_path) if not os.path.exists(FLAGS.ca_path):
os.makedirs(FLAGS.ca_path)
os.chdir(FLAGS.ca_path) os.chdir(FLAGS.ca_path)
# TODO(vish): Do this with M2Crypto instead # TODO(vish): Do this with M2Crypto instead
utils.runthis(_("Generating root CA: %s"), "sh", genrootca_sh_path) utils.runthis(_("Generating root CA: %s"), "sh", genrootca_sh_path)
@ -729,7 +730,10 @@ class CloudController(object):
instance['project_id'], instance['project_id'],
instance['host']) instance['host'])
i['productCodesSet'] = self._convert_to_set([], 'product_codes') i['productCodesSet'] = self._convert_to_set([], 'product_codes')
i['instanceType'] = instance['instance_type'] if instance['instance_type']:
i['instanceType'] = instance['instance_type'].get('name')
else:
i['instanceType'] = None
i['launchTime'] = instance['created_at'] i['launchTime'] = instance['created_at']
i['amiLaunchIndex'] = instance['launch_index'] i['amiLaunchIndex'] = instance['launch_index']
i['displayName'] = instance['display_name'] i['displayName'] = instance['display_name']
@ -784,7 +788,7 @@ class CloudController(object):
def allocate_address(self, context, **kwargs): def allocate_address(self, context, **kwargs):
LOG.audit(_("Allocate address"), context=context) LOG.audit(_("Allocate address"), context=context)
public_ip = self.network_api.allocate_floating_ip(context) public_ip = self.network_api.allocate_floating_ip(context)
return {'addressSet': [{'publicIp': public_ip}]} return {'publicIp': public_ip}
def release_address(self, context, public_ip, **kwargs): def release_address(self, context, public_ip, **kwargs):
LOG.audit(_("Release address %s"), public_ip, context=context) LOG.audit(_("Release address %s"), public_ip, context=context)
@ -814,7 +818,7 @@ class CloudController(object):
ramdisk = self._get_image(context, kwargs['ramdisk_id']) ramdisk = self._get_image(context, kwargs['ramdisk_id'])
kwargs['ramdisk_id'] = ramdisk['id'] kwargs['ramdisk_id'] = ramdisk['id']
instances = self.compute_api.create(context, instances = self.compute_api.create(context,
instance_type=instance_types.get_by_type( instance_type=instance_types.get_instance_type_by_name(
kwargs.get('instance_type', None)), kwargs.get('instance_type', None)),
image_id=self._get_image(context, kwargs['image_id'])['id'], image_id=self._get_image(context, kwargs['image_id'])['id'],
min_count=int(kwargs.get('min_count', max_count)), min_count=int(kwargs.get('min_count', max_count)),

View File

@ -13,15 +13,14 @@
# 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 common
import webob.exc import webob.exc
from nova import exception from nova import exception
from nova import flags from nova import flags
from nova import log as logging from nova import log as logging
from nova import wsgi
from nova.auth import manager from nova.auth import manager
from nova.api.openstack import common
from nova.api.openstack import faults from nova.api.openstack import faults
FLAGS = flags.FLAGS FLAGS = flags.FLAGS
@ -35,7 +34,7 @@ def _translate_keys(account):
manager=account.project_manager_id) manager=account.project_manager_id)
class Controller(wsgi.Controller): class Controller(common.OpenstackController):
_serialization_metadata = { _serialization_metadata = {
'application/xml': { 'application/xml': {

View File

@ -19,7 +19,7 @@ import time
from webob import exc from webob import exc
from nova import wsgi from nova.api.openstack import common
from nova.api.openstack import faults from nova.api.openstack import faults
import nova.image.service import nova.image.service
@ -29,7 +29,7 @@ def _translate_keys(inst):
return dict(backupSchedule=inst) return dict(backupSchedule=inst)
class Controller(wsgi.Controller): class Controller(common.OpenstackController):
""" The backup schedule API controller for the Openstack API """ """ The backup schedule API controller for the Openstack API """
_serialization_metadata = { _serialization_metadata = {

View File

@ -22,6 +22,7 @@ import webob
from nova import exception from nova import exception
from nova import flags from nova import flags
from nova import log as logging from nova import log as logging
from nova import wsgi
LOG = logging.getLogger('common') LOG = logging.getLogger('common')
@ -30,6 +31,10 @@ LOG = logging.getLogger('common')
FLAGS = flags.FLAGS FLAGS = flags.FLAGS
XML_NS_V10 = 'http://docs.rackspacecloud.com/servers/api/v1.0'
XML_NS_V11 = 'http://docs.openstack.org/compute/api/v1.1'
def limited(items, request, max_limit=FLAGS.osapi_max_limit): def limited(items, request, max_limit=FLAGS.osapi_max_limit):
""" """
Return a slice of items according to requested offset and limit. Return a slice of items according to requested offset and limit.
@ -128,3 +133,9 @@ def get_id_from_href(href):
except: except:
LOG.debug(_("Error extracting id from href: %s") % href) LOG.debug(_("Error extracting id from href: %s") % href)
raise webob.exc.HTTPBadRequest(_('could not parse id from href')) raise webob.exc.HTTPBadRequest(_('could not parse id from href'))
class OpenstackController(wsgi.Controller):
def get_default_xmlns(self, req):
# Use V10 by default
return XML_NS_V10

View File

@ -19,7 +19,7 @@ from webob import exc
from nova import console from nova import console
from nova import exception from nova import exception
from nova import wsgi from nova.api.openstack import common
from nova.api.openstack import faults from nova.api.openstack import faults
@ -43,7 +43,7 @@ def _translate_detail_keys(cons):
return dict(console=info) return dict(console=info)
class Controller(wsgi.Controller): class Controller(common.OpenstackController):
"""The Consoles Controller for the Openstack API""" """The Consoles Controller for the Openstack API"""
_serialization_metadata = { _serialization_metadata = {

View File

@ -28,6 +28,7 @@ from nova import exception
from nova import flags from nova import flags
from nova import log as logging from nova import log as logging
from nova import wsgi from nova import wsgi
from nova.api.openstack import common
from nova.api.openstack import faults from nova.api.openstack import faults
@ -115,7 +116,7 @@ class ExtensionDescriptor(object):
return response_exts return response_exts
class ActionExtensionController(wsgi.Controller): class ActionExtensionController(common.OpenstackController):
def __init__(self, application): def __init__(self, application):
@ -136,7 +137,7 @@ class ActionExtensionController(wsgi.Controller):
return res return res
class ResponseExtensionController(wsgi.Controller): class ResponseExtensionController(common.OpenstackController):
def __init__(self, application): def __init__(self, application):
self.application = application self.application = application
@ -155,7 +156,8 @@ class ResponseExtensionController(wsgi.Controller):
body = res.body body = res.body
headers = res.headers headers = res.headers
except AttributeError: except AttributeError:
body = self._serialize(res, content_type) default_xmlns = None
body = self._serialize(res, content_type, default_xmlns)
headers = {"Content-Type": content_type} headers = {"Content-Type": content_type}
res = webob.Response() res = webob.Response()
res.body = body res.body = body
@ -163,7 +165,7 @@ class ResponseExtensionController(wsgi.Controller):
return res return res
class ExtensionController(wsgi.Controller): class ExtensionController(common.OpenstackController):
def __init__(self, extension_manager): def __init__(self, extension_manager):
self.extension_manager = extension_manager self.extension_manager = extension_manager

View File

@ -20,10 +20,10 @@ import webob.dec
import webob.exc import webob.exc
from nova import wsgi from nova import wsgi
from nova.api.openstack import common
class Fault(webob.exc.HTTPException): class Fault(webob.exc.HTTPException):
"""An RS API fault response.""" """An RS API fault response."""
_fault_names = { _fault_names = {
@ -47,7 +47,7 @@ class Fault(webob.exc.HTTPException):
"""Generate a WSGI response based on the exception passed to ctor.""" """Generate a WSGI response based on the exception passed to ctor."""
# Replace the body with fault details. # Replace the body with fault details.
code = self.wrapped_exc.status_int code = self.wrapped_exc.status_int
fault_name = self._fault_names.get(code, "computeFault") fault_name = self._fault_names.get(code, "cloudServersFault")
fault_data = { fault_data = {
fault_name: { fault_name: {
'code': code, 'code': code,
@ -57,7 +57,8 @@ class Fault(webob.exc.HTTPException):
fault_data[fault_name]['retryAfter'] = retry fault_data[fault_name]['retryAfter'] = retry
# 'code' is an attribute on the fault tag itself # 'code' is an attribute on the fault tag itself
metadata = {'application/xml': {'attributes': {fault_name: 'code'}}} metadata = {'application/xml': {'attributes': {fault_name: 'code'}}}
serializer = wsgi.Serializer(metadata) default_xmlns = common.XML_NS_V10
serializer = wsgi.Serializer(metadata, default_xmlns)
content_type = req.best_match_content_type() content_type = req.best_match_content_type()
self.wrapped_exc.body = serializer.serialize(fault_data, content_type) self.wrapped_exc.body = serializer.serialize(fault_data, content_type)
self.wrapped_exc.content_type = content_type self.wrapped_exc.content_type = content_type

View File

@ -19,11 +19,11 @@ import webob
from nova import db from nova import db
from nova import exception from nova import exception
from nova import wsgi from nova.api.openstack import common
from nova.api.openstack import views from nova.api.openstack import views
class Controller(wsgi.Controller): class Controller(common.OpenstackController):
"""Flavor controller for the OpenStack API.""" """Flavor controller for the OpenStack API."""
_serialization_metadata = { _serialization_metadata = {
@ -76,3 +76,6 @@ class ControllerV11(Controller):
def _get_view_builder(self, req): def _get_view_builder(self, req):
base_url = req.application_url base_url = req.application_url
return views.flavors.ViewBuilderV11(base_url) return views.flavors.ViewBuilderV11(base_url)
def get_default_xmlns(self, req):
return common.XML_NS_V11

View File

@ -20,13 +20,14 @@ from webob import exc
from nova import flags from nova import flags
from nova import utils from nova import utils
from nova import wsgi from nova import wsgi
from nova.api.openstack import common
from nova.api.openstack import faults from nova.api.openstack import faults
FLAGS = flags.FLAGS FLAGS = flags.FLAGS
class Controller(wsgi.Controller): class Controller(common.OpenstackController):
"""The image metadata API controller for the Openstack API""" """The image metadata API controller for the Openstack API"""
def __init__(self): def __init__(self):

View File

@ -13,8 +13,6 @@
# 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 datetime
import webob.exc import webob.exc
from nova import compute from nova import compute
@ -22,7 +20,6 @@ from nova import exception
from nova import flags from nova import flags
from nova import log from nova import log
from nova import utils from nova import utils
from nova import wsgi
from nova.api.openstack import common from nova.api.openstack import common
from nova.api.openstack import faults from nova.api.openstack import faults
from nova.api.openstack.views import images as images_view from nova.api.openstack.views import images as images_view
@ -32,7 +29,7 @@ LOG = log.getLogger('nova.api.openstack.images')
FLAGS = flags.FLAGS FLAGS = flags.FLAGS
class Controller(wsgi.Controller): class Controller(common.OpenstackController):
"""Base `wsgi.Controller` for retrieving/displaying images.""" """Base `wsgi.Controller` for retrieving/displaying images."""
_serialization_metadata = { _serialization_metadata = {
@ -153,3 +150,6 @@ class ControllerV11(Controller):
"""Property to get the ViewBuilder class we need to use.""" """Property to get the ViewBuilder class we need to use."""
base_url = request.application_url base_url = request.application_url
return images_view.ViewBuilderV11(base_url) return images_view.ViewBuilderV11(base_url)
def get_default_xmlns(self, req):
return common.XML_NS_V11

View File

@ -31,8 +31,8 @@ from collections import defaultdict
from webob.dec import wsgify from webob.dec import wsgify
from nova import wsgi from nova import wsgi
from nova.api.openstack import common
from nova.api.openstack import faults from nova.api.openstack import faults
from nova.wsgi import Controller
from nova.wsgi import Middleware from nova.wsgi import Middleware
@ -43,7 +43,7 @@ PER_HOUR = 60 * 60
PER_DAY = 60 * 60 * 24 PER_DAY = 60 * 60 * 24
class LimitsController(Controller): class LimitsController(common.OpenstackController):
""" """
Controller for accessing limits in the OpenStack API. Controller for accessing limits in the OpenStack API.
""" """

View File

@ -19,10 +19,11 @@ from webob import exc
from nova import compute from nova import compute
from nova import wsgi from nova import wsgi
from nova.api.openstack import common
from nova.api.openstack import faults from nova.api.openstack import faults
class Controller(wsgi.Controller): class Controller(common.OpenstackController):
""" The server metadata API controller for the Openstack API """ """ The server metadata API controller for the Openstack API """
def __init__(self): def __init__(self):

View File

@ -44,7 +44,7 @@ LOG = logging.getLogger('server')
FLAGS = flags.FLAGS FLAGS = flags.FLAGS
class Controller(wsgi.Controller): class Controller(common.OpenstackController):
""" The Server API controller for the OpenStack API """ """ The Server API controller for the OpenStack API """
_serialization_metadata = { _serialization_metadata = {
@ -160,9 +160,11 @@ class Controller(wsgi.Controller):
name = name.strip() name = name.strip()
try: try:
inst_type = \
instance_types.get_instance_type_by_flavor_id(flavor_id)
(inst,) = self.compute_api.create( (inst,) = self.compute_api.create(
context, context,
instance_types.get_by_flavor_id(flavor_id), inst_type,
image_id, image_id,
kernel_id=kernel_id, kernel_id=kernel_id,
ramdisk_id=ramdisk_id, ramdisk_id=ramdisk_id,
@ -175,7 +177,7 @@ class Controller(wsgi.Controller):
except quota.QuotaError as error: except quota.QuotaError as error:
self._handle_quota_error(error) self._handle_quota_error(error)
inst['instance_type'] = flavor_id inst['instance_type'] = inst_type
inst['image_id'] = requested_image_id inst['image_id'] = requested_image_id
builder = self._get_view_builder(req) builder = self._get_view_builder(req)
@ -648,6 +650,9 @@ class ControllerV11(Controller):
def _limit_items(self, items, req): def _limit_items(self, items, req):
return common.limited_by_marker(items, req) return common.limited_by_marker(items, req)
def get_default_xmlns(self, req):
return common.XML_NS_V11
class ServerCreateRequestXMLDeserializer(object): class ServerCreateRequestXMLDeserializer(object):
""" """

View File

@ -17,7 +17,7 @@
from webob import exc from webob import exc
from nova import wsgi from nova.api.openstack import common
from nova.api.openstack import faults from nova.api.openstack import faults
@ -32,7 +32,7 @@ def _translate_detail_keys(inst):
return dict(sharedIpGroups=inst) return dict(sharedIpGroups=inst)
class Controller(wsgi.Controller): class Controller(common.OpenstackController):
""" The Shared IP Groups Controller for the Openstack API """ """ The Shared IP Groups Controller for the Openstack API """
_serialization_metadata = { _serialization_metadata = {

View File

@ -18,7 +18,6 @@ from webob import exc
from nova import exception from nova import exception
from nova import flags from nova import flags
from nova import log as logging from nova import log as logging
from nova import wsgi
from nova.api.openstack import common from nova.api.openstack import common
from nova.api.openstack import faults from nova.api.openstack import faults
from nova.auth import manager from nova.auth import manager
@ -35,7 +34,7 @@ def _translate_keys(user):
admin=user.admin) admin=user.admin)
class Controller(wsgi.Controller): class Controller(common.OpenstackController):
_serialization_metadata = { _serialization_metadata = {
'application/xml': { 'application/xml': {

View File

@ -115,7 +115,7 @@ class ViewBuilderV10(ViewBuilder):
def _build_flavor(self, response, inst): def _build_flavor(self, response, inst):
if 'instance_type' in dict(inst): if 'instance_type' in dict(inst):
response['flavorId'] = inst['instance_type'] response['flavorId'] = inst['instance_type']['flavorid']
class ViewBuilderV11(ViewBuilder): class ViewBuilderV11(ViewBuilder):
@ -134,7 +134,7 @@ class ViewBuilderV11(ViewBuilder):
def _build_flavor(self, response, inst): def _build_flavor(self, response, inst):
if "instance_type" in dict(inst): if "instance_type" in dict(inst):
flavor_id = inst["instance_type"] flavor_id = inst["instance_type"]['flavorid']
flavor_ref = self.flavor_builder.generate_href(flavor_id) flavor_ref = self.flavor_builder.generate_href(flavor_id)
response["flavorRef"] = flavor_ref response["flavorRef"] = flavor_ref

View File

@ -13,12 +13,10 @@
# 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 common
from nova import db from nova import db
from nova import flags from nova import flags
from nova import log as logging from nova import log as logging
from nova import wsgi from nova.api.openstack import common
from nova.scheduler import api from nova.scheduler import api
@ -43,7 +41,7 @@ def _scrub_zone(zone):
'deleted', 'deleted_at', 'updated_at')) 'deleted', 'deleted_at', 'updated_at'))
class Controller(wsgi.Controller): class Controller(common.OpenstackController):
_serialization_metadata = { _serialization_metadata = {
'application/xml': { 'application/xml': {

View File

@ -114,8 +114,11 @@ class API(base.Base):
"""Create the number of instances requested if quota and """Create the number of instances requested if quota and
other arguments check out ok.""" other arguments check out ok."""
type_data = instance_types.get_instance_type(instance_type) if not instance_type:
num_instances = quota.allowed_instances(context, max_count, type_data) instance_type = instance_types.get_default_instance_type()
num_instances = quota.allowed_instances(context, max_count,
instance_type)
if num_instances < min_count: if num_instances < min_count:
pid = context.project_id pid = context.project_id
LOG.warn(_("Quota exceeeded for %(pid)s," LOG.warn(_("Quota exceeeded for %(pid)s,"
@ -201,10 +204,10 @@ class API(base.Base):
'user_id': context.user_id, 'user_id': context.user_id,
'project_id': context.project_id, 'project_id': context.project_id,
'launch_time': time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime()), 'launch_time': time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime()),
'instance_type': instance_type, 'instance_type_id': instance_type['id'],
'memory_mb': type_data['memory_mb'], 'memory_mb': instance_type['memory_mb'],
'vcpus': type_data['vcpus'], 'vcpus': instance_type['vcpus'],
'local_gb': type_data['local_gb'], 'local_gb': instance_type['local_gb'],
'display_name': display_name, 'display_name': display_name,
'display_description': display_description, 'display_description': display_description,
'user_data': user_data or '', 'user_data': user_data or '',
@ -521,8 +524,7 @@ class API(base.Base):
def resize(self, context, instance_id, flavor_id): def resize(self, context, instance_id, flavor_id):
"""Resize a running instance.""" """Resize a running instance."""
instance = self.db.instance_get(context, instance_id) instance = self.db.instance_get(context, instance_id)
current_instance_type = self.db.instance_type_get_by_name( current_instance_type = instance['instance_type']
context, instance['instance_type'])
new_instance_type = self.db.instance_type_get_by_flavor_id( new_instance_type = self.db.instance_type_get_by_flavor_id(
context, flavor_id) context, flavor_id)

View File

@ -59,8 +59,8 @@ def create(name, memory, vcpus, local_gb, flavorid, swap=0,
rxtx_quota=rxtx_quota, rxtx_quota=rxtx_quota,
rxtx_cap=rxtx_cap)) rxtx_cap=rxtx_cap))
except exception.DBError, e: except exception.DBError, e:
LOG.exception(_('DB error: %s' % e)) LOG.exception(_('DB error: %s') % e)
raise exception.ApiError(_("Cannot create instance type: %s" % name)) raise exception.ApiError(_("Cannot create instance type: %s") % name)
def destroy(name): def destroy(name):
@ -72,8 +72,8 @@ def destroy(name):
try: try:
db.instance_type_destroy(context.get_admin_context(), name) db.instance_type_destroy(context.get_admin_context(), name)
except exception.NotFound: except exception.NotFound:
LOG.exception(_('Instance type %s not found for deletion' % name)) LOG.exception(_('Instance type %s not found for deletion') % name)
raise exception.ApiError(_("Unknown instance type: %s" % name)) raise exception.ApiError(_("Unknown instance type: %s") % name)
def purge(name): def purge(name):
@ -85,8 +85,8 @@ def purge(name):
try: try:
db.instance_type_purge(context.get_admin_context(), name) db.instance_type_purge(context.get_admin_context(), name)
except exception.NotFound: except exception.NotFound:
LOG.exception(_('Instance type %s not found for purge' % name)) LOG.exception(_('Instance type %s not found for purge') % name)
raise exception.ApiError(_("Unknown instance type: %s" % name)) raise exception.ApiError(_("Unknown instance type: %s") % name)
def get_all_types(inactive=0): def get_all_types(inactive=0):
@ -101,41 +101,43 @@ def get_all_flavors():
return get_all_types(context.get_admin_context()) return get_all_types(context.get_admin_context())
def get_instance_type(name): def get_default_instance_type():
name = FLAGS.default_instance_type
try:
return get_instance_type_by_name(name)
except exception.DBError:
raise exception.ApiError(_("Unknown instance type: %s") % name)
def get_instance_type(id):
"""Retrieves single instance type by id"""
if id is None:
return get_default_instance_type()
try:
ctxt = context.get_admin_context()
return db.instance_type_get_by_id(ctxt, id)
except exception.DBError:
raise exception.ApiError(_("Unknown instance type: %s") % name)
def get_instance_type_by_name(name):
"""Retrieves single instance type by name""" """Retrieves single instance type by name"""
if name is None: if name is None:
return FLAGS.default_instance_type return get_default_instance_type()
try: try:
ctxt = context.get_admin_context() ctxt = context.get_admin_context()
inst_type = db.instance_type_get_by_name(ctxt, name) return db.instance_type_get_by_name(ctxt, name)
return inst_type
except exception.DBError: except exception.DBError:
raise exception.ApiError(_("Unknown instance type: %s" % name)) raise exception.ApiError(_("Unknown instance type: %s") % name)
def get_by_type(instance_type): def get_instance_type_by_flavor_id(flavor_id):
"""retrieve instance type name""" """retrieve instance type by flavor_id"""
if instance_type is None:
return FLAGS.default_instance_type
try:
ctxt = context.get_admin_context()
inst_type = db.instance_type_get_by_name(ctxt, instance_type)
return inst_type['name']
except exception.DBError, e:
LOG.exception(_('DB error: %s' % e))
raise exception.ApiError(_("Unknown instance type: %s" %\
instance_type))
def get_by_flavor_id(flavor_id):
"""retrieve instance type's name by flavor_id"""
if flavor_id is None: if flavor_id is None:
return FLAGS.default_instance_type return get_default_instance_type()
try: try:
ctxt = context.get_admin_context() ctxt = context.get_admin_context()
flavor = db.instance_type_get_by_flavor_id(ctxt, flavor_id) return db.instance_type_get_by_flavor_id(ctxt, flavor_id)
return flavor['name']
except exception.DBError, e: except exception.DBError, e:
LOG.exception(_('DB error: %s' % e)) LOG.exception(_('DB error: %s') % e)
raise exception.ApiError(_("Unknown flavor: %s" % flavor_id)) raise exception.ApiError(_("Unknown flavor: %s") % flavor_id)

View File

@ -269,6 +269,8 @@ def _sign_csr(csr_text, ca_folder):
LOG.debug(_("Flags path: %s"), ca_folder) LOG.debug(_("Flags path: %s"), ca_folder)
start = os.getcwd() start = os.getcwd()
# Change working dir to CA # Change working dir to CA
if not os.path.exists(ca_folder):
os.makedirs(ca_folder)
os.chdir(ca_folder) os.chdir(ca_folder)
utils.execute('openssl', 'ca', '-batch', '-out', outbound, '-config', utils.execute('openssl', 'ca', '-batch', '-out', outbound, '-config',
'./openssl.cnf', '-infiles', inbound) './openssl.cnf', '-infiles', inbound)

View File

@ -1124,6 +1124,11 @@ def instance_type_get_all(context, inactive=False):
return IMPL.instance_type_get_all(context, inactive) return IMPL.instance_type_get_all(context, inactive)
def instance_type_get_by_id(context, id):
"""Get instance type by id"""
return IMPL.instance_type_get_by_id(context, id)
def instance_type_get_by_name(context, name): def instance_type_get_by_name(context, name):
"""Get instance type by name""" """Get instance type by name"""
return IMPL.instance_type_get_by_name(context, name) return IMPL.instance_type_get_by_name(context, name)

View File

@ -831,6 +831,7 @@ def instance_get(context, instance_id, session=None):
options(joinedload('volumes')).\ options(joinedload('volumes')).\
options(joinedload_all('fixed_ip.network')).\ options(joinedload_all('fixed_ip.network')).\
options(joinedload('metadata')).\ options(joinedload('metadata')).\
options(joinedload('instance_type')).\
filter_by(id=instance_id).\ filter_by(id=instance_id).\
filter_by(deleted=can_read_deleted(context)).\ filter_by(deleted=can_read_deleted(context)).\
first() first()
@ -840,6 +841,7 @@ def instance_get(context, instance_id, session=None):
options(joinedload_all('security_groups.rules')).\ options(joinedload_all('security_groups.rules')).\
options(joinedload('volumes')).\ options(joinedload('volumes')).\
options(joinedload('metadata')).\ options(joinedload('metadata')).\
options(joinedload('instance_type')).\
filter_by(project_id=context.project_id).\ filter_by(project_id=context.project_id).\
filter_by(id=instance_id).\ filter_by(id=instance_id).\
filter_by(deleted=False).\ filter_by(deleted=False).\
@ -859,6 +861,7 @@ def instance_get_all(context):
options(joinedload_all('fixed_ip.floating_ips')).\ options(joinedload_all('fixed_ip.floating_ips')).\
options(joinedload('security_groups')).\ options(joinedload('security_groups')).\
options(joinedload_all('fixed_ip.network')).\ options(joinedload_all('fixed_ip.network')).\
options(joinedload('instance_type')).\
filter_by(deleted=can_read_deleted(context)).\ filter_by(deleted=can_read_deleted(context)).\
all() all()
@ -870,6 +873,7 @@ def instance_get_all_by_user(context, user_id):
options(joinedload_all('fixed_ip.floating_ips')).\ options(joinedload_all('fixed_ip.floating_ips')).\
options(joinedload('security_groups')).\ options(joinedload('security_groups')).\
options(joinedload_all('fixed_ip.network')).\ options(joinedload_all('fixed_ip.network')).\
options(joinedload('instance_type')).\
filter_by(deleted=can_read_deleted(context)).\ filter_by(deleted=can_read_deleted(context)).\
filter_by(user_id=user_id).\ filter_by(user_id=user_id).\
all() all()
@ -882,6 +886,7 @@ def instance_get_all_by_host(context, host):
options(joinedload_all('fixed_ip.floating_ips')).\ options(joinedload_all('fixed_ip.floating_ips')).\
options(joinedload('security_groups')).\ options(joinedload('security_groups')).\
options(joinedload_all('fixed_ip.network')).\ options(joinedload_all('fixed_ip.network')).\
options(joinedload('instance_type')).\
filter_by(host=host).\ filter_by(host=host).\
filter_by(deleted=can_read_deleted(context)).\ filter_by(deleted=can_read_deleted(context)).\
all() all()
@ -896,6 +901,7 @@ def instance_get_all_by_project(context, project_id):
options(joinedload_all('fixed_ip.floating_ips')).\ options(joinedload_all('fixed_ip.floating_ips')).\
options(joinedload('security_groups')).\ options(joinedload('security_groups')).\
options(joinedload_all('fixed_ip.network')).\ options(joinedload_all('fixed_ip.network')).\
options(joinedload('instance_type')).\
filter_by(project_id=project_id).\ filter_by(project_id=project_id).\
filter_by(deleted=can_read_deleted(context)).\ filter_by(deleted=can_read_deleted(context)).\
all() all()
@ -910,6 +916,7 @@ def instance_get_all_by_reservation(context, reservation_id):
options(joinedload_all('fixed_ip.floating_ips')).\ options(joinedload_all('fixed_ip.floating_ips')).\
options(joinedload('security_groups')).\ options(joinedload('security_groups')).\
options(joinedload_all('fixed_ip.network')).\ options(joinedload_all('fixed_ip.network')).\
options(joinedload('instance_type')).\
filter_by(reservation_id=reservation_id).\ filter_by(reservation_id=reservation_id).\
filter_by(deleted=can_read_deleted(context)).\ filter_by(deleted=can_read_deleted(context)).\
all() all()
@ -918,6 +925,7 @@ def instance_get_all_by_reservation(context, reservation_id):
options(joinedload_all('fixed_ip.floating_ips')).\ options(joinedload_all('fixed_ip.floating_ips')).\
options(joinedload('security_groups')).\ options(joinedload('security_groups')).\
options(joinedload_all('fixed_ip.network')).\ options(joinedload_all('fixed_ip.network')).\
options(joinedload('instance_type')).\
filter_by(project_id=context.project_id).\ filter_by(project_id=context.project_id).\
filter_by(reservation_id=reservation_id).\ filter_by(reservation_id=reservation_id).\
filter_by(deleted=False).\ filter_by(deleted=False).\
@ -930,6 +938,7 @@ def instance_get_project_vpn(context, project_id):
return session.query(models.Instance).\ return session.query(models.Instance).\
options(joinedload_all('fixed_ip.floating_ips')).\ options(joinedload_all('fixed_ip.floating_ips')).\
options(joinedload('security_groups')).\ options(joinedload('security_groups')).\
options(joinedload('instance_type')).\
filter_by(project_id=project_id).\ filter_by(project_id=project_id).\
filter_by(image_id=FLAGS.vpn_image_id).\ filter_by(image_id=FLAGS.vpn_image_id).\
filter_by(deleted=can_read_deleted(context)).\ filter_by(deleted=can_read_deleted(context)).\
@ -2370,6 +2379,19 @@ def instance_type_get_all(context, inactive=False):
raise exception.NotFound raise exception.NotFound
@require_context
def instance_type_get_by_id(context, id):
"""Returns a dict describing specific instance_type"""
session = get_session()
inst_type = session.query(models.InstanceTypes).\
filter_by(id=id).\
first()
if not inst_type:
raise exception.NotFound(_("No instance type with id %s") % id)
else:
return dict(inst_type)
@require_context @require_context
def instance_type_get_by_name(context, name): def instance_type_get_by_name(context, name):
"""Returns a dict describing specific instance_type""" """Returns a dict describing specific instance_type"""

View File

@ -0,0 +1,84 @@
# 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.
from sqlalchemy import *
from sqlalchemy.sql import text
from migrate import *
#from nova import log as logging
meta = MetaData()
c_instance_type = Column('instance_type',
String(length=255, convert_unicode=False,
assert_unicode=None, unicode_error=None,
_warn_on_bytestring=False),
nullable=True)
c_instance_type_id = Column('instance_type_id',
String(length=255, convert_unicode=False,
assert_unicode=None, unicode_error=None,
_warn_on_bytestring=False),
nullable=True)
instance_types = Table('instance_types', meta,
Column('id', Integer(), primary_key=True, nullable=False),
Column('name',
String(length=255, convert_unicode=False, assert_unicode=None,
unicode_error=None, _warn_on_bytestring=False),
unique=True))
def upgrade(migrate_engine):
# Upgrade operations go here. Don't create your own engine;
# bind migrate_engine to your metadata
meta.bind = migrate_engine
instances = Table('instances', meta, autoload=True,
autoload_with=migrate_engine)
instances.create_column(c_instance_type_id)
recs = migrate_engine.execute(instance_types.select())
for row in recs:
type_id = row[0]
type_name = row[1]
migrate_engine.execute(instances.update()\
.where(instances.c.instance_type == type_name)\
.values(instance_type_id=type_id))
instances.c.instance_type.drop()
def downgrade(migrate_engine):
meta.bind = migrate_engine
instances = Table('instances', meta, autoload=True,
autoload_with=migrate_engine)
instances.create_column(c_instance_type)
recs = migrate_engine.execute(instance_types.select())
for row in recs:
type_id = row[0]
type_name = row[1]
migrate_engine.execute(instances.update()\
.where(instances.c.instance_type_id == type_id)\
.values(instance_type=type_name))
instances.c.instance_type_id.drop()

View File

@ -209,7 +209,7 @@ class Instance(BASE, NovaBase):
hostname = Column(String(255)) hostname = Column(String(255))
host = Column(String(255)) # , ForeignKey('hosts.id')) host = Column(String(255)) # , ForeignKey('hosts.id'))
instance_type = Column(String(255)) instance_type_id = Column(String(255))
user_data = Column(Text) user_data = Column(Text)
@ -268,6 +268,12 @@ class InstanceTypes(BASE, NovaBase):
rxtx_quota = Column(Integer, nullable=False, default=0) rxtx_quota = Column(Integer, nullable=False, default=0)
rxtx_cap = Column(Integer, nullable=False, default=0) rxtx_cap = Column(Integer, nullable=False, default=0)
instances = relationship(Instance,
backref=backref('instance_type', uselist=False),
foreign_keys=id,
primaryjoin='and_(Instance.instance_type_id == '
'InstanceTypes.id)')
class Volume(BASE, NovaBase): class Volume(BASE, NovaBase):
"""Represents a block storage device that can be attached to a vm.""" """Represents a block storage device that can be attached to a vm."""

View File

@ -391,6 +391,12 @@ def unbind_floating_ip(floating_ip):
'dev', FLAGS.public_interface) 'dev', FLAGS.public_interface)
def ensure_metadata_ip():
"""Sets up local metadata ip"""
_execute('sudo', 'ip', 'addr', 'add', '169.254.169.254/32',
'scope', 'link', 'dev', 'lo', check_exit_code=False)
def ensure_vlan_forward(public_ip, port, private_ip): def ensure_vlan_forward(public_ip, port, private_ip):
"""Sets up forwarding rules for vlan""" """Sets up forwarding rules for vlan"""
iptables_manager.ipv4['filter'].add_rule("FORWARD", iptables_manager.ipv4['filter'].add_rule("FORWARD",
@ -442,6 +448,7 @@ def ensure_vlan(vlan_num):
return interface return interface
@utils.synchronized('ensure_bridge', external=True)
def ensure_bridge(bridge, interface, net_attrs=None): def ensure_bridge(bridge, interface, net_attrs=None):
"""Create a bridge unless it already exists. """Create a bridge unless it already exists.
@ -495,6 +502,8 @@ def ensure_bridge(bridge, interface, net_attrs=None):
fields = line.split() fields = line.split()
if fields and fields[0] == "0.0.0.0" and fields[-1] == interface: if fields and fields[0] == "0.0.0.0" and fields[-1] == interface:
gateway = fields[1] gateway = fields[1]
_execute('sudo', 'route', 'del', 'default', 'gw', gateway,
'dev', interface)
out, err = _execute('sudo', 'ip', 'addr', 'show', 'dev', interface, out, err = _execute('sudo', 'ip', 'addr', 'show', 'dev', interface,
'scope', 'global') 'scope', 'global')
for line in out.split("\n"): for line in out.split("\n"):
@ -504,7 +513,7 @@ def ensure_bridge(bridge, interface, net_attrs=None):
_execute(*_ip_bridge_cmd('del', params, fields[-1])) _execute(*_ip_bridge_cmd('del', params, fields[-1]))
_execute(*_ip_bridge_cmd('add', params, bridge)) _execute(*_ip_bridge_cmd('add', params, bridge))
if gateway: if gateway:
_execute('sudo', 'route', 'add', '0.0.0.0', 'gw', gateway) _execute('sudo', 'route', 'add', 'default', 'gw', gateway)
out, err = _execute('sudo', 'brctl', 'addif', bridge, interface, out, err = _execute('sudo', 'brctl', 'addif', bridge, interface,
check_exit_code=False) check_exit_code=False)

View File

@ -126,6 +126,7 @@ class NetworkManager(manager.SchedulerDependentManager):
standalone service. standalone service.
""" """
self.driver.init_host() self.driver.init_host()
self.driver.ensure_metadata_ip()
# Set up networking for the projects for which we're already # Set up networking for the projects for which we're already
# the designated network host. # the designated network host.
ctxt = context.get_admin_context() ctxt = context.get_admin_context()

View File

@ -53,13 +53,13 @@ class APITest(test.TestCase):
#api.application = succeed #api.application = succeed
api = self._wsgi_app(succeed) api = self._wsgi_app(succeed)
resp = Request.blank('/').get_response(api) resp = Request.blank('/').get_response(api)
self.assertFalse('computeFault' in resp.body, resp.body) self.assertFalse('cloudServersFault' in resp.body, resp.body)
self.assertEqual(resp.status_int, 200, resp.body) self.assertEqual(resp.status_int, 200, resp.body)
#api.application = raise_webob_exc #api.application = raise_webob_exc
api = self._wsgi_app(raise_webob_exc) api = self._wsgi_app(raise_webob_exc)
resp = Request.blank('/').get_response(api) resp = Request.blank('/').get_response(api)
self.assertFalse('computeFault' in resp.body, resp.body) self.assertFalse('cloudServersFault' in resp.body, resp.body)
self.assertEqual(resp.status_int, 404, resp.body) self.assertEqual(resp.status_int, 404, resp.body)
#api.application = raise_api_fault #api.application = raise_api_fault
@ -71,11 +71,11 @@ class APITest(test.TestCase):
#api.application = fail #api.application = fail
api = self._wsgi_app(fail) api = self._wsgi_app(fail)
resp = Request.blank('/').get_response(api) resp = Request.blank('/').get_response(api)
self.assertTrue('{"computeFault' in resp.body, resp.body) self.assertTrue('{"cloudServersFault' in resp.body, resp.body)
self.assertEqual(resp.status_int, 500, resp.body) self.assertEqual(resp.status_int, 500, resp.body)
#api.application = fail #api.application = fail
api = self._wsgi_app(fail) api = self._wsgi_app(fail)
resp = Request.blank('/.xml').get_response(api) resp = Request.blank('/.xml').get_response(api)
self.assertTrue('<computeFault' in resp.body, resp.body) self.assertTrue('<cloudServersFault' in resp.body, resp.body)
self.assertEqual(resp.status_int, 500, resp.body) self.assertEqual(resp.status_int, 500, resp.body)

View File

@ -22,6 +22,7 @@ import webob.dec
import webob.exc import webob.exc
from nova import test from nova import test
from nova.api.openstack import common
from nova.api.openstack import faults from nova.api.openstack import faults
@ -47,10 +48,10 @@ class TestFaults(test.TestCase):
response = request.get_response(fault) response = request.get_response(fault)
expected = self._prepare_xml(""" expected = self._prepare_xml("""
<badRequest code="400"> <badRequest code="400" xmlns="%s">
<message>scram</message> <message>scram</message>
</badRequest> </badRequest>
""") """ % common.XML_NS_V10)
actual = self._prepare_xml(response.body) actual = self._prepare_xml(response.body)
self.assertEqual(response.content_type, "application/xml") self.assertEqual(response.content_type, "application/xml")
@ -91,11 +92,11 @@ class TestFaults(test.TestCase):
response = request.get_response(fault) response = request.get_response(fault)
expected = self._prepare_xml(""" expected = self._prepare_xml("""
<overLimit code="413"> <overLimit code="413" xmlns="%s">
<message>sorry</message> <message>sorry</message>
<retryAfter>4</retryAfter> <retryAfter>4</retryAfter>
</overLimit> </overLimit>
""") """ % common.XML_NS_V10)
actual = self._prepare_xml(response.body) actual = self._prepare_xml(response.body)
self.assertEqual(expected, actual) self.assertEqual(expected, actual)

View File

@ -146,7 +146,7 @@ class LocalImageServiceTest(_BaseImageServiceTests):
for x in [1, 2, 3]: for x in [1, 2, 3]:
tempfile.mkstemp(prefix='ami-', dir=self.tempdir) tempfile.mkstemp(prefix='ami-', dir=self.tempdir)
# create some valid image directories names # create some valid image directories names
for x in ["1485baed", "1a60f0ee", "3123a73d"]: for x in ["1485baed", "1a60f0ee", "3123a73d"]:
os.makedirs(os.path.join(self.tempdir, x)) os.makedirs(os.path.join(self.tempdir, x))
found_image_ids = self.service._ids() found_image_ids = self.service._ids()
self.assertEqual(True, isinstance(found_image_ids, list)) self.assertEqual(True, isinstance(found_image_ids, list))
@ -335,7 +335,8 @@ class ImageControllerWithGlanceServiceTest(test.TestCase):
name="public image" name="public image"
updated="%(expected_now)s" updated="%(expected_now)s"
created="%(expected_now)s" created="%(expected_now)s"
status="ACTIVE" /> status="ACTIVE"
xmlns="http://docs.rackspacecloud.com/servers/api/v1.0" />
""" % (locals())) """ % (locals()))
self.assertEqual(expected_image.toxml(), actual_image.toxml()) self.assertEqual(expected_image.toxml(), actual_image.toxml())
@ -353,7 +354,8 @@ class ImageControllerWithGlanceServiceTest(test.TestCase):
name="None" name="None"
updated="%(expected_now)s" updated="%(expected_now)s"
created="%(expected_now)s" created="%(expected_now)s"
status="ACTIVE" /> status="ACTIVE"
xmlns="http://docs.rackspacecloud.com/servers/api/v1.0" />
""" % (locals())) """ % (locals()))
self.assertEqual(expected_image.toxml(), actual_image.toxml()) self.assertEqual(expected_image.toxml(), actual_image.toxml())
@ -372,7 +374,8 @@ class ImageControllerWithGlanceServiceTest(test.TestCase):
name="public image" name="public image"
updated="%(expected_now)s" updated="%(expected_now)s"
created="%(expected_now)s" created="%(expected_now)s"
status="ACTIVE"> status="ACTIVE"
xmlns="http://docs.openstack.org/compute/api/v1.1">
<links> <links>
<link href="%(expected_href)s" rel="self"/> <link href="%(expected_href)s" rel="self"/>
<link href="%(expected_href)s" rel="bookmark" <link href="%(expected_href)s" rel="bookmark"
@ -408,7 +411,8 @@ class ImageControllerWithGlanceServiceTest(test.TestCase):
self.assertEqual(404, response.status_int) self.assertEqual(404, response.status_int)
expected = minidom.parseString(""" expected = minidom.parseString("""
<itemNotFound code="404"> <itemNotFound code="404"
xmlns="http://docs.rackspacecloud.com/servers/api/v1.0">
<message> <message>
Image not found. Image not found.
</message> </message>
@ -441,8 +445,11 @@ class ImageControllerWithGlanceServiceTest(test.TestCase):
response = request.get_response(fakes.wsgi_app()) response = request.get_response(fakes.wsgi_app())
self.assertEqual(404, response.status_int) self.assertEqual(404, response.status_int)
# NOTE(justinsb): I believe this should still use the v1.0 XSD,
# because the element hasn't changed definition
expected = minidom.parseString(""" expected = minidom.parseString("""
<itemNotFound code="404"> <itemNotFound code="404"
xmlns="http://docs.rackspacecloud.com/servers/api/v1.0">
<message> <message>
Image not found. Image not found.
</message> </message>

View File

@ -136,10 +136,17 @@ class LimitsControllerTest(BaseLimitTestSuite):
request = self._get_index_request("application/xml") request = self._get_index_request("application/xml")
response = request.get_response(self.controller) response = request.get_response(self.controller)
expected = "<limits><rate/><absolute/></limits>" expected = parseString("""
body = response.body.replace("\n", "").replace(" ", "") <limits
xmlns="http://docs.rackspacecloud.com/servers/api/v1.0">
<rate/>
<absolute/>
</limits>
""".replace(" ", ""))
self.assertEqual(expected, body) body = parseString(response.body.replace(" ", ""))
self.assertEqual(expected.toxml(), body.toxml())
def test_index_xml(self): def test_index_xml(self):
"""Test getting limit details in XML.""" """Test getting limit details in XML."""
@ -148,7 +155,8 @@ class LimitsControllerTest(BaseLimitTestSuite):
response = request.get_response(self.controller) response = request.get_response(self.controller)
expected = parseString(""" expected = parseString("""
<limits> <limits
xmlns="http://docs.rackspacecloud.com/servers/api/v1.0">
<rate> <rate>
<limit URI="*" regex=".*" remaining="10" resetTime="0" <limit URI="*" regex=".*" remaining="10" resetTime="0"
unit="MINUTE" value="10" verb="GET"/> unit="MINUTE" value="10" verb="GET"/>

View File

@ -32,6 +32,7 @@ from nova import test
import nova.api.openstack import nova.api.openstack
from nova.api.openstack import servers from nova.api.openstack import servers
import nova.compute.api import nova.compute.api
from nova.compute import instance_types
import nova.db.api import nova.db.api
from nova.db.sqlalchemy.models import Instance from nova.db.sqlalchemy.models import Instance
from nova.db.sqlalchemy.models import InstanceMetadata from nova.db.sqlalchemy.models import InstanceMetadata
@ -71,13 +72,19 @@ def instance_address(context, instance_id):
return None return None
def stub_instance(id, user_id=1, private_address=None, public_addresses=None): def stub_instance(id, user_id=1, private_address=None, public_addresses=None,
host=None):
metadata = [] metadata = []
metadata.append(InstanceMetadata(key='seq', value=id)) metadata.append(InstanceMetadata(key='seq', value=id))
inst_type = instance_types.get_instance_type_by_flavor_id(1)
if public_addresses == None: if public_addresses == None:
public_addresses = list() public_addresses = list()
if host != None:
host = str(host)
instance = { instance = {
"id": id, "id": id,
"admin_pass": "", "admin_pass": "",
@ -95,8 +102,8 @@ def stub_instance(id, user_id=1, private_address=None, public_addresses=None):
"vcpus": 0, "vcpus": 0,
"local_gb": 0, "local_gb": 0,
"hostname": "", "hostname": "",
"host": None, "host": host,
"instance_type": "1", "instance_type": dict(inst_type),
"user_data": "", "user_data": "",
"reservation_id": "", "reservation_id": "",
"mac_address": "", "mac_address": "",
@ -628,7 +635,7 @@ class ServersTest(test.TestCase):
self.assertEqual(s['hostId'], '') self.assertEqual(s['hostId'], '')
self.assertEqual(s['name'], 'server%d' % i) self.assertEqual(s['name'], 'server%d' % i)
self.assertEqual(s['imageId'], '10') self.assertEqual(s['imageId'], '10')
self.assertEqual(s['flavorId'], '1') self.assertEqual(s['flavorId'], 1)
self.assertEqual(s['status'], 'BUILD') self.assertEqual(s['status'], 'BUILD')
self.assertEqual(s['metadata']['seq'], i) self.assertEqual(s['metadata']['seq'], i)
@ -654,12 +661,8 @@ class ServersTest(test.TestCase):
instances - 2 on one host and 3 on another. instances - 2 on one host and 3 on another.
''' '''
def stub_instance(id, user_id=1):
return Instance(id=id, state=0, image_id=10, user_id=user_id,
display_name='server%s' % id, host='host%s' % (id % 2))
def return_servers_with_host(context, user_id=1): def return_servers_with_host(context, user_id=1):
return [stub_instance(i) for i in xrange(5)] return [stub_instance(i, 1, None, None, i % 2) for i in xrange(5)]
self.stubs.Set(nova.db.api, 'instance_get_all_by_user', self.stubs.Set(nova.db.api, 'instance_get_all_by_user',
return_servers_with_host) return_servers_with_host)
@ -677,7 +680,8 @@ class ServersTest(test.TestCase):
self.assertEqual(s['id'], i) self.assertEqual(s['id'], i)
self.assertEqual(s['hostId'], host_ids[i % 2]) self.assertEqual(s['hostId'], host_ids[i % 2])
self.assertEqual(s['name'], 'server%d' % i) self.assertEqual(s['name'], 'server%d' % i)
self.assertEqual(s['imageId'], 10) self.assertEqual(s['imageId'], '10')
self.assertEqual(s['flavorId'], 1)
def test_server_pause(self): def test_server_pause(self):
FLAGS.allow_admin_api = True FLAGS.allow_admin_api = True

View File

@ -28,29 +28,34 @@ def stub_out_db_instance_api(stubs, injected=True):
"""Stubs out the db API for creating Instances.""" """Stubs out the db API for creating Instances."""
INSTANCE_TYPES = { INSTANCE_TYPES = {
'm1.tiny': dict(memory_mb=512, 'm1.tiny': dict(id=2,
memory_mb=512,
vcpus=1, vcpus=1,
local_gb=0, local_gb=0,
flavorid=1, flavorid=1,
rxtx_cap=1), rxtx_cap=1),
'm1.small': dict(memory_mb=2048, 'm1.small': dict(id=5,
memory_mb=2048,
vcpus=1, vcpus=1,
local_gb=20, local_gb=20,
flavorid=2, flavorid=2,
rxtx_cap=2), rxtx_cap=2),
'm1.medium': 'm1.medium':
dict(memory_mb=4096, dict(id=1,
memory_mb=4096,
vcpus=2, vcpus=2,
local_gb=40, local_gb=40,
flavorid=3, flavorid=3,
rxtx_cap=3), rxtx_cap=3),
'm1.large': dict(memory_mb=8192, 'm1.large': dict(id=3,
memory_mb=8192,
vcpus=4, vcpus=4,
local_gb=80, local_gb=80,
flavorid=4, flavorid=4,
rxtx_cap=4), rxtx_cap=4),
'm1.xlarge': 'm1.xlarge':
dict(memory_mb=16384, dict(id=4,
memory_mb=16384,
vcpus=8, vcpus=8,
local_gb=160, local_gb=160,
flavorid=5, flavorid=5,
@ -107,6 +112,12 @@ def stub_out_db_instance_api(stubs, injected=True):
def fake_instance_type_get_by_name(context, name): def fake_instance_type_get_by_name(context, name):
return INSTANCE_TYPES[name] return INSTANCE_TYPES[name]
def fake_instance_type_get_by_id(context, id):
for name, inst_type in INSTANCE_TYPES.iteritems():
if str(inst_type['id']) == str(id):
return inst_type
return None
def fake_network_get_by_instance(context, instance_id): def fake_network_get_by_instance(context, instance_id):
# Even instance numbers are on vlan networks # Even instance numbers are on vlan networks
if instance_id % 2 == 0: if instance_id % 2 == 0:
@ -136,6 +147,7 @@ def stub_out_db_instance_api(stubs, injected=True):
fake_network_get_all_by_instance) fake_network_get_all_by_instance)
stubs.Set(db, 'instance_type_get_all', fake_instance_type_get_all) stubs.Set(db, 'instance_type_get_all', fake_instance_type_get_all)
stubs.Set(db, 'instance_type_get_by_name', fake_instance_type_get_by_name) stubs.Set(db, 'instance_type_get_by_name', fake_instance_type_get_by_name)
stubs.Set(db, 'instance_type_get_by_id', fake_instance_type_get_by_id)
stubs.Set(db, 'instance_get_fixed_address', stubs.Set(db, 'instance_get_fixed_address',
fake_instance_get_fixed_address) fake_instance_get_fixed_address)
stubs.Set(db, 'instance_get_fixed_address_v6', stubs.Set(db, 'instance_get_fixed_address_v6',

View File

@ -0,0 +1,56 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2011 Justin Santa Barbara
# 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.
from nova import flags
from nova.log import logging
from nova.tests.integrated import integrated_helpers
from nova.api.openstack import common
LOG = logging.getLogger('nova.tests.integrated')
FLAGS = flags.FLAGS
FLAGS.verbose = True
class XmlTests(integrated_helpers._IntegratedTestBase):
""""Some basic XML sanity checks."""
def test_namespace_limits(self):
"""/limits should have v1.0 namespace (hasn't changed in 1.1)."""
headers = {}
headers['Accept'] = 'application/xml'
response = self.api.api_request('/limits', headers=headers)
data = response.read()
LOG.debug("data: %s" % data)
prefix = '<limits xmlns="%s"' % common.XML_NS_V10
self.assertTrue(data.startswith(prefix))
def test_namespace_servers(self):
"""/servers should have v1.1 namespace (has changed in 1.1)."""
headers = {}
headers['Accept'] = 'application/xml'
response = self.api.api_request('/servers', headers=headers)
data = response.read()
LOG.debug("data: %s" % data)
prefix = '<servers xmlns="%s"' % common.XML_NS_V11
self.assertTrue(data.startswith(prefix))

View File

@ -84,7 +84,8 @@ class ComputeTestCase(test.TestCase):
inst['launch_time'] = '10' inst['launch_time'] = '10'
inst['user_id'] = self.user.id inst['user_id'] = self.user.id
inst['project_id'] = self.project.id inst['project_id'] = self.project.id
inst['instance_type'] = 'm1.tiny' type_id = instance_types.get_instance_type_by_name('m1.tiny')['id']
inst['instance_type_id'] = type_id
inst['mac_address'] = utils.generate_mac() inst['mac_address'] = utils.generate_mac()
inst['ami_launch_index'] = 0 inst['ami_launch_index'] = 0
inst.update(params) inst.update(params)
@ -132,7 +133,7 @@ class ComputeTestCase(test.TestCase):
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(self.context, ref = self.compute_api.create(self.context,
FLAGS.default_instance_type, None, **instance) instance_types.get_default_instance_type(), None, **instance)
try: try:
self.assertNotEqual(ref[0]['display_name'], None) self.assertNotEqual(ref[0]['display_name'], None)
finally: finally:
@ -143,7 +144,7 @@ class ComputeTestCase(test.TestCase):
group = self._create_group() group = self._create_group()
ref = self.compute_api.create( ref = self.compute_api.create(
self.context, self.context,
instance_type=FLAGS.default_instance_type, instance_type=instance_types.get_default_instance_type(),
image_id=None, image_id=None,
security_group=['testgroup']) security_group=['testgroup'])
try: try:
@ -161,7 +162,7 @@ class ComputeTestCase(test.TestCase):
ref = self.compute_api.create( ref = self.compute_api.create(
self.context, self.context,
instance_type=FLAGS.default_instance_type, instance_type=instance_types.get_default_instance_type(),
image_id=None, image_id=None,
security_group=['testgroup']) security_group=['testgroup'])
try: try:
@ -177,7 +178,7 @@ class ComputeTestCase(test.TestCase):
ref = self.compute_api.create( ref = self.compute_api.create(
self.context, self.context,
instance_type=FLAGS.default_instance_type, instance_type=instance_types.get_default_instance_type(),
image_id=None, image_id=None,
security_group=['testgroup']) security_group=['testgroup'])
@ -359,8 +360,9 @@ class ComputeTestCase(test.TestCase):
instance_id = self._create_instance() instance_id = self._create_instance()
self.compute.run_instance(self.context, instance_id) self.compute.run_instance(self.context, instance_id)
inst_type = instance_types.get_instance_type_by_name('m1.xlarge')
db.instance_update(self.context, instance_id, db.instance_update(self.context, instance_id,
{'instance_type': 'm1.xlarge'}) {'instance_type_id': inst_type['id']})
self.assertRaises(exception.ApiError, self.compute_api.resize, self.assertRaises(exception.ApiError, self.compute_api.resize,
context, instance_id, 1) context, instance_id, 1)
@ -380,8 +382,8 @@ class ComputeTestCase(test.TestCase):
self.compute.terminate_instance(context, instance_id) self.compute.terminate_instance(context, instance_id)
def test_get_by_flavor_id(self): def test_get_by_flavor_id(self):
type = instance_types.get_by_flavor_id(1) type = instance_types.get_instance_type_by_flavor_id(1)
self.assertEqual(type, 'm1.tiny') self.assertEqual(type['name'], 'm1.tiny')
def test_resize_same_source_fails(self): def test_resize_same_source_fails(self):
"""Ensure instance fails to migrate when source and destination are """Ensure instance fails to migrate when source and destination are

View File

@ -62,7 +62,7 @@ class ConsoleTestCase(test.TestCase):
inst['launch_time'] = '10' inst['launch_time'] = '10'
inst['user_id'] = self.user.id inst['user_id'] = self.user.id
inst['project_id'] = self.project.id inst['project_id'] = self.project.id
inst['instance_type'] = 'm1.tiny' inst['instance_type_id'] = 1
inst['mac_address'] = utils.generate_mac() inst['mac_address'] = utils.generate_mac()
inst['ami_launch_index'] = 0 inst['ami_launch_index'] = 0
return db.instance_create(self.context, inst)['id'] return db.instance_create(self.context, inst)['id']

View File

@ -40,7 +40,11 @@ class InstanceTypeTestCase(test.TestCase):
max_flavorid = session.query(models.InstanceTypes).\ max_flavorid = session.query(models.InstanceTypes).\
order_by("flavorid desc").\ order_by("flavorid desc").\
first() first()
max_id = session.query(models.InstanceTypes).\
order_by("id desc").\
first()
self.flavorid = max_flavorid["flavorid"] + 1 self.flavorid = max_flavorid["flavorid"] + 1
self.id = max_id["id"] + 1
self.name = str(int(time.time())) self.name = str(int(time.time()))
def test_instance_type_create_then_delete(self): def test_instance_type_create_then_delete(self):
@ -53,7 +57,7 @@ class InstanceTypeTestCase(test.TestCase):
'instance type was not created') 'instance type was not created')
instance_types.destroy(self.name) instance_types.destroy(self.name)
self.assertEqual(1, self.assertEqual(1,
instance_types.get_instance_type(self.name)["deleted"]) instance_types.get_instance_type(self.id)["deleted"])
self.assertEqual(starting_inst_list, instance_types.get_all_types()) self.assertEqual(starting_inst_list, instance_types.get_all_types())
instance_types.purge(self.name) instance_types.purge(self.name)
self.assertEqual(len(starting_inst_list), self.assertEqual(len(starting_inst_list),

View File

@ -67,7 +67,7 @@ class QuotaTestCase(test.TestCase):
inst['reservation_id'] = 'r-fakeres' inst['reservation_id'] = 'r-fakeres'
inst['user_id'] = self.user.id inst['user_id'] = self.user.id
inst['project_id'] = self.project.id inst['project_id'] = self.project.id
inst['instance_type'] = 'm1.large' inst['instance_type_id'] = '3' # m1.large
inst['vcpus'] = cores inst['vcpus'] = cores
inst['mac_address'] = utils.generate_mac() inst['mac_address'] = utils.generate_mac()
return db.instance_create(self.context, inst)['id'] return db.instance_create(self.context, inst)['id']
@ -124,11 +124,12 @@ class QuotaTestCase(test.TestCase):
for i in range(FLAGS.quota_instances): for i in range(FLAGS.quota_instances):
instance_id = self._create_instance() instance_id = self._create_instance()
instance_ids.append(instance_id) instance_ids.append(instance_id)
inst_type = instance_types.get_instance_type_by_name('m1.small')
self.assertRaises(quota.QuotaError, compute.API().create, self.assertRaises(quota.QuotaError, compute.API().create,
self.context, self.context,
min_count=1, min_count=1,
max_count=1, max_count=1,
instance_type='m1.small', instance_type=inst_type,
image_id=1) image_id=1)
for instance_id in instance_ids: for instance_id in instance_ids:
db.instance_destroy(self.context, instance_id) db.instance_destroy(self.context, instance_id)
@ -137,11 +138,12 @@ class QuotaTestCase(test.TestCase):
instance_ids = [] instance_ids = []
instance_id = self._create_instance(cores=4) instance_id = self._create_instance(cores=4)
instance_ids.append(instance_id) instance_ids.append(instance_id)
inst_type = instance_types.get_instance_type_by_name('m1.small')
self.assertRaises(quota.QuotaError, compute.API().create, self.assertRaises(quota.QuotaError, compute.API().create,
self.context, self.context,
min_count=1, min_count=1,
max_count=1, max_count=1,
instance_type='m1.small', instance_type=inst_type,
image_id=1) image_id=1)
for instance_id in instance_ids: for instance_id in instance_ids:
db.instance_destroy(self.context, instance_id) db.instance_destroy(self.context, instance_id)
@ -192,11 +194,12 @@ class QuotaTestCase(test.TestCase):
metadata = {} metadata = {}
for i in range(FLAGS.quota_metadata_items + 1): for i in range(FLAGS.quota_metadata_items + 1):
metadata['key%s' % i] = 'value%s' % i metadata['key%s' % i] = 'value%s' % i
inst_type = instance_types.get_instance_type_by_name('m1.small')
self.assertRaises(quota.QuotaError, compute.API().create, self.assertRaises(quota.QuotaError, compute.API().create,
self.context, self.context,
min_count=1, min_count=1,
max_count=1, max_count=1,
instance_type='m1.small', instance_type=inst_type,
image_id='fake', image_id='fake',
metadata=metadata) metadata=metadata)
@ -207,13 +210,15 @@ class QuotaTestCase(test.TestCase):
def _create_with_injected_files(self, files): def _create_with_injected_files(self, files):
api = compute.API(image_service=self.StubImageService()) api = compute.API(image_service=self.StubImageService())
inst_type = instance_types.get_instance_type_by_name('m1.small')
api.create(self.context, min_count=1, max_count=1, api.create(self.context, min_count=1, max_count=1,
instance_type='m1.small', image_id='fake', instance_type=inst_type, image_id='fake',
injected_files=files) injected_files=files)
def test_no_injected_files(self): def test_no_injected_files(self):
api = compute.API(image_service=self.StubImageService()) api = compute.API(image_service=self.StubImageService())
api.create(self.context, instance_type='m1.small', image_id='fake') inst_type = instance_types.get_instance_type_by_name('m1.small')
api.create(self.context, instance_type=inst_type, image_id='fake')
def test_max_injected_files(self): def test_max_injected_files(self):
files = [] files = []

View File

@ -263,7 +263,7 @@ class SimpleDriverTestCase(test.TestCase):
inst['reservation_id'] = 'r-fakeres' inst['reservation_id'] = 'r-fakeres'
inst['user_id'] = self.user.id inst['user_id'] = self.user.id
inst['project_id'] = self.project.id inst['project_id'] = self.project.id
inst['instance_type'] = 'm1.tiny' inst['instance_type_id'] = '1'
inst['mac_address'] = utils.generate_mac() inst['mac_address'] = utils.generate_mac()
inst['vcpus'] = kwargs.get('vcpus', 1) inst['vcpus'] = kwargs.get('vcpus', 1)
inst['ami_launch_index'] = 0 inst['ami_launch_index'] = 0

View File

@ -140,7 +140,7 @@ class LibvirtConnTestCase(test.TestCase):
'vcpus': 2, 'vcpus': 2,
'project_id': 'fake', 'project_id': 'fake',
'bridge': 'br101', 'bridge': 'br101',
'instance_type': 'm1.small'} 'instance_type_id': '5'} # m1.small
def lazy_load_library_exists(self): def lazy_load_library_exists(self):
"""check if libvirt is available.""" """check if libvirt is available."""
@ -479,7 +479,7 @@ class LibvirtConnTestCase(test.TestCase):
fake_timer = FakeTime() fake_timer = FakeTime()
self.create_fake_libvirt_mock(nwfilterLookupByName=fake_raise) self.create_fake_libvirt_mock()
instance_ref = db.instance_create(self.context, self.test_instance) instance_ref = db.instance_create(self.context, self.test_instance)
# Start test # Start test
@ -488,6 +488,7 @@ class LibvirtConnTestCase(test.TestCase):
conn = libvirt_conn.LibvirtConnection(False) conn = libvirt_conn.LibvirtConnection(False)
conn.firewall_driver.setattr('setup_basic_filtering', fake_none) conn.firewall_driver.setattr('setup_basic_filtering', fake_none)
conn.firewall_driver.setattr('prepare_instance_filter', fake_none) conn.firewall_driver.setattr('prepare_instance_filter', fake_none)
conn.firewall_driver.setattr('instance_filter_exists', fake_none)
conn.ensure_filtering_rules_for_instance(instance_ref, conn.ensure_filtering_rules_for_instance(instance_ref,
time=fake_timer) time=fake_timer)
except exception.Error, e: except exception.Error, e:

View File

@ -106,7 +106,7 @@ class VolumeTestCase(test.TestCase):
inst['launch_time'] = '10' inst['launch_time'] = '10'
inst['user_id'] = 'fake' inst['user_id'] = 'fake'
inst['project_id'] = 'fake' inst['project_id'] = 'fake'
inst['instance_type'] = 'm1.tiny' inst['instance_type_id'] = '2' # m1.tiny
inst['mac_address'] = utils.generate_mac() inst['mac_address'] = utils.generate_mac()
inst['ami_launch_index'] = 0 inst['ami_launch_index'] = 0
instance_id = db.instance_create(self.context, inst)['id'] instance_id = db.instance_create(self.context, inst)['id']

View File

@ -80,7 +80,7 @@ class XenAPIVolumeTestCase(test.TestCase):
'image_id': 1, 'image_id': 1,
'kernel_id': 2, 'kernel_id': 2,
'ramdisk_id': 3, 'ramdisk_id': 3,
'instance_type': 'm1.large', 'instance_type_id': '3', # m1.large
'mac_address': 'aa:bb:cc:dd:ee:ff', 'mac_address': 'aa:bb:cc:dd:ee:ff',
'os_type': 'linux'} 'os_type': 'linux'}
@ -289,11 +289,11 @@ class XenAPIVMTestCase(test.TestCase):
'enabled':'1'}], 'enabled':'1'}],
'ip6s': [{'ip': 'fe80::a8bb:ccff:fedd:eeff', 'ip6s': [{'ip': 'fe80::a8bb:ccff:fedd:eeff',
'netmask': '120', 'netmask': '120',
'enabled': '1', 'enabled': '1'}],
'gateway': 'fe80::a00:1'}],
'mac': 'aa:bb:cc:dd:ee:ff', 'mac': 'aa:bb:cc:dd:ee:ff',
'dns': ['10.0.0.2'], 'dns': ['10.0.0.2'],
'gateway': '10.0.0.1'}) 'gateway': '10.0.0.1',
'gateway6': 'fe80::a00:1'})
def check_vm_params_for_windows(self): def check_vm_params_for_windows(self):
self.assertEquals(self.vm['platform']['nx'], 'true') self.assertEquals(self.vm['platform']['nx'], 'true')
@ -328,7 +328,7 @@ class XenAPIVMTestCase(test.TestCase):
self.assertEquals(self.vm['HVM_boot_policy'], '') self.assertEquals(self.vm['HVM_boot_policy'], '')
def _test_spawn(self, image_id, kernel_id, ramdisk_id, def _test_spawn(self, image_id, kernel_id, ramdisk_id,
instance_type="m1.large", os_type="linux", instance_type_id="3", os_type="linux",
instance_id=1, check_injection=False): instance_id=1, check_injection=False):
stubs.stubout_loopingcall_start(self.stubs) stubs.stubout_loopingcall_start(self.stubs)
values = {'id': instance_id, values = {'id': instance_id,
@ -337,7 +337,7 @@ class XenAPIVMTestCase(test.TestCase):
'image_id': image_id, 'image_id': image_id,
'kernel_id': kernel_id, 'kernel_id': kernel_id,
'ramdisk_id': ramdisk_id, 'ramdisk_id': ramdisk_id,
'instance_type': instance_type, 'instance_type_id': instance_type_id,
'mac_address': 'aa:bb:cc:dd:ee:ff', 'mac_address': 'aa:bb:cc:dd:ee:ff',
'os_type': os_type} 'os_type': os_type}
instance = db.instance_create(self.context, values) instance = db.instance_create(self.context, values)
@ -349,7 +349,7 @@ class XenAPIVMTestCase(test.TestCase):
FLAGS.xenapi_image_service = 'glance' FLAGS.xenapi_image_service = 'glance'
self.assertRaises(Exception, self.assertRaises(Exception,
self._test_spawn, self._test_spawn,
1, 2, 3, "m1.xlarge") 1, 2, 3, "4") # m1.xlarge
def test_spawn_raw_objectstore(self): def test_spawn_raw_objectstore(self):
FLAGS.xenapi_image_service = 'objectstore' FLAGS.xenapi_image_service = 'objectstore'
@ -523,7 +523,7 @@ class XenAPIVMTestCase(test.TestCase):
'image_id': 1, 'image_id': 1,
'kernel_id': 2, 'kernel_id': 2,
'ramdisk_id': 3, 'ramdisk_id': 3,
'instance_type': 'm1.large', 'instance_type_id': '3', # m1.large
'mac_address': 'aa:bb:cc:dd:ee:ff', 'mac_address': 'aa:bb:cc:dd:ee:ff',
'os_type': 'linux'} 'os_type': 'linux'}
instance = db.instance_create(self.context, values) instance = db.instance_create(self.context, values)
@ -580,7 +580,7 @@ class XenAPIMigrateInstance(test.TestCase):
'kernel_id': None, 'kernel_id': None,
'ramdisk_id': None, 'ramdisk_id': None,
'local_gb': 5, 'local_gb': 5,
'instance_type': 'm1.large', 'instance_type_id': '3', # m1.large
'mac_address': 'aa:bb:cc:dd:ee:ff', 'mac_address': 'aa:bb:cc:dd:ee:ff',
'os_type': 'linux'} 'os_type': 'linux'}

View File

@ -169,34 +169,34 @@ def _get_network_info(instance):
instance['id']) instance['id'])
network_info = [] network_info = []
def ip_dict(ip):
return {
"ip": ip.address,
"netmask": network["netmask"],
"enabled": "1"}
def ip6_dict(ip6):
prefix = ip6.network.cidr_v6
mac = instance.mac_address
return {
"ip": utils.to_global_ipv6(prefix, mac),
"netmask": ip6.network.netmask_v6,
"gateway": ip6.network.gateway_v6,
"enabled": "1"}
for network in networks: for network in networks:
network_ips = [ip for ip in ip_addresses network_ips = [ip for ip in ip_addresses
if ip.network_id == network.id] if ip['network_id'] == network['id']]
def ip_dict(ip):
return {
'ip': ip['address'],
'netmask': network['netmask'],
'enabled': '1'}
def ip6_dict():
prefix = network['cidr_v6']
mac = instance['mac_address']
return {
'ip': utils.to_global_ipv6(prefix, mac),
'netmask': network['netmask_v6'],
'enabled': '1'}
mapping = { mapping = {
'label': network['label'], 'label': network['label'],
'gateway': network['gateway'], 'gateway': network['gateway'],
'mac': instance.mac_address, 'mac': instance['mac_address'],
'dns': [network['dns']], 'dns': [network['dns']],
'ips': [ip_dict(ip) for ip in network_ips]} 'ips': [ip_dict(ip) for ip in network_ips]}
if FLAGS.use_ipv6: if FLAGS.use_ipv6:
mapping['ip6s'] = [ip6_dict(ip) for ip in network_ips] mapping['ip6s'] = [ip6_dict()]
mapping['gateway6'] = network['gateway_v6']
network_info.append((network, mapping)) network_info.append((network, mapping))
return network_info return network_info
@ -796,7 +796,10 @@ class LibvirtConnection(driver.ComputeDriver):
root_fname = '%08x' % int(disk_images['image_id']) root_fname = '%08x' % int(disk_images['image_id'])
size = FLAGS.minimum_root_size size = FLAGS.minimum_root_size
if inst['instance_type'] == 'm1.tiny' or suffix == '.rescue':
inst_type_id = inst['instance_type_id']
inst_type = instance_types.get_instance_type(inst_type_id)
if inst_type['name'] == 'm1.tiny' or suffix == '.rescue':
size = None size = None
root_fname += "_sm" root_fname += "_sm"
@ -808,14 +811,13 @@ class LibvirtConnection(driver.ComputeDriver):
user=user, user=user,
project=project, project=project,
size=size) size=size)
type_data = instance_types.get_instance_type(inst['instance_type'])
if type_data['local_gb']: if inst_type['local_gb']:
self._cache_image(fn=self._create_local, self._cache_image(fn=self._create_local,
target=basepath('disk.local'), target=basepath('disk.local'),
fname="local_%s" % type_data['local_gb'], fname="local_%s" % inst_type['local_gb'],
cow=FLAGS.use_cow_images, cow=FLAGS.use_cow_images,
local_gb=type_data['local_gb']) local_gb=inst_type['local_gb'])
# For now, we assume that if we're not using a kernel, we're using a # For now, we assume that if we're not using a kernel, we're using a
# partitioned disk image where the target partition is the first # partitioned disk image where the target partition is the first
@ -949,8 +951,8 @@ class LibvirtConnection(driver.ComputeDriver):
nics.append(self._get_nic_for_xml(network, nics.append(self._get_nic_for_xml(network,
mapping)) mapping))
# FIXME(vish): stick this in db # FIXME(vish): stick this in db
instance_type_name = instance['instance_type'] inst_type_id = instance['instance_type_id']
instance_type = instance_types.get_instance_type(instance_type_name) inst_type = instance_types.get_instance_type(inst_type_id)
if FLAGS.use_cow_images: if FLAGS.use_cow_images:
driver_type = 'qcow2' driver_type = 'qcow2'
@ -961,10 +963,10 @@ class LibvirtConnection(driver.ComputeDriver):
'name': instance['name'], 'name': instance['name'],
'basepath': os.path.join(FLAGS.instances_path, 'basepath': os.path.join(FLAGS.instances_path,
instance['name']), instance['name']),
'memory_kb': instance_type['memory_mb'] * 1024, 'memory_kb': inst_type['memory_mb'] * 1024,
'vcpus': instance_type['vcpus'], 'vcpus': inst_type['vcpus'],
'rescue': rescue, 'rescue': rescue,
'local': instance_type['local_gb'], 'local': inst_type['local_gb'],
'driver_type': driver_type, 'driver_type': driver_type,
'nics': nics} 'nics': nics}
@ -1401,18 +1403,13 @@ class LibvirtConnection(driver.ComputeDriver):
# wait for completion # wait for completion
timeout_count = range(FLAGS.live_migration_retry_count) timeout_count = range(FLAGS.live_migration_retry_count)
while timeout_count: while timeout_count:
try: if self.firewall_driver.instance_filter_exists(instance_ref):
filter_name = 'nova-instance-%s' % instance_ref.name
self._conn.nwfilterLookupByName(filter_name)
break break
except libvirt.libvirtError: timeout_count.pop()
timeout_count.pop() if len(timeout_count) == 0:
if len(timeout_count) == 0: msg = _('Timeout migrating for %s. nwfilter not found.')
ec2_id = instance_ref['hostname'] raise exception.Error(msg % instance_ref.name)
iname = instance_ref.name time.sleep(1)
msg = _('Timeout migrating for %(ec2_id)s(%(iname)s)')
raise exception.Error(msg % locals())
time.sleep(1)
def live_migration(self, ctxt, instance_ref, dest, def live_migration(self, ctxt, instance_ref, dest,
post_method, recover_method): post_method, recover_method):
@ -1541,6 +1538,10 @@ class FirewallDriver(object):
""" """
raise NotImplementedError() raise NotImplementedError()
def instance_filter_exists(self, instance):
"""Check nova-instance-instance-xxx exists"""
raise NotImplementedError()
class NWFilterFirewall(FirewallDriver): class NWFilterFirewall(FirewallDriver):
""" """
@ -1848,6 +1849,21 @@ class NWFilterFirewall(FirewallDriver):
return 'nova-instance-%s' % (instance['name']) return 'nova-instance-%s' % (instance['name'])
return 'nova-instance-%s-%s' % (instance['name'], nic_id) return 'nova-instance-%s-%s' % (instance['name'], nic_id)
def instance_filter_exists(self, instance):
"""Check nova-instance-instance-xxx exists"""
network_info = _get_network_info(instance)
for (network, mapping) in network_info:
nic_id = mapping['mac'].replace(':', '')
instance_filter_name = self._instance_filter_name(instance, nic_id)
try:
self._conn.nwfilterLookupByName(instance_filter_name)
except libvirt.libvirtError:
name = instance.name
LOG.debug(_('The nwfilter(%(instance_filter_name)s) for'
'%(name)s is not found.') % locals())
return False
return True
class IptablesFirewallDriver(FirewallDriver): class IptablesFirewallDriver(FirewallDriver):
def __init__(self, execute=None, **kwargs): def __init__(self, execute=None, **kwargs):
@ -2037,6 +2053,10 @@ class IptablesFirewallDriver(FirewallDriver):
return ipv4_rules, ipv6_rules return ipv4_rules, ipv6_rules
def instance_filter_exists(self, instance):
"""Check nova-instance-instance-xxx exists"""
return self.nwfilter.instance_filter_exists(instance)
def refresh_security_group_members(self, security_group): def refresh_security_group_members(self, security_group):
pass pass

View File

@ -101,8 +101,8 @@ class VMHelper(HelperBase):
3. Using hardware virtualization 3. Using hardware virtualization
""" """
instance_type = instance_types.\ inst_type_id = instance.instance_type_id
get_instance_type(instance.instance_type) instance_type = instance_types.get_instance_type(inst_type_id)
mem = str(long(instance_type['memory_mb']) * 1024 * 1024) mem = str(long(instance_type['memory_mb']) * 1024 * 1024)
vcpus = str(instance_type['vcpus']) vcpus = str(instance_type['vcpus'])
rec = { rec = {
@ -169,8 +169,8 @@ class VMHelper(HelperBase):
@classmethod @classmethod
def ensure_free_mem(cls, session, instance): def ensure_free_mem(cls, session, instance):
instance_type = instance_types.get_instance_type( inst_type_id = instance.instance_type_id
instance.instance_type) instance_type = instance_types.get_instance_type(inst_type_id)
mem = long(instance_type['memory_mb']) * 1024 * 1024 mem = long(instance_type['memory_mb']) * 1024 * 1024
#get free memory from host #get free memory from host
host = session.get_xenapi_host() host = session.get_xenapi_host()
@ -1130,7 +1130,7 @@ def _prepare_injectables(inst, networks_info):
'dns': dns, 'dns': dns,
'address_v6': ip_v6 and ip_v6['ip'] or '', 'address_v6': ip_v6 and ip_v6['ip'] or '',
'netmask_v6': ip_v6 and ip_v6['netmask'] or '', 'netmask_v6': ip_v6 and ip_v6['netmask'] or '',
'gateway_v6': ip_v6 and ip_v6['gateway'] or '', 'gateway_v6': ip_v6 and info['gateway6'] or '',
'use_ipv6': FLAGS.use_ipv6} 'use_ipv6': FLAGS.use_ipv6}
interfaces_info.append(interface_info) interfaces_info.append(interface_info)

View File

@ -176,7 +176,7 @@ class VMOps(object):
vdi_ref, network_info) vdi_ref, network_info)
self.create_vifs(vm_ref, network_info) self.create_vifs(vm_ref, network_info)
self.inject_network_info(instance, vm_ref, network_info) self.inject_network_info(instance, network_info, vm_ref)
return vm_ref return vm_ref
def _spawn(self, instance, vm_ref): def _spawn(self, instance, vm_ref):
@ -802,8 +802,10 @@ class VMOps(object):
instance['id']) instance['id'])
networks = db.network_get_all_by_instance(admin_context, networks = db.network_get_all_by_instance(admin_context,
instance['id']) instance['id'])
flavor = db.instance_type_get_by_name(admin_context,
instance['instance_type']) inst_type = db.instance_type_get_by_id(admin_context,
instance['instance_type_id'])
network_info = [] network_info = []
for network in networks: for network in networks:
network_IPs = [ip for ip in IPs if ip.network_id == network.id] network_IPs = [ip for ip in IPs if ip.network_id == network.id]
@ -814,12 +816,11 @@ class VMOps(object):
"netmask": network["netmask"], "netmask": network["netmask"],
"enabled": "1"} "enabled": "1"}
def ip6_dict(ip6): def ip6_dict():
return { return {
"ip": utils.to_global_ipv6(network['cidr_v6'], "ip": utils.to_global_ipv6(network['cidr_v6'],
instance['mac_address']), instance['mac_address']),
"netmask": network['netmask_v6'], "netmask": network['netmask_v6'],
"gateway": network['gateway_v6'],
"enabled": "1"} "enabled": "1"}
info = { info = {
@ -827,23 +828,41 @@ class VMOps(object):
'gateway': network['gateway'], 'gateway': network['gateway'],
'broadcast': network['broadcast'], 'broadcast': network['broadcast'],
'mac': instance.mac_address, 'mac': instance.mac_address,
'rxtx_cap': flavor['rxtx_cap'], 'rxtx_cap': inst_type['rxtx_cap'],
'dns': [network['dns']], 'dns': [network['dns']],
'ips': [ip_dict(ip) for ip in network_IPs]} 'ips': [ip_dict(ip) for ip in network_IPs]}
if network['cidr_v6']: if network['cidr_v6']:
info['ip6s'] = [ip6_dict(ip) for ip in network_IPs] info['ip6s'] = [ip6_dict()]
if network['gateway_v6']:
info['gateway6'] = network['gateway_v6']
network_info.append((network, info)) network_info.append((network, info))
return network_info return network_info
def inject_network_info(self, instance, vm_ref, network_info): #TODO{tr3buchet) remove this shim with nova-multi-nic
def inject_network_info(self, instance, network_info=None, vm_ref=None):
"""
shim in place which makes inject_network_info work without being
passed network_info.
shim goes away after nova-multi-nic
"""
if not network_info:
network_info = self._get_network_info(instance)
self._inject_network_info(instance, network_info, vm_ref)
def _inject_network_info(self, instance, network_info, vm_ref=None):
""" """
Generate the network info and make calls to place it into the Generate the network info and make calls to place it into the
xenstore and the xenstore param list. xenstore and the xenstore param list.
vm_ref can be passed in because it will sometimes be different than
what VMHelper.lookup(session, instance.name) will find (ex: rescue)
""" """
logging.debug(_("injecting network info to xs for vm: |%s|"), vm_ref) logging.debug(_("injecting network info to xs for vm: |%s|"), vm_ref)
# this function raises if vm_ref is not a vm_opaque_ref if vm_ref:
self._session.get_xenapi().VM.get_record(vm_ref) # this function raises if vm_ref is not a vm_opaque_ref
self._session.get_xenapi().VM.get_record(vm_ref)
else:
vm_ref = VMHelper.lookup(self._session, instance.name)
for (network, info) in network_info: for (network, info) in network_info:
location = 'vm-data/networking/%s' % info['mac'].replace(':', '') location = 'vm-data/networking/%s' % info['mac'].replace(':', '')
@ -875,8 +894,10 @@ class VMOps(object):
VMHelper.create_vif(self._session, vm_ref, network_ref, VMHelper.create_vif(self._session, vm_ref, network_ref,
mac_address, device, rxtx_cap) mac_address, device, rxtx_cap)
def reset_network(self, instance, vm_ref): def reset_network(self, instance, vm_ref=None):
"""Creates uuid arg to pass to make_agent_call and calls it.""" """Creates uuid arg to pass to make_agent_call and calls it."""
if not vm_ref:
vm_ref = VMHelper.lookup(self._session, instance.name)
args = {'id': str(uuid.uuid4())} args = {'id': str(uuid.uuid4())}
# TODO(tr3buchet): fix function call after refactor # TODO(tr3buchet): fix function call after refactor
#resp = self._make_agent_call('resetnetwork', instance, '', args) #resp = self._make_agent_call('resetnetwork', instance, '', args)

View File

@ -63,6 +63,7 @@ import xmlrpclib
from eventlet import event from eventlet import event
from eventlet import tpool from eventlet import tpool
from eventlet import timeout
from nova import context from nova import context
from nova import db from nova import db
@ -140,6 +141,9 @@ flags.DEFINE_bool('xenapi_remap_vbd_dev', False,
flags.DEFINE_string('xenapi_remap_vbd_dev_prefix', 'sd', flags.DEFINE_string('xenapi_remap_vbd_dev_prefix', 'sd',
'Specify prefix to remap VBD dev to ' 'Specify prefix to remap VBD dev to '
'(ex. /dev/xvdb -> /dev/sdb)') '(ex. /dev/xvdb -> /dev/sdb)')
flags.DEFINE_integer('xenapi_login_timeout',
10,
'Timeout in seconds for XenAPI login.')
def get_connection(_): def get_connection(_):
@ -318,7 +322,10 @@ class XenAPISession(object):
def __init__(self, url, user, pw): def __init__(self, url, user, pw):
self.XenAPI = self.get_imported_xenapi() self.XenAPI = self.get_imported_xenapi()
self._session = self._create_session(url) self._session = self._create_session(url)
self._session.login_with_password(user, pw) exception = self.XenAPI.Failure(_("Unable to log in to XenAPI "
"(is the Dom0 disk full?)"))
with timeout.Timeout(FLAGS.xenapi_login_timeout, exception):
self._session.login_with_password(user, pw)
self.loop = None self.loop = None
def get_imported_xenapi(self): def get_imported_xenapi(self):

View File

@ -355,24 +355,25 @@ class Controller(object):
if type(result) is dict: if type(result) is dict:
content_type = req.best_match_content_type() content_type = req.best_match_content_type()
body = self._serialize(result, content_type) default_xmlns = self.get_default_xmlns(req)
body = self._serialize(result, content_type, default_xmlns)
response = webob.Response() response = webob.Response()
response.headers["Content-Type"] = content_type response.headers["Content-Type"] = content_type
response.body = body response.body = body
return response return response
else: else:
return result return result
def _serialize(self, data, content_type): def _serialize(self, data, content_type, default_xmlns):
""" """
Serialize the given dict to the provided content_type. Serialize the given dict to the provided content_type.
Uses self._serialization_metadata if it exists, which is a dict mapping Uses self._serialization_metadata if it exists, which is a dict mapping
MIME types to information needed to serialize to that type. MIME types to information needed to serialize to that type.
""" """
_metadata = getattr(type(self), "_serialization_metadata", {}) _metadata = getattr(type(self), "_serialization_metadata", {})
serializer = Serializer(_metadata)
serializer = Serializer(_metadata, default_xmlns)
try: try:
return serializer.serialize(data, content_type) return serializer.serialize(data, content_type)
except exception.InvalidContentType: except exception.InvalidContentType:
@ -388,19 +389,24 @@ class Controller(object):
serializer = Serializer(_metadata) serializer = Serializer(_metadata)
return serializer.deserialize(data, content_type) return serializer.deserialize(data, content_type)
def get_default_xmlns(self, req):
"""Provide the XML namespace to use if none is otherwise specified."""
return None
class Serializer(object): class Serializer(object):
""" """
Serializes and deserializes dictionaries to certain MIME types. Serializes and deserializes dictionaries to certain MIME types.
""" """
def __init__(self, metadata=None): def __init__(self, metadata=None, default_xmlns=None):
""" """
Create a serializer based on the given WSGI environment. Create a serializer based on the given WSGI environment.
'metadata' is an optional dict mapping MIME types to information 'metadata' is an optional dict mapping MIME types to information
needed to serialize a dictionary to that type. needed to serialize a dictionary to that type.
""" """
self.metadata = metadata or {} self.metadata = metadata or {}
self.default_xmlns = default_xmlns
def _get_serialize_handler(self, content_type): def _get_serialize_handler(self, content_type):
handlers = { handlers = {
@ -478,11 +484,23 @@ class Serializer(object):
root_key = data.keys()[0] root_key = data.keys()[0]
doc = minidom.Document() doc = minidom.Document()
node = self._to_xml_node(doc, metadata, root_key, data[root_key]) node = self._to_xml_node(doc, metadata, root_key, data[root_key])
xmlns = node.getAttribute('xmlns')
if not xmlns and self.default_xmlns:
node.setAttribute('xmlns', self.default_xmlns)
return node.toprettyxml(indent=' ') return node.toprettyxml(indent=' ')
def _to_xml_node(self, doc, metadata, nodename, data): def _to_xml_node(self, doc, metadata, nodename, data):
"""Recursive method to convert data members to XML nodes.""" """Recursive method to convert data members to XML nodes."""
result = doc.createElement(nodename) result = doc.createElement(nodename)
# Set the xml namespace if one is specified
# TODO(justinsb): We could also use prefixes on the keys
xmlns = metadata.get('xmlns', None)
if xmlns:
result.setAttribute('xmlns', xmlns)
if type(data) is list: if type(data) is list:
singular = metadata.get('plurals', {}).get(nodename, None) singular = metadata.get('plurals', {}).get(nodename, None)
if singular is None: if singular is None:
@ -532,6 +550,7 @@ def paste_config_file(basename):
""" """
configfiles = [basename, configfiles = [basename,
os.path.join(FLAGS.state_path, 'etc', 'nova', basename),
os.path.join(FLAGS.state_path, 'etc', basename), os.path.join(FLAGS.state_path, 'etc', basename),
os.path.join(FLAGS.state_path, basename), os.path.join(FLAGS.state_path, basename),
'/etc/nova/%s' % basename] '/etc/nova/%s' % basename]

View File

@ -56,16 +56,17 @@ def read_record(self, arg_dict):
and boolean True, attempting to read a non-existent path will return and boolean True, attempting to read a non-existent path will return
the string 'None' instead of raising an exception. the string 'None' instead of raising an exception.
""" """
cmd = "xenstore-read /local/domain/%(dom_id)s/%(path)s" % arg_dict cmd = ["xenstore-read", "/local/domain/%(dom_id)s/%(path)s" % arg_dict]
try: try:
return _run_command(cmd).rstrip("\n") ret, result = _run_command(cmd)
return result.rstrip("\n")
except pluginlib.PluginError, e: except pluginlib.PluginError, e:
if arg_dict.get("ignore_missing_path", False): if arg_dict.get("ignore_missing_path", False):
cmd = "xenstore-exists /local/domain/%(dom_id)s/%(path)s; echo $?" cmd = ["xenstore-exists",
cmd = cmd % arg_dict "/local/domain/%(dom_id)s/%(path)s" % arg_dict]
ret = _run_command(cmd).strip() ret, result = _run_command(cmd).strip()
# If the path exists, the cmd should return "0" # If the path exists, the cmd should return "0"
if ret != "0": if ret != 0:
# No such path, so ignore the error and return the # No such path, so ignore the error and return the
# string 'None', since None can't be marshalled # string 'None', since None can't be marshalled
# over RPC. # over RPC.
@ -83,8 +84,9 @@ def write_record(self, arg_dict):
you must specify a 'value' key, whose value must be a string. Typically, you must specify a 'value' key, whose value must be a string. Typically,
you can json-ify more complex values and store the json output. you can json-ify more complex values and store the json output.
""" """
cmd = "xenstore-write /local/domain/%(dom_id)s/%(path)s '%(value)s'" cmd = ["xenstore-write",
cmd = cmd % arg_dict "/local/domain/%(dom_id)s/%(path)s" % arg_dict,
arg_dict["value"]]
_run_command(cmd) _run_command(cmd)
return arg_dict["value"] return arg_dict["value"]
@ -96,10 +98,10 @@ def list_records(self, arg_dict):
path as the key and the stored value as the value. If the path path as the key and the stored value as the value. If the path
doesn't exist, an empty dict is returned. doesn't exist, an empty dict is returned.
""" """
cmd = "xenstore-ls /local/domain/%(dom_id)s/%(path)s" % arg_dict dirpath = "/local/domain/%(dom_id)s/%(path)s" % arg_dict
cmd = cmd.rstrip("/") cmd = ["xenstore-ls", dirpath.rstrip("/")]
try: try:
recs = _run_command(cmd) ret, recs = _run_command(cmd)
except pluginlib.PluginError, e: except pluginlib.PluginError, e:
if "No such file or directory" in "%s" % e: if "No such file or directory" in "%s" % e:
# Path doesn't exist. # Path doesn't exist.
@ -128,8 +130,9 @@ def delete_record(self, arg_dict):
"""Just like it sounds: it removes the record for the specified """Just like it sounds: it removes the record for the specified
VM and the specified path from xenstore. VM and the specified path from xenstore.
""" """
cmd = "xenstore-rm /local/domain/%(dom_id)s/%(path)s" % arg_dict cmd = ["xenstore-rm", "/local/domain/%(dom_id)s/%(path)s" % arg_dict]
return _run_command(cmd) ret, result = _run_command(cmd)
return result
def _paths_from_ls(recs): def _paths_from_ls(recs):
@ -171,9 +174,9 @@ def _run_command(cmd):
Otherwise, the output from stdout is returned. Otherwise, the output from stdout is returned.
""" """
pipe = subprocess.PIPE pipe = subprocess.PIPE
proc = subprocess.Popen([cmd], shell=True, stdin=pipe, stdout=pipe, proc = subprocess.Popen(cmd, stdin=pipe, stdout=pipe, stderr=pipe,
stderr=pipe, close_fds=True) close_fds=True)
proc.wait() ret = proc.wait()
err = proc.stderr.read() err = proc.stderr.read()
if err: if err:
raise pluginlib.PluginError(err) raise pluginlib.PluginError(err)

View File

@ -16,6 +16,7 @@
# 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 glob
import os import os
import subprocess import subprocess
import sys import sys
@ -86,6 +87,19 @@ try:
except: except:
pass pass
def find_data_files(destdir, srcdir):
package_data = []
files = []
for d in glob.glob('%s/*' % (srcdir, )):
if os.path.isdir(d):
package_data += find_data_files(
os.path.join(destdir, os.path.basename(d)), d)
else:
files += [d]
package_data += [(destdir, files)]
return package_data
DistUtilsExtra.auto.setup(name='nova', DistUtilsExtra.auto.setup(name='nova',
version=version.canonical_version_string(), version=version.canonical_version_string(),
description='cloud computing fabric controller', description='cloud computing fabric controller',
@ -96,6 +110,7 @@ DistUtilsExtra.auto.setup(name='nova',
packages=find_packages(exclude=['bin', 'smoketests']), packages=find_packages(exclude=['bin', 'smoketests']),
include_package_data=True, include_package_data=True,
test_suite='nose.collector', test_suite='nose.collector',
data_files=find_data_files('share/nova', 'tools'),
scripts=['bin/nova-ajax-console-proxy', scripts=['bin/nova-ajax-console-proxy',
'bin/nova-api', 'bin/nova-api',
'bin/nova-compute', 'bin/nova-compute',