1
# vim: tabstop=4 shiftwidth=4 softtabstop=4
2
# Copyright [2010] [Anso Labs, LLC]
4
# Licensed under the Apache License, Version 2.0 (the "License");
5
# you may not use this file except in compliance with the License.
6
# You may obtain a copy of the License at
8
# http://www.apache.org/licenses/LICENSE-2.0
10
# Unless required by applicable law or agreed to in writing, software
11
# distributed under the License is distributed on an "AS IS" BASIS,
12
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
# See the License for the specific language governing permissions and
14
# limitations under the License.
20
from nova import vendor
22
from boto.ec2 import regioninfo
23
from tornado import httpserver
24
from twisted.internet import defer
26
from nova import flags
28
from nova.auth import users
29
from nova.endpoint import api
30
from nova.endpoint import cloud
36
# NOTE(termie): These are a bunch of helper methods and classes to short
37
# circuit boto calls and feed them into our tornado handlers,
38
# it's pretty damn circuitous so apologies if you have to fix
40
def boto_to_tornado(method, path, headers, data, host, connection=None):
41
""" translate boto requests into tornado requests
43
connection should be a FakeTornadoHttpConnection instance
45
headers = httpserver.HTTPHeaders()
46
for k, v in headers.iteritems():
49
req = httpserver.HTTPRequest(method=method,
54
remote_ip='127.0.0.1',
55
connection=connection)
59
def raw_to_httpresponse(s):
60
""" translate a raw tornado http response into an httplib.HTTPResponse """
61
sock = FakeHttplibSocket(s)
62
resp = httplib.HTTPResponse(sock)
67
class FakeHttplibSocket(object):
68
""" a fake socket implementation for httplib.HTTPResponse, trivial """
69
def __init__(self, s):
70
self.fp = StringIO.StringIO(s)
72
def makefile(self, mode, other):
76
class FakeTornadoStream(object):
77
""" a fake stream to satisfy tornado's assumptions, trivial """
78
def set_close_callback(self, f):
82
class FakeTornadoConnection(object):
83
""" a fake connection object for tornado to pass to its handlers
85
web requests are expected to write to this as they get data and call
86
finish when they are done with the request, we buffer the writes and
87
kick off a callback when it is done so that we can feed the result back
90
def __init__(self, d):
92
self._buffer = StringIO.StringIO()
94
def write(self, chunk):
95
self._buffer.write(chunk)
98
s = self._buffer.getvalue()
105
return FakeTornadoStream()
108
class FakeHttplibConnection(object):
109
""" a fake httplib.HTTPConnection for boto to use
111
requests made via this connection actually get translated and routed into
112
our tornado app, we then wait for the response and turn it back into
113
the httplib.HTTPResponse that boto expects.
115
def __init__(self, app, host, is_secure=False):
118
self.deferred = defer.Deferred()
120
def request(self, method, path, data, headers):
121
req = boto_to_tornado
122
conn = FakeTornadoConnection(self.deferred)
123
request = boto_to_tornado(connection=conn,
129
handler = self.app(request)
130
self.deferred.addCallback(raw_to_httpresponse)
132
def getresponse(self):
133
@defer.inlineCallbacks
135
result = yield self.deferred
136
defer.returnValue(result)
138
# NOTE(termie): defer.returnValue above should ensure that
139
# this deferred has already been called by the time
140
# we get here, we are going to cheat and return
141
# the result of the callback
148
class ApiEc2TestCase(test.BaseTestCase):
150
super(ApiEc2TestCase, self).setUp()
152
self.users = users.UserManager.instance()
153
self.cloud = cloud.CloudController()
155
self.host = '127.0.0.1'
157
self.app = api.APIServerApplication(self.users, {'Cloud': self.cloud})
158
self.ec2 = boto.connect_ec2(
159
aws_access_key_id='fake',
160
aws_secret_access_key='fake',
162
region=regioninfo.RegionInfo(None, 'test', self.host),
164
path='/services/Cloud')
166
self.mox.StubOutWithMock(self.ec2, 'new_http_connection')
168
def expect_http(self, host=None, is_secure=False):
169
http = FakeHttplibConnection(
170
self.app, '%s:%d' % (self.host, FLAGS.cc_port), False)
171
self.ec2.new_http_connection(host, is_secure).AndReturn(http)
174
def test_describe_instances(self):
178
self.assertEqual(self.ec2.get_all_instances(), [])
181
def test_get_all_key_pairs(self):
184
keyname = "".join(random.choice("sdiuisudfsdcnpaqwertasd") for x in range(random.randint(4, 8)))
185
self.users.generate_key_pair('fake', keyname)
187
rv = self.ec2.get_all_key_pairs()
188
self.assertTrue(filter(lambda k: k.name == keyname, rv))