Merge with trunk
This commit is contained in:
commit
674acd025b
3
.mailmap
3
.mailmap
@ -29,6 +29,7 @@
|
||||
<matt.dietz@rackspace.com> <matthewdietz@Matthew-Dietzs-MacBook-Pro.local>
|
||||
<matt.dietz@rackspace.com> <mdietz@openstack>
|
||||
<mordred@inaugust.com> <mordred@hudson>
|
||||
<naveedm9@gmail.com> <naveed.massjouni@rackspace.com>
|
||||
<nirmal.ranganathan@rackspace.com> <nirmal.ranganathan@rackspace.coom>
|
||||
<paul@openstack.org> <paul.voccio@rackspace.com>
|
||||
<paul@openstack.org> <pvoccio@castor.local>
|
||||
@ -36,6 +37,7 @@
|
||||
<rlane@wikimedia.org> <laner@controller>
|
||||
<sleepsonthefloor@gmail.com> <root@tonbuntu>
|
||||
<soren.hansen@rackspace.com> <soren@linux2go.dk>
|
||||
<throughnothing@gmail.com> <will.wolf@rackspace.com>
|
||||
<todd@ansolabs.com> <todd@lapex>
|
||||
<todd@ansolabs.com> <todd@rubidine.com>
|
||||
<tushar.vitthal.patil@gmail.com> <tpatil@vertex.co.in>
|
||||
@ -44,5 +46,4 @@
|
||||
<ueno.nachi@lab.ntt.co.jp> <openstack@lab.ntt.co.jp>
|
||||
<vishvananda@gmail.com> <root@mirror.nasanebula.net>
|
||||
<vishvananda@gmail.com> <root@ubuntu>
|
||||
<naveedm9@gmail.com> <naveed.massjouni@rackspace.com>
|
||||
<vishvananda@gmail.com> <vishvananda@yahoo.com>
|
||||
|
2
Authors
2
Authors
@ -80,7 +80,7 @@ Trey Morris <trey.morris@rackspace.com>
|
||||
Tushar Patil <tushar.vitthal.patil@gmail.com>
|
||||
Vasiliy Shlykov <vash@vasiliyshlykov.org>
|
||||
Vishvananda Ishaya <vishvananda@gmail.com>
|
||||
William Wolf <will.wolf@rackspace.com>
|
||||
William Wolf <throughnothing@gmail.com>
|
||||
Yoshiaki Tamura <yoshi@midokura.jp>
|
||||
Youcef Laribi <Youcef.Laribi@eu.citrix.com>
|
||||
Yuriy Taraday <yorik.sar@gmail.com>
|
||||
|
@ -19,6 +19,7 @@
|
||||
"""Handles all requests relating to instances (guest vms)."""
|
||||
|
||||
import datetime
|
||||
import eventlet
|
||||
import re
|
||||
import time
|
||||
|
||||
@ -42,6 +43,8 @@ LOG = logging.getLogger('nova.compute.api')
|
||||
|
||||
FLAGS = flags.FLAGS
|
||||
flags.DECLARE('vncproxy_topic', 'nova.vnc')
|
||||
flags.DEFINE_integer('find_host_timeout', 30,
|
||||
'Timeout after NN seconds when looking for a host.')
|
||||
|
||||
|
||||
def generate_default_hostname(instance_id):
|
||||
@ -484,7 +487,7 @@ class API(base.Base):
|
||||
|
||||
def _find_host(self, context, instance_id):
|
||||
"""Find the host associated with an instance."""
|
||||
for attempts in xrange(10):
|
||||
for attempts in xrange(FLAGS.find_host_timeout):
|
||||
instance = self.get(context, instance_id)
|
||||
host = instance["host"]
|
||||
if host:
|
||||
@ -493,6 +496,15 @@ class API(base.Base):
|
||||
raise exception.Error(_("Unable to find host for Instance %s")
|
||||
% instance_id)
|
||||
|
||||
def _set_admin_password(self, context, instance_id, password):
|
||||
"""Set the root/admin password for the given instance."""
|
||||
host = self._find_host(context, instance_id)
|
||||
|
||||
rpc.cast(context,
|
||||
self.db.queue_get_for(context, FLAGS.compute_topic, host),
|
||||
{"method": "set_admin_password",
|
||||
"args": {"instance_id": instance_id, "new_pass": password}})
|
||||
|
||||
def snapshot(self, context, instance_id, name):
|
||||
"""Snapshot the given instance.
|
||||
|
||||
@ -646,12 +658,8 @@ class API(base.Base):
|
||||
|
||||
def set_admin_password(self, context, instance_id, password=None):
|
||||
"""Set the root/admin password for the given instance."""
|
||||
host = self._find_host(context, instance_id)
|
||||
|
||||
rpc.cast(context,
|
||||
self.db.queue_get_for(context, FLAGS.compute_topic, host),
|
||||
{"method": "set_admin_password",
|
||||
"args": {"instance_id": instance_id, "new_pass": password}})
|
||||
eventlet.spawn_n(self._set_admin_password(context, instance_id,
|
||||
password))
|
||||
|
||||
def inject_file(self, context, instance_id):
|
||||
"""Write a file to the given instance."""
|
||||
|
@ -77,7 +77,8 @@ flags.DEFINE_integer("rescue_timeout", 0,
|
||||
" Set to 0 to disable.")
|
||||
flags.DEFINE_bool('auto_assign_floating_ip', False,
|
||||
'Autoassigning floating ip to VM')
|
||||
|
||||
flags.DEFINE_integer('host_state_interval', 120,
|
||||
'Interval in seconds for querying the host status')
|
||||
|
||||
LOG = logging.getLogger('nova.compute.manager')
|
||||
|
||||
@ -426,6 +427,12 @@ class ComputeManager(manager.SchedulerDependentManager):
|
||||
LOG.audit(_("Instance %s: Root password set"),
|
||||
instance_ref["name"])
|
||||
break
|
||||
except NotImplementedError:
|
||||
# NOTE(dprince): if the driver doesn't implement
|
||||
# set_admin_password we break to avoid a loop
|
||||
LOG.warn(_('set_admin_password is not implemented '
|
||||
'by this driver.'))
|
||||
break
|
||||
except Exception, e:
|
||||
# Catch all here because this could be anything.
|
||||
LOG.exception(e)
|
||||
|
@ -183,7 +183,7 @@ class ServersTest(test.TestCase):
|
||||
self.assertEqual(res_dict['server']['id'], 1)
|
||||
self.assertEqual(res_dict['server']['name'], 'server1')
|
||||
|
||||
def test_get_server_by_id_v11(self):
|
||||
def test_get_server_by_id_v1_1(self):
|
||||
req = webob.Request.blank('/v1.1/servers/1')
|
||||
res = req.get_response(fakes.wsgi_app())
|
||||
res_dict = json.loads(res.body)
|
||||
@ -246,7 +246,7 @@ class ServersTest(test.TestCase):
|
||||
self.assertEqual(len(addresses["private"]), 1)
|
||||
self.assertEqual(addresses["private"][0], private)
|
||||
|
||||
def test_get_server_addresses_V10(self):
|
||||
def test_get_server_addresses_v1_0(self):
|
||||
private = '192.168.0.3'
|
||||
public = ['1.2.3.4']
|
||||
new_return_server = return_server_with_addresses(private, public)
|
||||
@ -257,7 +257,7 @@ class ServersTest(test.TestCase):
|
||||
self.assertEqual(res_dict, {
|
||||
'addresses': {'public': public, 'private': [private]}})
|
||||
|
||||
def test_get_server_addresses_xml_V10(self):
|
||||
def test_get_server_addresses_xml_v1_0(self):
|
||||
private_expected = "192.168.0.3"
|
||||
public_expected = ["1.2.3.4"]
|
||||
new_return_server = return_server_with_addresses(private_expected,
|
||||
@ -276,7 +276,7 @@ class ServersTest(test.TestCase):
|
||||
(ip,) = private.getElementsByTagName('ip')
|
||||
self.assertEquals(ip.getAttribute('addr'), private_expected)
|
||||
|
||||
def test_get_server_addresses_public_V10(self):
|
||||
def test_get_server_addresses_public_v1_0(self):
|
||||
private = "192.168.0.3"
|
||||
public = ["1.2.3.4"]
|
||||
new_return_server = return_server_with_addresses(private, public)
|
||||
@ -286,7 +286,7 @@ class ServersTest(test.TestCase):
|
||||
res_dict = json.loads(res.body)
|
||||
self.assertEqual(res_dict, {'public': public})
|
||||
|
||||
def test_get_server_addresses_private_V10(self):
|
||||
def test_get_server_addresses_private_v1_0(self):
|
||||
private = "192.168.0.3"
|
||||
public = ["1.2.3.4"]
|
||||
new_return_server = return_server_with_addresses(private, public)
|
||||
@ -296,7 +296,7 @@ class ServersTest(test.TestCase):
|
||||
res_dict = json.loads(res.body)
|
||||
self.assertEqual(res_dict, {'private': [private]})
|
||||
|
||||
def test_get_server_addresses_public_xml_V10(self):
|
||||
def test_get_server_addresses_public_xml_v1_0(self):
|
||||
private = "192.168.0.3"
|
||||
public = ["1.2.3.4"]
|
||||
new_return_server = return_server_with_addresses(private, public)
|
||||
@ -310,7 +310,7 @@ class ServersTest(test.TestCase):
|
||||
(ip,) = public_node.getElementsByTagName('ip')
|
||||
self.assertEquals(ip.getAttribute('addr'), public[0])
|
||||
|
||||
def test_get_server_addresses_private_xml_V10(self):
|
||||
def test_get_server_addresses_private_xml_v1_0(self):
|
||||
private = "192.168.0.3"
|
||||
public = ["1.2.3.4"]
|
||||
new_return_server = return_server_with_addresses(private, public)
|
||||
@ -324,7 +324,7 @@ class ServersTest(test.TestCase):
|
||||
(ip,) = private_node.getElementsByTagName('ip')
|
||||
self.assertEquals(ip.getAttribute('addr'), private)
|
||||
|
||||
def test_get_server_by_id_with_addresses_v11(self):
|
||||
def test_get_server_by_id_with_addresses_v1_1(self):
|
||||
private = "192.168.0.3"
|
||||
public = ["1.2.3.4"]
|
||||
new_return_server = return_server_with_addresses(private, public)
|
||||
@ -354,7 +354,7 @@ class ServersTest(test.TestCase):
|
||||
self.assertEqual(s.get('imageId', None), None)
|
||||
i += 1
|
||||
|
||||
def test_get_server_list_v11(self):
|
||||
def test_get_server_list_v1_1(self):
|
||||
req = webob.Request.blank('/v1.1/servers')
|
||||
res = req.get_response(fakes.wsgi_app())
|
||||
res_dict = json.loads(res.body)
|
||||
@ -576,16 +576,16 @@ class ServersTest(test.TestCase):
|
||||
res = req.get_response(fakes.wsgi_app())
|
||||
self.assertEqual(res.status_int, 400)
|
||||
|
||||
def test_create_instance_v11(self):
|
||||
def test_create_instance_v1_1(self):
|
||||
self._setup_for_create_instance()
|
||||
|
||||
imageRef = 'http://localhost/v1.1/images/2'
|
||||
flavorRef = 'http://localhost/v1.1/flavors/3'
|
||||
image_ref = 'http://localhost/v1.1/images/2'
|
||||
flavor_ref = 'http://localhost/v1.1/flavors/3'
|
||||
body = {
|
||||
'server': {
|
||||
'name': 'server_test',
|
||||
'imageRef': imageRef,
|
||||
'flavorRef': flavorRef,
|
||||
'imageRef': image_ref,
|
||||
'flavorRef': flavor_ref,
|
||||
'metadata': {
|
||||
'hello': 'world',
|
||||
'open': 'stack',
|
||||
@ -605,17 +605,17 @@ class ServersTest(test.TestCase):
|
||||
self.assertEqual(16, len(server['adminPass']))
|
||||
self.assertEqual('server_test', server['name'])
|
||||
self.assertEqual(1, server['id'])
|
||||
self.assertEqual(flavorRef, server['flavorRef'])
|
||||
self.assertEqual(imageRef, server['imageRef'])
|
||||
self.assertEqual(flavor_ref, server['flavorRef'])
|
||||
self.assertEqual(image_ref, server['imageRef'])
|
||||
self.assertEqual(res.status_int, 200)
|
||||
|
||||
def test_create_instance_v11_bad_href(self):
|
||||
def test_create_instance_v1_1_bad_href(self):
|
||||
self._setup_for_create_instance()
|
||||
|
||||
imageRef = 'http://localhost/v1.1/images/asdf'
|
||||
flavorRef = 'http://localhost/v1.1/flavors/3'
|
||||
image_ref = 'http://localhost/v1.1/images/asdf'
|
||||
flavor_ref = 'http://localhost/v1.1/flavors/3'
|
||||
body = dict(server=dict(
|
||||
name='server_test', imageRef=imageRef, flavorRef=flavorRef,
|
||||
name='server_test', imageRef=image_ref, flavorRef=flavor_ref,
|
||||
metadata={'hello': 'world', 'open': 'stack'},
|
||||
personality={}))
|
||||
req = webob.Request.blank('/v1.1/servers')
|
||||
@ -625,17 +625,17 @@ class ServersTest(test.TestCase):
|
||||
res = req.get_response(fakes.wsgi_app())
|
||||
self.assertEqual(res.status_int, 400)
|
||||
|
||||
def test_create_instance_v11_local_href(self):
|
||||
def test_create_instance_v1_1_local_href(self):
|
||||
self._setup_for_create_instance()
|
||||
|
||||
imageRef = 'http://localhost/v1.1/images/2'
|
||||
imageRefLocal = '2'
|
||||
flavorRef = 'http://localhost/v1.1/flavors/3'
|
||||
image_ref = 'http://localhost/v1.1/images/2'
|
||||
image_ref_local = '2'
|
||||
flavor_ref = 'http://localhost/v1.1/flavors/3'
|
||||
body = {
|
||||
'server': {
|
||||
'name': 'server_test',
|
||||
'imageRef': imageRefLocal,
|
||||
'flavorRef': flavorRef,
|
||||
'imageRef': image_ref_local,
|
||||
'flavorRef': flavor_ref,
|
||||
},
|
||||
}
|
||||
|
||||
@ -648,11 +648,11 @@ class ServersTest(test.TestCase):
|
||||
|
||||
server = json.loads(res.body)['server']
|
||||
self.assertEqual(1, server['id'])
|
||||
self.assertEqual(flavorRef, server['flavorRef'])
|
||||
self.assertEqual(imageRef, server['imageRef'])
|
||||
self.assertEqual(flavor_ref, server['flavorRef'])
|
||||
self.assertEqual(image_ref, server['imageRef'])
|
||||
self.assertEqual(res.status_int, 200)
|
||||
|
||||
def test_create_instance_with_admin_pass_v10(self):
|
||||
def test_create_instance_with_admin_pass_v1_0(self):
|
||||
self._setup_for_create_instance()
|
||||
|
||||
body = {
|
||||
@ -673,16 +673,16 @@ class ServersTest(test.TestCase):
|
||||
self.assertNotEqual(res['server']['adminPass'],
|
||||
body['server']['adminPass'])
|
||||
|
||||
def test_create_instance_with_admin_pass_v11(self):
|
||||
def test_create_instance_with_admin_pass_v1_1(self):
|
||||
self._setup_for_create_instance()
|
||||
|
||||
imageRef = 'http://localhost/v1.1/images/2'
|
||||
flavorRef = 'http://localhost/v1.1/flavors/3'
|
||||
image_ref = 'http://localhost/v1.1/images/2'
|
||||
flavor_ref = 'http://localhost/v1.1/flavors/3'
|
||||
body = {
|
||||
'server': {
|
||||
'name': 'server_test',
|
||||
'imageRef': imageRef,
|
||||
'flavorRef': flavorRef,
|
||||
'imageRef': image_ref,
|
||||
'flavorRef': flavor_ref,
|
||||
'adminPass': 'testpass',
|
||||
},
|
||||
}
|
||||
@ -695,16 +695,16 @@ class ServersTest(test.TestCase):
|
||||
server = json.loads(res.body)['server']
|
||||
self.assertEqual(server['adminPass'], body['server']['adminPass'])
|
||||
|
||||
def test_create_instance_with_empty_admin_pass_v11(self):
|
||||
def test_create_instance_with_empty_admin_pass_v1_1(self):
|
||||
self._setup_for_create_instance()
|
||||
|
||||
imageRef = 'http://localhost/v1.1/images/2'
|
||||
flavorRef = 'http://localhost/v1.1/flavors/3'
|
||||
image_ref = 'http://localhost/v1.1/images/2'
|
||||
flavor_ref = 'http://localhost/v1.1/flavors/3'
|
||||
body = {
|
||||
'server': {
|
||||
'name': 'server_test',
|
||||
'imageRef': imageRef,
|
||||
'flavorRef': flavorRef,
|
||||
'imageRef': image_ref,
|
||||
'flavorRef': flavor_ref,
|
||||
'adminPass': '',
|
||||
},
|
||||
}
|
||||
@ -758,7 +758,7 @@ class ServersTest(test.TestCase):
|
||||
res = req.get_response(fakes.wsgi_app())
|
||||
self.assertEqual(res.status_int, 400)
|
||||
|
||||
def test_update_server_v10(self):
|
||||
def test_update_server_v1_0(self):
|
||||
inst_dict = dict(name='server_test', adminPass='bacon')
|
||||
self.body = json.dumps(dict(server=inst_dict))
|
||||
|
||||
@ -781,7 +781,7 @@ class ServersTest(test.TestCase):
|
||||
res = req.get_response(fakes.wsgi_app())
|
||||
self.assertEqual(res.status_int, 204)
|
||||
|
||||
def test_update_server_adminPass_ignored_v11(self):
|
||||
def test_update_server_adminPass_ignored_v1_1(self):
|
||||
inst_dict = dict(name='server_test', adminPass='bacon')
|
||||
self.body = json.dumps(dict(server=inst_dict))
|
||||
|
||||
@ -822,7 +822,7 @@ class ServersTest(test.TestCase):
|
||||
res = req.get_response(fakes.wsgi_app())
|
||||
self.assertEqual(res.status_int, 501)
|
||||
|
||||
def test_server_backup_schedule_deprecated_v11(self):
|
||||
def test_server_backup_schedule_deprecated_v1_1(self):
|
||||
req = webob.Request.blank('/v1.1/servers/1/backup_schedule')
|
||||
res = req.get_response(fakes.wsgi_app())
|
||||
self.assertEqual(res.status_int, 404)
|
||||
@ -1113,7 +1113,7 @@ class ServersTest(test.TestCase):
|
||||
res = req.get_response(fakes.wsgi_app())
|
||||
self.assertEqual(res.status_int, 400)
|
||||
|
||||
def test_server_rebuild_accepted_minimum_v11(self):
|
||||
def test_server_rebuild_accepted_minimum_v1_1(self):
|
||||
body = {
|
||||
"rebuild": {
|
||||
"imageRef": "http://localhost/images/2",
|
||||
@ -1128,7 +1128,7 @@ class ServersTest(test.TestCase):
|
||||
res = req.get_response(fakes.wsgi_app())
|
||||
self.assertEqual(res.status_int, 202)
|
||||
|
||||
def test_server_rebuild_rejected_when_building_v11(self):
|
||||
def test_server_rebuild_rejected_when_building_v1_1(self):
|
||||
body = {
|
||||
"rebuild": {
|
||||
"imageRef": "http://localhost/images/2",
|
||||
@ -1147,7 +1147,7 @@ class ServersTest(test.TestCase):
|
||||
res = req.get_response(fakes.wsgi_app())
|
||||
self.assertEqual(res.status_int, 409)
|
||||
|
||||
def test_server_rebuild_accepted_with_metadata_v11(self):
|
||||
def test_server_rebuild_accepted_with_metadata_v1_1(self):
|
||||
body = {
|
||||
"rebuild": {
|
||||
"imageRef": "http://localhost/images/2",
|
||||
@ -1165,7 +1165,7 @@ class ServersTest(test.TestCase):
|
||||
res = req.get_response(fakes.wsgi_app())
|
||||
self.assertEqual(res.status_int, 202)
|
||||
|
||||
def test_server_rebuild_accepted_with_bad_metadata_v11(self):
|
||||
def test_server_rebuild_accepted_with_bad_metadata_v1_1(self):
|
||||
body = {
|
||||
"rebuild": {
|
||||
"imageRef": "http://localhost/images/2",
|
||||
@ -1181,7 +1181,7 @@ class ServersTest(test.TestCase):
|
||||
res = req.get_response(fakes.wsgi_app())
|
||||
self.assertEqual(res.status_int, 400)
|
||||
|
||||
def test_server_rebuild_bad_entity_v11(self):
|
||||
def test_server_rebuild_bad_entity_v1_1(self):
|
||||
body = {
|
||||
"rebuild": {
|
||||
"imageId": 2,
|
||||
@ -1196,7 +1196,7 @@ class ServersTest(test.TestCase):
|
||||
res = req.get_response(fakes.wsgi_app())
|
||||
self.assertEqual(res.status_int, 400)
|
||||
|
||||
def test_server_rebuild_bad_personality_v11(self):
|
||||
def test_server_rebuild_bad_personality_v1_1(self):
|
||||
body = {
|
||||
"rebuild": {
|
||||
"imageRef": "http://localhost/images/2",
|
||||
@ -1215,7 +1215,7 @@ class ServersTest(test.TestCase):
|
||||
res = req.get_response(fakes.wsgi_app())
|
||||
self.assertEqual(res.status_int, 400)
|
||||
|
||||
def test_server_rebuild_personality_v11(self):
|
||||
def test_server_rebuild_personality_v1_1(self):
|
||||
body = {
|
||||
"rebuild": {
|
||||
"imageRef": "http://localhost/images/2",
|
||||
|
@ -279,6 +279,26 @@ class CloudTestCase(test.TestCase):
|
||||
user_group=['all'])
|
||||
self.assertEqual(True, result['is_public'])
|
||||
|
||||
def test_deregister_image(self):
|
||||
deregister_image = self.cloud.deregister_image
|
||||
|
||||
def fake_delete(self, context, id):
|
||||
return None
|
||||
|
||||
self.stubs.Set(local.LocalImageService, 'delete', fake_delete)
|
||||
# valid image
|
||||
result = deregister_image(self.context, 'ami-00000001')
|
||||
self.assertEqual(result['imageId'], 'ami-00000001')
|
||||
# invalid image
|
||||
self.stubs.UnsetAll()
|
||||
|
||||
def fake_detail_empty(self, context):
|
||||
return []
|
||||
|
||||
self.stubs.Set(local.LocalImageService, 'detail', fake_detail_empty)
|
||||
self.assertRaises(exception.ImageNotFound, deregister_image,
|
||||
self.context, 'ami-bad001')
|
||||
|
||||
def test_console_output(self):
|
||||
instance_type = FLAGS.default_instance_type
|
||||
max_count = 1
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
"""Test suite for XenAPI."""
|
||||
|
||||
import eventlet
|
||||
import functools
|
||||
import json
|
||||
import os
|
||||
@ -198,6 +199,28 @@ class XenAPIVMTestCase(test.TestCase):
|
||||
self.context = context.RequestContext('fake', 'fake', False)
|
||||
self.conn = xenapi_conn.get_connection(False)
|
||||
|
||||
def test_parallel_builds(self):
|
||||
stubs.stubout_loopingcall_delay(self.stubs)
|
||||
|
||||
def _do_build(id, proj, user, *args):
|
||||
values = {
|
||||
'id': id,
|
||||
'project_id': proj,
|
||||
'user_id': user,
|
||||
'image_id': 1,
|
||||
'kernel_id': 2,
|
||||
'ramdisk_id': 3,
|
||||
'instance_type_id': '3', # m1.large
|
||||
'mac_address': 'aa:bb:cc:dd:ee:ff',
|
||||
'os_type': 'linux'}
|
||||
instance = db.instance_create(self.context, values)
|
||||
self.conn.spawn(instance)
|
||||
|
||||
gt1 = eventlet.spawn(_do_build, 1, self.project.id, self.user.id)
|
||||
gt2 = eventlet.spawn(_do_build, 2, self.project.id, self.user.id)
|
||||
gt1.wait()
|
||||
gt2.wait()
|
||||
|
||||
def test_list_instances_0(self):
|
||||
instances = self.conn.list_instances()
|
||||
self.assertEquals(instances, [])
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
"""Stubouts, mocks and fixtures for the test suite"""
|
||||
|
||||
import eventlet
|
||||
from nova.virt import xenapi_conn
|
||||
from nova.virt.xenapi import fake
|
||||
from nova.virt.xenapi import volume_utils
|
||||
@ -28,29 +29,6 @@ def stubout_instance_snapshot(stubs):
|
||||
@classmethod
|
||||
def fake_fetch_image(cls, session, instance_id, image, user, project,
|
||||
type):
|
||||
# Stubout wait_for_task
|
||||
def fake_wait_for_task(self, task, id):
|
||||
class FakeEvent:
|
||||
|
||||
def send(self, value):
|
||||
self.rv = value
|
||||
|
||||
def wait(self):
|
||||
return self.rv
|
||||
|
||||
done = FakeEvent()
|
||||
self._poll_task(id, task, done)
|
||||
rv = done.wait()
|
||||
return rv
|
||||
|
||||
def fake_loop(self):
|
||||
pass
|
||||
|
||||
stubs.Set(xenapi_conn.XenAPISession, 'wait_for_task',
|
||||
fake_wait_for_task)
|
||||
|
||||
stubs.Set(xenapi_conn.XenAPISession, '_stop_loop', fake_loop)
|
||||
|
||||
from nova.virt.xenapi.fake import create_vdi
|
||||
name_label = "instance-%s" % instance_id
|
||||
#TODO: create fake SR record
|
||||
@ -63,11 +41,6 @@ def stubout_instance_snapshot(stubs):
|
||||
|
||||
stubs.Set(vm_utils.VMHelper, 'fetch_image', fake_fetch_image)
|
||||
|
||||
def fake_parse_xmlrpc_value(val):
|
||||
return val
|
||||
|
||||
stubs.Set(xenapi_conn, '_parse_xmlrpc_value', fake_parse_xmlrpc_value)
|
||||
|
||||
def fake_wait_for_vhd_coalesce(session, instance_id, sr_ref, vdi_ref,
|
||||
original_parent_uuid):
|
||||
from nova.virt.xenapi.fake import create_vdi
|
||||
@ -144,6 +117,16 @@ def stubout_loopingcall_start(stubs):
|
||||
stubs.Set(utils.LoopingCall, 'start', fake_start)
|
||||
|
||||
|
||||
def stubout_loopingcall_delay(stubs):
|
||||
def fake_start(self, interval, now=True):
|
||||
self._running = True
|
||||
eventlet.sleep(1)
|
||||
self.f(*self.args, **self.kw)
|
||||
# This would fail before parallel xenapi calls were fixed
|
||||
assert self._running == False
|
||||
stubs.Set(utils.LoopingCall, 'start', fake_start)
|
||||
|
||||
|
||||
class FakeSessionForVMTests(fake.SessionBase):
|
||||
""" Stubs out a XenAPISession for VM tests """
|
||||
def __init__(self, uri):
|
||||
|
@ -442,6 +442,8 @@ class LoopingCall(object):
|
||||
try:
|
||||
while self._running:
|
||||
self.f(*self.args, **self.kw)
|
||||
if not self._running:
|
||||
break
|
||||
greenthread.sleep(interval)
|
||||
except LoopingCallDone, e:
|
||||
self.stop()
|
||||
|
@ -347,7 +347,6 @@ class XenAPISession(object):
|
||||
"(is the Dom0 disk full?)"))
|
||||
with timeout.Timeout(FLAGS.xenapi_login_timeout, exception):
|
||||
self._session.login_with_password(user, pw)
|
||||
self.loop = None
|
||||
|
||||
def get_imported_xenapi(self):
|
||||
"""Stubout point. This can be replaced with a mock xenapi module."""
|
||||
@ -384,57 +383,52 @@ class XenAPISession(object):
|
||||
|
||||
def wait_for_task(self, task, id=None):
|
||||
"""Return the result of the given task. The task is polled
|
||||
until it completes. Not re-entrant."""
|
||||
until it completes."""
|
||||
done = event.Event()
|
||||
self.loop = utils.LoopingCall(self._poll_task, id, task, done)
|
||||
self.loop.start(FLAGS.xenapi_task_poll_interval, now=True)
|
||||
rv = done.wait()
|
||||
self.loop.stop()
|
||||
return rv
|
||||
loop = utils.LoopingCall(f=None)
|
||||
|
||||
def _stop_loop(self):
|
||||
"""Stop polling for task to finish."""
|
||||
#NOTE(sandy-walsh) Had to break this call out to support unit tests.
|
||||
if self.loop:
|
||||
self.loop.stop()
|
||||
def _poll_task():
|
||||
"""Poll the given XenAPI task, and return the result if the
|
||||
action was completed successfully or not.
|
||||
"""
|
||||
try:
|
||||
name = self._session.xenapi.task.get_name_label(task)
|
||||
status = self._session.xenapi.task.get_status(task)
|
||||
if id:
|
||||
action = dict(
|
||||
instance_id=int(id),
|
||||
action=name[0:255], # Ensure action is never > 255
|
||||
error=None)
|
||||
if status == "pending":
|
||||
return
|
||||
elif status == "success":
|
||||
result = self._session.xenapi.task.get_result(task)
|
||||
LOG.info(_("Task [%(name)s] %(task)s status:"
|
||||
" success %(result)s") % locals())
|
||||
done.send(_parse_xmlrpc_value(result))
|
||||
else:
|
||||
error_info = self._session.xenapi.task.get_error_info(task)
|
||||
action["error"] = str(error_info)
|
||||
LOG.warn(_("Task [%(name)s] %(task)s status:"
|
||||
" %(status)s %(error_info)s") % locals())
|
||||
done.send_exception(self.XenAPI.Failure(error_info))
|
||||
|
||||
if id:
|
||||
db.instance_action_create(context.get_admin_context(),
|
||||
action)
|
||||
except self.XenAPI.Failure, exc:
|
||||
LOG.warn(exc)
|
||||
done.send_exception(*sys.exc_info())
|
||||
loop.stop()
|
||||
|
||||
loop.f = _poll_task
|
||||
loop.start(FLAGS.xenapi_task_poll_interval, now=True)
|
||||
return done.wait()
|
||||
|
||||
def _create_session(self, url):
|
||||
"""Stubout point. This can be replaced with a mock session."""
|
||||
return self.XenAPI.Session(url)
|
||||
|
||||
def _poll_task(self, id, task, done):
|
||||
"""Poll the given XenAPI task, and fire the given action if we
|
||||
get a result.
|
||||
"""
|
||||
try:
|
||||
name = self._session.xenapi.task.get_name_label(task)
|
||||
status = self._session.xenapi.task.get_status(task)
|
||||
if id:
|
||||
action = dict(
|
||||
instance_id=int(id),
|
||||
action=name[0:255], # Ensure action is never > 255
|
||||
error=None)
|
||||
if status == "pending":
|
||||
return
|
||||
elif status == "success":
|
||||
result = self._session.xenapi.task.get_result(task)
|
||||
LOG.info(_("Task [%(name)s] %(task)s status:"
|
||||
" success %(result)s") % locals())
|
||||
done.send(_parse_xmlrpc_value(result))
|
||||
else:
|
||||
error_info = self._session.xenapi.task.get_error_info(task)
|
||||
action["error"] = str(error_info)
|
||||
LOG.warn(_("Task [%(name)s] %(task)s status:"
|
||||
" %(status)s %(error_info)s") % locals())
|
||||
done.send_exception(self.XenAPI.Failure(error_info))
|
||||
|
||||
if id:
|
||||
db.instance_action_create(context.get_admin_context(), action)
|
||||
except self.XenAPI.Failure, exc:
|
||||
LOG.warn(exc)
|
||||
done.send_exception(*sys.exc_info())
|
||||
self._stop_loop()
|
||||
|
||||
def _unwrap_plugin_exceptions(self, func, *args, **kwargs):
|
||||
"""Parse exception details"""
|
||||
try:
|
||||
|
@ -1,3 +1,4 @@
|
||||
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2010 United States Government as represented by the
|
||||
@ -31,11 +32,15 @@ ROOT = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
|
||||
VENV = os.path.join(ROOT, '.nova-venv')
|
||||
PIP_REQUIRES = os.path.join(ROOT, 'tools', 'pip-requires')
|
||||
TWISTED_NOVA='http://nova.openstack.org/Twisted-10.0.0Nova.tar.gz'
|
||||
PY_VERSION = "python" + str(sys.version_info[0]) + '.' + str(sys.version_info[1])
|
||||
|
||||
def die(message, *args):
|
||||
print >>sys.stderr, message % args
|
||||
sys.exit(1)
|
||||
|
||||
def check_python_version():
|
||||
if sys.version_info < (2, 6):
|
||||
die("Need Python Version >= 2.6")
|
||||
|
||||
def run_command(cmd, redirect_output=True, check_exit_code=True):
|
||||
"""
|
||||
@ -100,12 +105,12 @@ def install_dependencies(venv=VENV):
|
||||
|
||||
|
||||
# Tell the virtual env how to "import nova"
|
||||
pthfile = os.path.join(venv, "lib", "python2.6", "site-packages", "nova.pth")
|
||||
pthfile = os.path.join(venv, "lib", PY_VERSION, "site-packages", "nova.pth")
|
||||
f = open(pthfile, 'w')
|
||||
f.write("%s\n" % ROOT)
|
||||
# Patch eventlet (see FAQ # 1485)
|
||||
patchsrc = os.path.join(ROOT, 'tools', 'eventlet-patch')
|
||||
patchfile = os.path.join(venv, "lib", "python2.6", "site-packages", "eventlet",
|
||||
patchfile = os.path.join(venv, "lib", PY_VERSION, "site-packages", "eventlet",
|
||||
"green", "subprocess.py")
|
||||
patch_cmd = "patch %s %s" % (patchfile, patchsrc)
|
||||
os.system(patch_cmd)
|
||||
@ -134,6 +139,7 @@ def print_help():
|
||||
|
||||
|
||||
def main(argv):
|
||||
check_python_version()
|
||||
check_dependencies()
|
||||
create_virtualenv()
|
||||
install_dependencies()
|
||||
|
@ -2,7 +2,7 @@ SQLAlchemy==0.6.3
|
||||
pep8==0.5.0
|
||||
pylint==0.19
|
||||
IPy==0.70
|
||||
Cheetah==2.4.2.1
|
||||
Cheetah==2.4.4
|
||||
M2Crypto==0.20.2
|
||||
amqplib==0.6.1
|
||||
anyjson==0.2.4
|
||||
|
Loading…
x
Reference in New Issue
Block a user