Merge lp:~soren/nova/lp658257 into lp:~hudson-openstack/nova/trunk

Proposed by Soren Hansen
Status: Merged
Approved by: Jay Pipes
Approved revision: 335
Merged at revision: 336
Proposed branch: lp:~soren/nova/lp658257
Merge into: lp:~hudson-openstack/nova/trunk
Diff against target: 155 lines (+49/-14)
5 files modified
nova/api/ec2/cloud.py (+3/-3)
nova/api/ec2/images.py (+3/-0)
nova/fakerabbit.py (+14/-0)
nova/rpc.py (+9/-0)
nova/tests/cloud_unittest.py (+20/-11)
To merge this branch: bzr merge lp:~soren/nova/lp658257
Reviewer Review Type Date Requested Status
Jay Pipes (community) Approve
Michael Gundlach (community) Approve
Review via email: mp+38108@code.launchpad.net

Description of the change

Fix EC2 GetConsoleOutput method and add unit tests for it.

To post a comment you must log in.
Revision history for this message
Michael Gundlach (gundlach) wrote :

lgtm.

I need to file a separate bug, because I replaced instance_id with ec2_id_list in several places for clarity. I missed that these were kwargs.

review: Approve
Revision history for this message
Jay Pipes (jaypipes) wrote :

Hi!

Looks good, Soren! Nice job switching over to eventlet.

One tiny FYI, not cause for non-approval:

120 + self.network = utils.import_class(FLAGS.network_manager)()

There is a shortcut in utils called import_object() that would be:

  self.network = utils.import_object(FLAGS.network_manager)

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'nova/api/ec2/cloud.py'
2--- nova/api/ec2/cloud.py 2010-10-05 20:16:42 +0000
3+++ nova/api/ec2/cloud.py 2010-10-11 11:43:40 +0000
4@@ -258,9 +258,9 @@
5 def delete_security_group(self, context, group_name, **kwargs):
6 return True
7
8- def get_console_output(self, context, ec2_id_list, **kwargs):
9- # ec2_id_list is passed in as a list of instances
10- ec2_id = ec2_id_list[0]
11+ def get_console_output(self, context, instance_id, **kwargs):
12+ # instance_id is passed in as a list of instances
13+ ec2_id = instance_id[0]
14 internal_id = ec2_id_to_internal_id(ec2_id)
15 instance_ref = db.instance_get_by_internal_id(context, internal_id)
16 return rpc.call('%s.%s' % (FLAGS.compute_topic,
17
18=== modified file 'nova/api/ec2/images.py'
19--- nova/api/ec2/images.py 2010-09-28 20:39:52 +0000
20+++ nova/api/ec2/images.py 2010-10-11 11:43:40 +0000
21@@ -69,6 +69,9 @@
22
23 optionally filtered by a list of image_id """
24
25+ if FLAGS.connection_type == 'fake':
26+ return [{ 'imageId' : 'bar'}]
27+
28 # FIXME: send along the list of only_images to check for
29 response = conn(context).make_request(
30 method='GET',
31
32=== modified file 'nova/fakerabbit.py'
33--- nova/fakerabbit.py 2010-08-16 12:16:21 +0000
34+++ nova/fakerabbit.py 2010-10-11 11:43:40 +0000
35@@ -22,6 +22,7 @@
36 import Queue as queue
37
38 from carrot.backends import base
39+from eventlet import greenthread
40
41
42 class Message(base.BaseMessage):
43@@ -38,6 +39,7 @@
44 def publish(self, message, routing_key=None):
45 logging.debug('(%s) publish (key: %s) %s',
46 self.name, routing_key, message)
47+ routing_key = routing_key.split('.')[0]
48 if routing_key in self._routes:
49 for f in self._routes[routing_key]:
50 logging.debug('Publishing to route %s', f)
51@@ -94,6 +96,18 @@
52 self._exchanges[exchange].bind(self._queues[queue].push,
53 routing_key)
54
55+ def declare_consumer(self, queue, callback, *args, **kwargs):
56+ self.current_queue = queue
57+ self.current_callback = callback
58+
59+ def consume(self, *args, **kwargs):
60+ while True:
61+ item = self.get(self.current_queue)
62+ if item:
63+ self.current_callback(item)
64+ raise StopIteration()
65+ greenthread.sleep(0)
66+
67 def get(self, queue, no_ack=False):
68 if not queue in self._queues or not self._queues[queue].size():
69 return None
70
71=== modified file 'nova/rpc.py'
72--- nova/rpc.py 2010-09-25 02:25:12 +0000
73+++ nova/rpc.py 2010-10-11 11:43:40 +0000
74@@ -28,6 +28,7 @@
75
76 from carrot import connection as carrot_connection
77 from carrot import messaging
78+from eventlet import greenthread
79 from twisted.internet import defer
80 from twisted.internet import task
81
82@@ -107,6 +108,14 @@
83 logging.exception("Failed to fetch message from queue")
84 self.failed_connection = True
85
86+ def attach_to_eventlet(self):
87+ """Only needed for unit tests!"""
88+ def fetch_repeatedly():
89+ while True:
90+ self.fetch(enable_callbacks=True)
91+ greenthread.sleep(0.1)
92+ greenthread.spawn(fetch_repeatedly)
93+
94 def attach_to_twisted(self):
95 """Attach a callback to twisted that fires 10 times a second"""
96 loop = task.LoopingCall(self.fetch, enable_callbacks=True)
97
98=== modified file 'nova/tests/cloud_unittest.py'
99--- nova/tests/cloud_unittest.py 2010-10-04 20:39:05 +0000
100+++ nova/tests/cloud_unittest.py 2010-10-11 11:43:40 +0000
101@@ -16,6 +16,7 @@
102 # License for the specific language governing permissions and limitations
103 # under the License.
104
105+from base64 import b64decode
106 import json
107 import logging
108 from M2Crypto import BIO
109@@ -63,11 +64,17 @@
110 self.cloud = cloud.CloudController()
111
112 # set up a service
113- self.compute = utils.import_class(FLAGS.compute_manager)
114+ self.compute = utils.import_class(FLAGS.compute_manager)()
115 self.compute_consumer = rpc.AdapterConsumer(connection=self.conn,
116 topic=FLAGS.compute_topic,
117 proxy=self.compute)
118- self.compute_consumer.attach_to_twisted()
119+ self.compute_consumer.attach_to_eventlet()
120+ self.network = utils.import_class(FLAGS.network_manager)()
121+ self.network_consumer = rpc.AdapterConsumer(connection=self.conn,
122+ topic=FLAGS.network_topic,
123+ proxy=self.network)
124+ self.network_consumer.attach_to_eventlet()
125+
126
127 self.manager = manager.AuthManager()
128 self.user = self.manager.create_user('admin', 'admin', 'admin', True)
129@@ -85,15 +92,17 @@
130 return cloud._gen_key(self.context, self.context.user.id, name)
131
132 def test_console_output(self):
133- if FLAGS.connection_type == 'fake':
134- logging.debug("Can't test instances without a real virtual env.")
135- return
136- instance_id = 'foo'
137- inst = yield self.compute.run_instance(instance_id)
138- output = yield self.cloud.get_console_output(self.context, [instance_id])
139- logging.debug(output)
140- self.assert_(output)
141- rv = yield self.compute.terminate_instance(instance_id)
142+ image_id = FLAGS.default_image
143+ instance_type = FLAGS.default_instance_type
144+ max_count = 1
145+ kwargs = {'image_id': image_id,
146+ 'instance_type': instance_type,
147+ 'max_count': max_count }
148+ rv = yield self.cloud.run_instances(self.context, **kwargs)
149+ instance_id = rv['instancesSet'][0]['instanceId']
150+ output = yield self.cloud.get_console_output(context=self.context, instance_id=[instance_id])
151+ self.assertEquals(b64decode(output['output']), 'FAKE CONSOLE OUTPUT')
152+ rv = yield self.cloud.terminate_instances(self.context, [instance_id])
153
154
155 def test_key_generation(self):