Includes changes for creating instances via the Rackspace API. Utilizes much of the existing EC2 functionality to power the Rackspace side of things, at least for now.
This commit is contained in:
		
							
								
								
									
										42
									
								
								nova/api/cloud.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								nova/api/cloud.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,42 @@
 | 
			
		||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
 | 
			
		||||
 | 
			
		||||
# Copyright 2010 United States Government as represented by the
 | 
			
		||||
# Administrator of the National Aeronautics and Space Administration.
 | 
			
		||||
# All Rights Reserved.
 | 
			
		||||
#
 | 
			
		||||
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
 | 
			
		||||
#    not use this file except in compliance with the License. You may obtain
 | 
			
		||||
#    a copy of the License at
 | 
			
		||||
#
 | 
			
		||||
#         http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
#
 | 
			
		||||
#    Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
#    License for the specific language governing permissions and limitations
 | 
			
		||||
#    under the License.
 | 
			
		||||
 | 
			
		||||
"""
 | 
			
		||||
Methods for API calls to control instances via AMQP.
 | 
			
		||||
"""
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
from nova import db
 | 
			
		||||
from nova import flags
 | 
			
		||||
from nova import rpc
 | 
			
		||||
 | 
			
		||||
FLAGS = flags.FLAGS
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def reboot(instance_id, context=None):
 | 
			
		||||
    """Reboot the given instance.
 | 
			
		||||
    
 | 
			
		||||
    #TODO(gundlach) not actually sure what context is used for by ec2 here
 | 
			
		||||
    -- I think we can just remove it and use None all the time.
 | 
			
		||||
    """
 | 
			
		||||
    instance_ref = db.instance_get_by_ec2_id(None, instance_id)
 | 
			
		||||
    host = instance_ref['host']
 | 
			
		||||
    rpc.cast(db.queue_get_for(context, FLAGS.compute_topic, host),
 | 
			
		||||
             {"method": "reboot_instance",
 | 
			
		||||
              "args": {"context": None,
 | 
			
		||||
                       "instance_id": instance_ref['id']}})
 | 
			
		||||
@@ -36,6 +36,7 @@ from nova import quota
 | 
			
		||||
from nova import rpc
 | 
			
		||||
from nova import utils
 | 
			
		||||
from nova.compute.instance_types import INSTANCE_TYPES
 | 
			
		||||
from nova.api import cloud
 | 
			
		||||
from nova.api.ec2 import images
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -684,12 +685,7 @@ class CloudController(object):
 | 
			
		||||
    def reboot_instances(self, context, instance_id, **kwargs):
 | 
			
		||||
        """instance_id is a list of instance ids"""
 | 
			
		||||
        for id_str in instance_id:
 | 
			
		||||
            instance_ref = db.instance_get_by_ec2_id(context, id_str)
 | 
			
		||||
            host = instance_ref['host']
 | 
			
		||||
            rpc.cast(db.queue_get_for(context, FLAGS.compute_topic, host),
 | 
			
		||||
                     {"method": "reboot_instance",
 | 
			
		||||
                      "args": {"context": None,
 | 
			
		||||
                               "instance_id": instance_ref['id']}})
 | 
			
		||||
            cloud.reboot(id_str, context=context)
 | 
			
		||||
        return True
 | 
			
		||||
 | 
			
		||||
    def update_instance(self, context, instance_id, **kwargs):
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										33
									
								
								nova/api/rackspace/context.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								nova/api/rackspace/context.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,33 @@
 | 
			
		||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
 | 
			
		||||
 | 
			
		||||
# Copyright 2010 OpenStack LLC.
 | 
			
		||||
# 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.
 | 
			
		||||
 | 
			
		||||
"""
 | 
			
		||||
APIRequestContext
 | 
			
		||||
"""
 | 
			
		||||
 | 
			
		||||
import random
 | 
			
		||||
 | 
			
		||||
class Project(object):
 | 
			
		||||
    def __init__(self, user_id):
 | 
			
		||||
        self.id = user_id
 | 
			
		||||
    
 | 
			
		||||
class APIRequestContext(object):
 | 
			
		||||
    """ This is an adapter class to get around all of the assumptions made in
 | 
			
		||||
    the FlatNetworking """
 | 
			
		||||
    def __init__(self, user_id):
 | 
			
		||||
        self.user_id = user_id
 | 
			
		||||
        self.project = Project(user_id)
 | 
			
		||||
@@ -17,35 +17,45 @@
 | 
			
		||||
 | 
			
		||||
import time
 | 
			
		||||
 | 
			
		||||
import webob
 | 
			
		||||
from webob import exc
 | 
			
		||||
 | 
			
		||||
from nova import flags
 | 
			
		||||
from nova import rpc
 | 
			
		||||
from nova import utils
 | 
			
		||||
from nova import wsgi
 | 
			
		||||
from nova.api import cloud
 | 
			
		||||
from nova.api.rackspace import _id_translator
 | 
			
		||||
from nova.api.rackspace import context
 | 
			
		||||
from nova.api.rackspace import faults
 | 
			
		||||
from nova.compute import instance_types
 | 
			
		||||
from nova.compute import power_state
 | 
			
		||||
import nova.api.rackspace
 | 
			
		||||
import nova.image.service
 | 
			
		||||
 | 
			
		||||
FLAGS = flags.FLAGS
 | 
			
		||||
 | 
			
		||||
flags.DEFINE_string('rs_network_manager', 'nova.network.manager.FlatManager',
 | 
			
		||||
    'Networking for rackspace')
 | 
			
		||||
 | 
			
		||||
def _instance_id_translator():
 | 
			
		||||
    """ Helper method for initializing an id translator for Rackspace instance
 | 
			
		||||
    ids """
 | 
			
		||||
    return _id_translator.RackspaceAPIIdTranslator( "instance", 'nova')
 | 
			
		||||
 | 
			
		||||
def translator_instance():
 | 
			
		||||
def _image_service():
 | 
			
		||||
    """ Helper method for initializing the image id translator """
 | 
			
		||||
    service = nova.image.service.ImageService.load()
 | 
			
		||||
    return _id_translator.RackspaceAPIIdTranslator(
 | 
			
		||||
            "image", service.__class__.__name__)
 | 
			
		||||
    return (service, _id_translator.RackspaceAPIIdTranslator(
 | 
			
		||||
            "image", service.__class__.__name__))
 | 
			
		||||
 | 
			
		||||
def _filter_params(inst_dict):
 | 
			
		||||
    """ Extracts all updatable parameters for a server update request """
 | 
			
		||||
    keys = ['name', 'adminPass']
 | 
			
		||||
    keys = dict(name='name', admin_pass='adminPass')
 | 
			
		||||
    new_attrs = {}
 | 
			
		||||
    for k in keys:
 | 
			
		||||
        if inst_dict.has_key(k):
 | 
			
		||||
            new_attrs[k] = inst_dict[k]
 | 
			
		||||
    for k, v in keys.items():
 | 
			
		||||
        if inst_dict.has_key(v):
 | 
			
		||||
            new_attrs[k] = inst_dict[v]
 | 
			
		||||
    return new_attrs
 | 
			
		||||
 | 
			
		||||
def _entity_list(entities):
 | 
			
		||||
@@ -84,7 +94,6 @@ def _entity_inst(inst):
 | 
			
		||||
 | 
			
		||||
class Controller(wsgi.Controller):
 | 
			
		||||
    """ The Server API controller for the Openstack API """
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    _serialization_metadata = {
 | 
			
		||||
        'application/xml': {
 | 
			
		||||
@@ -122,8 +131,11 @@ class Controller(wsgi.Controller):
 | 
			
		||||
 | 
			
		||||
    def show(self, req, id):
 | 
			
		||||
        """ Returns server details by server id """
 | 
			
		||||
        inst_id_trans = _instance_id_translator()
 | 
			
		||||
        inst_id = inst_id_trans.from_rs_id(id)
 | 
			
		||||
 | 
			
		||||
        user_id = req.environ['nova.context']['user']['id']
 | 
			
		||||
        inst = self.db_driver.instance_get(None, id)
 | 
			
		||||
        inst = self.db_driver.instance_get_by_ec2_id(None, inst_id)
 | 
			
		||||
        if inst:
 | 
			
		||||
            if inst.user_id == user_id:
 | 
			
		||||
                return _entity_detail(inst)
 | 
			
		||||
@@ -131,8 +143,11 @@ class Controller(wsgi.Controller):
 | 
			
		||||
 | 
			
		||||
    def delete(self, req, id):
 | 
			
		||||
        """ Destroys a server """
 | 
			
		||||
        inst_id_trans = _instance_id_translator()
 | 
			
		||||
        inst_id = inst_id_trans.from_rs_id(id)
 | 
			
		||||
 | 
			
		||||
        user_id = req.environ['nova.context']['user']['id']
 | 
			
		||||
        instance = self.db_driver.instance_get(None, id)
 | 
			
		||||
        instance = self.db_driver.instance_get_by_ec2_id(None, inst_id)
 | 
			
		||||
        if instance and instance['user_id'] == user_id:
 | 
			
		||||
            self.db_driver.instance_destroy(None, id)
 | 
			
		||||
            return faults.Fault(exc.HTTPAccepted())
 | 
			
		||||
@@ -140,10 +155,15 @@ class Controller(wsgi.Controller):
 | 
			
		||||
 | 
			
		||||
    def create(self, req):
 | 
			
		||||
        """ Creates a new server for a given user """
 | 
			
		||||
        if not req.environ.has_key('inst_dict'):
 | 
			
		||||
 | 
			
		||||
        env = self._deserialize(req.body, req)
 | 
			
		||||
        if not env:
 | 
			
		||||
            return faults.Fault(exc.HTTPUnprocessableEntity())
 | 
			
		||||
 | 
			
		||||
        inst = self._build_server_instance(req)
 | 
			
		||||
        try:
 | 
			
		||||
            inst = self._build_server_instance(req, env)
 | 
			
		||||
        except Exception, e:
 | 
			
		||||
            return faults.Fault(exc.HTTPUnprocessableEntity())
 | 
			
		||||
 | 
			
		||||
        rpc.cast(
 | 
			
		||||
            FLAGS.compute_topic, {
 | 
			
		||||
@@ -153,62 +173,127 @@ class Controller(wsgi.Controller):
 | 
			
		||||
 | 
			
		||||
    def update(self, req, id):
 | 
			
		||||
        """ Updates the server name or password """
 | 
			
		||||
        if not req.environ.has_key('inst_dict'):
 | 
			
		||||
        inst_id_trans = _instance_id_translator()
 | 
			
		||||
        inst_id = inst_id_trans.from_rs_id(id)
 | 
			
		||||
        user_id = req.environ['nova.context']['user']['id']
 | 
			
		||||
 | 
			
		||||
        inst_dict = self._deserialize(req.body, req)
 | 
			
		||||
        
 | 
			
		||||
        if not inst_dict:
 | 
			
		||||
            return faults.Fault(exc.HTTPUnprocessableEntity())
 | 
			
		||||
 | 
			
		||||
        instance = self.db_driver.instance_get(None, id)
 | 
			
		||||
        if not instance:
 | 
			
		||||
        instance = self.db_driver.instance_get_by_ec2_id(None, inst_id)
 | 
			
		||||
        if not instance or instance.user_id != user_id:
 | 
			
		||||
            return faults.Fault(exc.HTTPNotFound())
 | 
			
		||||
 | 
			
		||||
        attrs = req.environ['nova.context'].get('model_attributes', None)
 | 
			
		||||
        if attrs:
 | 
			
		||||
            self.db_driver.instance_update(None, id, _filter_params(attrs))
 | 
			
		||||
        self.db_driver.instance_update(None, id, 
 | 
			
		||||
            _filter_params(inst_dict['server']))
 | 
			
		||||
        return faults.Fault(exc.HTTPNoContent())
 | 
			
		||||
 | 
			
		||||
    def action(self, req, id):
 | 
			
		||||
        """ multi-purpose method used to reboot, rebuild, and 
 | 
			
		||||
        resize a server """
 | 
			
		||||
        if not req.environ.has_key('inst_dict'):
 | 
			
		||||
            return faults.Fault(exc.HTTPUnprocessableEntity())
 | 
			
		||||
        input_dict = self._deserialize(req.body, req)
 | 
			
		||||
        try:
 | 
			
		||||
            reboot_type = input_dict['reboot']['type']
 | 
			
		||||
        except Exception:
 | 
			
		||||
            raise faults.Fault(webob.exc.HTTPNotImplemented())
 | 
			
		||||
        opaque_id = _instance_id_translator().from_rs_id(id)
 | 
			
		||||
        cloud.reboot(opaque_id)
 | 
			
		||||
 | 
			
		||||
    def _build_server_instance(self, req):
 | 
			
		||||
    def _build_server_instance(self, req, env):
 | 
			
		||||
        """Build instance data structure and save it to the data store."""
 | 
			
		||||
        ltime = time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime())
 | 
			
		||||
        inst = {}
 | 
			
		||||
 | 
			
		||||
        env = req.environ['inst_dict']
 | 
			
		||||
 | 
			
		||||
        image_id = env['server']['imageId']
 | 
			
		||||
        opaque_id = translator_instance().from_rs_id(image_id)
 | 
			
		||||
 | 
			
		||||
        inst['name'] = env['server']['server_name']
 | 
			
		||||
        inst['image_id'] = opaque_id
 | 
			
		||||
        inst['instance_type'] = env['server']['flavorId']
 | 
			
		||||
        inst_id_trans = _instance_id_translator()
 | 
			
		||||
 | 
			
		||||
        user_id = req.environ['nova.context']['user']['id']
 | 
			
		||||
        inst['user_id'] = user_id
 | 
			
		||||
 | 
			
		||||
        flavor_id = env['server']['flavorId']
 | 
			
		||||
 | 
			
		||||
        instance_type, flavor = [(k, v) for k, v in
 | 
			
		||||
            instance_types.INSTANCE_TYPES.iteritems()
 | 
			
		||||
            if v['flavorid'] == flavor_id][0]
 | 
			
		||||
 | 
			
		||||
        image_id = env['server']['imageId']
 | 
			
		||||
        
 | 
			
		||||
        img_service, image_id_trans = _image_service()
 | 
			
		||||
 | 
			
		||||
        opaque_image_id = image_id_trans.to_rs_id(image_id)        
 | 
			
		||||
        image = img_service.show(opaque_image_id)
 | 
			
		||||
 | 
			
		||||
        if not image: 
 | 
			
		||||
            raise Exception, "Image not found"
 | 
			
		||||
 | 
			
		||||
        inst['server_name'] = env['server']['name']
 | 
			
		||||
        inst['image_id'] = opaque_image_id
 | 
			
		||||
        inst['user_id'] = user_id
 | 
			
		||||
        inst['launch_time'] = ltime
 | 
			
		||||
        inst['mac_address'] = utils.generate_mac()
 | 
			
		||||
        inst['project_id'] = user_id
 | 
			
		||||
 | 
			
		||||
        inst['project_id'] = env['project']['id']
 | 
			
		||||
        inst['reservation_id'] = reservation
 | 
			
		||||
        reservation = utils.generate_uid('r')
 | 
			
		||||
        inst['state_description'] = 'scheduling'
 | 
			
		||||
        inst['kernel_id'] = image.get('kernelId', FLAGS.default_kernel)
 | 
			
		||||
        inst['ramdisk_id'] = image.get('ramdiskId', FLAGS.default_ramdisk)
 | 
			
		||||
        inst['reservation_id'] = utils.generate_uid('r')
 | 
			
		||||
 | 
			
		||||
        address = self.network.allocate_ip(
 | 
			
		||||
                    inst['user_id'],
 | 
			
		||||
                    inst['project_id'],
 | 
			
		||||
                    mac=inst['mac_address'])
 | 
			
		||||
        inst['display_name'] = env['server']['name']
 | 
			
		||||
        inst['display_description'] = env['server']['name']
 | 
			
		||||
 | 
			
		||||
        inst['private_dns_name'] = str(address)
 | 
			
		||||
        inst['bridge_name'] = network.BridgedNetwork.get_network_for_project(
 | 
			
		||||
                                inst['user_id'],
 | 
			
		||||
                                inst['project_id'],
 | 
			
		||||
                                'default')['bridge_name']
 | 
			
		||||
        #TODO(dietz) this may be ill advised
 | 
			
		||||
        key_pair_ref = self.db_driver.key_pair_get_all_by_user(
 | 
			
		||||
            None, user_id)[0]
 | 
			
		||||
 | 
			
		||||
        inst['key_data'] = key_pair_ref['public_key']
 | 
			
		||||
        inst['key_name'] = key_pair_ref['name']
 | 
			
		||||
 | 
			
		||||
        #TODO(dietz) stolen from ec2 api, see TODO there
 | 
			
		||||
        inst['security_group'] = 'default'
 | 
			
		||||
 | 
			
		||||
        # Flavor related attributes
 | 
			
		||||
        inst['instance_type'] = instance_type
 | 
			
		||||
        inst['memory_mb'] = flavor['memory_mb']
 | 
			
		||||
        inst['vcpus'] = flavor['vcpus']
 | 
			
		||||
        inst['local_gb'] = flavor['local_gb']
 | 
			
		||||
 | 
			
		||||
        ref = self.db_driver.instance_create(None, inst)
 | 
			
		||||
        inst['id'] = ref.id
 | 
			
		||||
        inst['id'] = inst_id_trans.to_rs_id(ref.ec2_id)
 | 
			
		||||
        
 | 
			
		||||
        # TODO(dietz): this isn't explicitly necessary, but the networking
 | 
			
		||||
        # calls depend on an object with a project_id property, and therefore
 | 
			
		||||
        # should be cleaned up later
 | 
			
		||||
        api_context = context.APIRequestContext(user_id)
 | 
			
		||||
    
 | 
			
		||||
        inst['mac_address'] = utils.generate_mac()
 | 
			
		||||
        
 | 
			
		||||
        #TODO(dietz) is this necessary? 
 | 
			
		||||
        inst['launch_index'] = 0
 | 
			
		||||
 | 
			
		||||
        inst['hostname'] = ref.ec2_id
 | 
			
		||||
        self.db_driver.instance_update(None, inst['id'], inst)
 | 
			
		||||
 | 
			
		||||
        network_manager = utils.import_object(FLAGS.rs_network_manager)
 | 
			
		||||
        address = network_manager.allocate_fixed_ip(api_context,
 | 
			
		||||
            inst['id'])
 | 
			
		||||
 | 
			
		||||
        # TODO(vish): This probably should be done in the scheduler
 | 
			
		||||
        #             network is setup when host is assigned
 | 
			
		||||
        network_topic = self._get_network_topic(user_id)
 | 
			
		||||
        rpc.call(network_topic,
 | 
			
		||||
                 {"method": "setup_fixed_ip",
 | 
			
		||||
                  "args": {"context": None,
 | 
			
		||||
                           "address": address}})
 | 
			
		||||
        return inst
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    def _get_network_topic(self, user_id):
 | 
			
		||||
        """Retrieves the network host for a project"""
 | 
			
		||||
        network_ref = self.db_driver.project_get_network(None, 
 | 
			
		||||
            user_id)
 | 
			
		||||
        host = network_ref['host']
 | 
			
		||||
        if not host:
 | 
			
		||||
            host = rpc.call(FLAGS.network_topic,
 | 
			
		||||
                                  {"method": "set_network_host",
 | 
			
		||||
                                   "args": {"context": None,
 | 
			
		||||
                                            "project_id": user_id}})
 | 
			
		||||
        return self.db_driver.queue_get_for(None, FLAGS.network_topic, host)
 | 
			
		||||
 
 | 
			
		||||
@@ -199,6 +199,8 @@ class Instance(BASE, NovaBase):
 | 
			
		||||
    id = Column(Integer, primary_key=True)
 | 
			
		||||
    ec2_id = Column(String(10), unique=True)
 | 
			
		||||
 | 
			
		||||
    admin_pass = Column(String(255))
 | 
			
		||||
 | 
			
		||||
    user_id = Column(String(255))
 | 
			
		||||
    project_id = Column(String(255))
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,12 +1,14 @@
 | 
			
		||||
import datetime
 | 
			
		||||
import unittest
 | 
			
		||||
 | 
			
		||||
import stubout
 | 
			
		||||
import webob
 | 
			
		||||
import webob.dec
 | 
			
		||||
import unittest
 | 
			
		||||
import stubout
 | 
			
		||||
 | 
			
		||||
import nova.api
 | 
			
		||||
import nova.api.rackspace.auth
 | 
			
		||||
from nova import auth
 | 
			
		||||
from nova.tests.api.rackspace import test_helper
 | 
			
		||||
import datetime
 | 
			
		||||
 | 
			
		||||
class Test(unittest.TestCase):
 | 
			
		||||
    def setUp(self):
 | 
			
		||||
 
 | 
			
		||||
@@ -38,7 +38,6 @@ class FlavorsTest(unittest.TestCase):
 | 
			
		||||
    def test_get_flavor_list(self):
 | 
			
		||||
        req = webob.Request.blank('/v1.0/flavors')
 | 
			
		||||
        res = req.get_response(nova.api.API())
 | 
			
		||||
        print res
 | 
			
		||||
 | 
			
		||||
    def test_get_flavor_by_id(self):
 | 
			
		||||
        pass
 | 
			
		||||
 
 | 
			
		||||
@@ -15,6 +15,7 @@
 | 
			
		||||
#    License for the specific language governing permissions and limitations
 | 
			
		||||
#    under the License.
 | 
			
		||||
 | 
			
		||||
import stubout
 | 
			
		||||
import unittest
 | 
			
		||||
 | 
			
		||||
from nova.api.rackspace import images
 | 
			
		||||
 
 | 
			
		||||
@@ -26,6 +26,7 @@ import nova.api.rackspace
 | 
			
		||||
from nova.api.rackspace import servers
 | 
			
		||||
import nova.db.api
 | 
			
		||||
from nova.db.sqlalchemy.models import Instance
 | 
			
		||||
import nova.rpc
 | 
			
		||||
from nova.tests.api.test_helper import *
 | 
			
		||||
from nova.tests.api.rackspace import test_helper
 | 
			
		||||
 | 
			
		||||
@@ -52,8 +53,11 @@ class ServersTest(unittest.TestCase):
 | 
			
		||||
        test_helper.stub_for_testing(self.stubs)
 | 
			
		||||
        test_helper.stub_out_rate_limiting(self.stubs)
 | 
			
		||||
        test_helper.stub_out_auth(self.stubs)
 | 
			
		||||
        test_helper.stub_out_id_translator(self.stubs)
 | 
			
		||||
        test_helper.stub_out_key_pair_funcs(self.stubs)
 | 
			
		||||
        test_helper.stub_out_image_service(self.stubs)
 | 
			
		||||
        self.stubs.Set(nova.db.api, 'instance_get_all', return_servers)
 | 
			
		||||
        self.stubs.Set(nova.db.api, 'instance_get', return_server)
 | 
			
		||||
        self.stubs.Set(nova.db.api, 'instance_get_by_ec2_id', return_server)
 | 
			
		||||
        self.stubs.Set(nova.db.api, 'instance_get_all_by_user', 
 | 
			
		||||
            return_servers)
 | 
			
		||||
 | 
			
		||||
@@ -67,9 +71,6 @@ class ServersTest(unittest.TestCase):
 | 
			
		||||
        self.assertEqual(res_dict['server']['id'], '1')
 | 
			
		||||
        self.assertEqual(res_dict['server']['name'], 'server1')
 | 
			
		||||
 | 
			
		||||
    def test_get_backup_schedule(self):
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
    def test_get_server_list(self):
 | 
			
		||||
        req = webob.Request.blank('/v1.0/servers')
 | 
			
		||||
        res = req.get_response(nova.api.API())
 | 
			
		||||
@@ -82,24 +83,86 @@ class ServersTest(unittest.TestCase):
 | 
			
		||||
            self.assertEqual(s.get('imageId', None), None)
 | 
			
		||||
            i += 1
 | 
			
		||||
 | 
			
		||||
    #def test_create_instance(self):
 | 
			
		||||
    #    test_helper.stub_out_image_translator(self.stubs)
 | 
			
		||||
    #    body = dict(server=dict(
 | 
			
		||||
    #        name='server_test', imageId=2, flavorId=2, metadata={},
 | 
			
		||||
    #        personality = {}
 | 
			
		||||
    #    ))
 | 
			
		||||
    #    req = webob.Request.blank('/v1.0/servers')
 | 
			
		||||
    #    req.method = 'POST'
 | 
			
		||||
    #    req.body = json.dumps(body)
 | 
			
		||||
    def test_create_instance(self):
 | 
			
		||||
        def server_update(context, id, params):
 | 
			
		||||
            pass 
 | 
			
		||||
 | 
			
		||||
    #    res = req.get_response(nova.api.API())
 | 
			
		||||
        def instance_create(context, inst):
 | 
			
		||||
            class Foo(object):
 | 
			
		||||
                ec2_id = 1
 | 
			
		||||
            return Foo()
 | 
			
		||||
 | 
			
		||||
    #    print res
 | 
			
		||||
    def test_update_server_password(self):
 | 
			
		||||
        pass
 | 
			
		||||
        def fake_method(*args, **kwargs):
 | 
			
		||||
            pass
 | 
			
		||||
        
 | 
			
		||||
        def project_get_network(context, user_id):
 | 
			
		||||
            return dict(id='1', host='localhost') 
 | 
			
		||||
 | 
			
		||||
    def test_update_server_name(self):
 | 
			
		||||
        pass
 | 
			
		||||
        def queue_get_for(context, *args):
 | 
			
		||||
            return 'network_topic'
 | 
			
		||||
 | 
			
		||||
        self.stubs.Set(nova.db.api, 'project_get_network', project_get_network)
 | 
			
		||||
        self.stubs.Set(nova.db.api, 'instance_create', instance_create)
 | 
			
		||||
        self.stubs.Set(nova.rpc, 'cast', fake_method)
 | 
			
		||||
        self.stubs.Set(nova.rpc, 'call', fake_method)
 | 
			
		||||
        self.stubs.Set(nova.db.api, 'instance_update',
 | 
			
		||||
            server_update)
 | 
			
		||||
        self.stubs.Set(nova.db.api, 'queue_get_for', queue_get_for)
 | 
			
		||||
        self.stubs.Set(nova.network.manager.FlatManager, 'allocate_fixed_ip',
 | 
			
		||||
            fake_method)
 | 
			
		||||
            
 | 
			
		||||
        test_helper.stub_out_id_translator(self.stubs)
 | 
			
		||||
        body = dict(server=dict(
 | 
			
		||||
            name='server_test', imageId=2, flavorId=2, metadata={},
 | 
			
		||||
            personality = {}
 | 
			
		||||
        ))
 | 
			
		||||
        req = webob.Request.blank('/v1.0/servers')
 | 
			
		||||
        req.method = 'POST'
 | 
			
		||||
        req.body = json.dumps(body)
 | 
			
		||||
 | 
			
		||||
        res = req.get_response(nova.api.API())
 | 
			
		||||
 | 
			
		||||
        self.assertEqual(res.status_int, 200)
 | 
			
		||||
 | 
			
		||||
    def test_update_no_body(self):
 | 
			
		||||
        req = webob.Request.blank('/v1.0/servers/1')
 | 
			
		||||
        req.method = 'PUT'
 | 
			
		||||
        res = req.get_response(nova.api.API())
 | 
			
		||||
        self.assertEqual(res.status_int, 422)
 | 
			
		||||
 | 
			
		||||
    def test_update_bad_params(self):
 | 
			
		||||
        """ Confirm that update is filtering params """
 | 
			
		||||
        inst_dict = dict(cat='leopard', name='server_test', adminPass='bacon')
 | 
			
		||||
        self.body = json.dumps(dict(server=inst_dict))
 | 
			
		||||
 | 
			
		||||
        def server_update(context, id, params):
 | 
			
		||||
            self.update_called = True
 | 
			
		||||
            filtered_dict = dict(name='server_test', admin_pass='bacon')
 | 
			
		||||
            self.assertEqual(params, filtered_dict)
 | 
			
		||||
 | 
			
		||||
        self.stubs.Set(nova.db.api, 'instance_update',
 | 
			
		||||
            server_update)
 | 
			
		||||
 | 
			
		||||
        req = webob.Request.blank('/v1.0/servers/1')
 | 
			
		||||
        req.method = 'PUT'
 | 
			
		||||
        req.body = self.body
 | 
			
		||||
        req.get_response(nova.api.API())
 | 
			
		||||
 | 
			
		||||
    def test_update_server(self):
 | 
			
		||||
        inst_dict = dict(name='server_test', adminPass='bacon')
 | 
			
		||||
        self.body = json.dumps(dict(server=inst_dict))
 | 
			
		||||
 | 
			
		||||
        def server_update(context, id, params):
 | 
			
		||||
            filtered_dict = dict(name='server_test', admin_pass='bacon')
 | 
			
		||||
            self.assertEqual(params, filtered_dict)
 | 
			
		||||
 | 
			
		||||
        self.stubs.Set(nova.db.api, 'instance_update',
 | 
			
		||||
            server_update)
 | 
			
		||||
 | 
			
		||||
        req = webob.Request.blank('/v1.0/servers/1')
 | 
			
		||||
        req.method = 'PUT'
 | 
			
		||||
        req.body = self.body
 | 
			
		||||
        req.get_response(nova.api.API())
 | 
			
		||||
 | 
			
		||||
    def test_create_backup_schedules(self):
 | 
			
		||||
        req = webob.Request.blank('/v1.0/servers/1/backup_schedules')
 | 
			
		||||
 
 | 
			
		||||
@@ -15,6 +15,7 @@
 | 
			
		||||
#    License for the specific language governing permissions and limitations
 | 
			
		||||
#    under the License.
 | 
			
		||||
 | 
			
		||||
import stubout
 | 
			
		||||
import unittest
 | 
			
		||||
 | 
			
		||||
from nova.api.rackspace import sharedipgroups
 | 
			
		||||
 
 | 
			
		||||
@@ -9,6 +9,7 @@ from nova import utils
 | 
			
		||||
from nova import flags
 | 
			
		||||
import nova.api.rackspace.auth
 | 
			
		||||
import nova.api.rackspace._id_translator
 | 
			
		||||
from nova.image import service
 | 
			
		||||
from nova.wsgi import Router
 | 
			
		||||
 | 
			
		||||
FLAGS = flags.FLAGS
 | 
			
		||||
@@ -40,7 +41,19 @@ def fake_wsgi(self, req):
 | 
			
		||||
        req.environ['inst_dict'] = json.loads(req.body)
 | 
			
		||||
    return self.application
 | 
			
		||||
 | 
			
		||||
def stub_out_image_translator(stubs):
 | 
			
		||||
def stub_out_key_pair_funcs(stubs):
 | 
			
		||||
    def key_pair(context, user_id):
 | 
			
		||||
        return [dict(name='key', public_key='public_key')]
 | 
			
		||||
    stubs.Set(nova.db.api, 'key_pair_get_all_by_user',
 | 
			
		||||
        key_pair)
 | 
			
		||||
 | 
			
		||||
def stub_out_image_service(stubs):
 | 
			
		||||
    def fake_image_show(meh, id):
 | 
			
		||||
        return dict(kernelId=1, ramdiskId=1)
 | 
			
		||||
 | 
			
		||||
    stubs.Set(nova.image.service.LocalImageService, 'show', fake_image_show)
 | 
			
		||||
 | 
			
		||||
def stub_out_id_translator(stubs):
 | 
			
		||||
    class FakeTranslator(object):
 | 
			
		||||
        def __init__(self, id_type, service_name):
 | 
			
		||||
            pass
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										20
									
								
								nova/wsgi.py
									
									
									
									
									
								
							
							
						
						
									
										20
									
								
								nova/wsgi.py
									
									
									
									
									
								
							@@ -230,6 +230,15 @@ class Controller(object):
 | 
			
		||||
        serializer = Serializer(request.environ, _metadata)
 | 
			
		||||
        return serializer.to_content_type(data)
 | 
			
		||||
 | 
			
		||||
    def _deserialize(self, data, request):
 | 
			
		||||
        """
 | 
			
		||||
        Deserialize the request body to the response type requested in request.
 | 
			
		||||
        Uses self._serialization_metadata if it exists, which is a dict mapping
 | 
			
		||||
        MIME types to information needed to serialize to that type.
 | 
			
		||||
        """
 | 
			
		||||
        _metadata = getattr(type(self), "_serialization_metadata", {})
 | 
			
		||||
        serializer = Serializer(request.environ, _metadata)
 | 
			
		||||
        return serializer.deserialize(data)
 | 
			
		||||
 | 
			
		||||
class Serializer(object):
 | 
			
		||||
    """
 | 
			
		||||
@@ -272,10 +281,13 @@ class Serializer(object):
 | 
			
		||||
        The string must be in the format of a supported MIME type.
 | 
			
		||||
        """
 | 
			
		||||
        datastring = datastring.strip()
 | 
			
		||||
        is_xml = (datastring[0] == '<')
 | 
			
		||||
        if not is_xml:
 | 
			
		||||
            return json.loads(datastring)
 | 
			
		||||
        return self._from_xml(datastring)
 | 
			
		||||
        try:
 | 
			
		||||
            is_xml = (datastring[0] == '<')
 | 
			
		||||
            if not is_xml:
 | 
			
		||||
                return json.loads(datastring)
 | 
			
		||||
            return self._from_xml(datastring)
 | 
			
		||||
        except:
 | 
			
		||||
            return None
 | 
			
		||||
 | 
			
		||||
    def _from_xml(self, datastring):
 | 
			
		||||
        xmldata = self.metadata.get('application/xml', {})
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user