Statistics
| Branch: | Tag: | Revision:

root / test / ganeti.rpc_unittest.py @ 3b877f08

History | View | Annotate | Download (10 kB)

1 33231500 Michael Hanselmann
#!/usr/bin/python
2 33231500 Michael Hanselmann
#
3 33231500 Michael Hanselmann
4 33231500 Michael Hanselmann
# Copyright (C) 2010 Google Inc.
5 33231500 Michael Hanselmann
#
6 33231500 Michael Hanselmann
# This program is free software; you can redistribute it and/or modify
7 33231500 Michael Hanselmann
# it under the terms of the GNU General Public License as published by
8 33231500 Michael Hanselmann
# the Free Software Foundation; either version 2 of the License, or
9 33231500 Michael Hanselmann
# (at your option) any later version.
10 33231500 Michael Hanselmann
#
11 33231500 Michael Hanselmann
# This program is distributed in the hope that it will be useful, but
12 33231500 Michael Hanselmann
# WITHOUT ANY WARRANTY; without even the implied warranty of
13 33231500 Michael Hanselmann
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 33231500 Michael Hanselmann
# General Public License for more details.
15 33231500 Michael Hanselmann
#
16 33231500 Michael Hanselmann
# You should have received a copy of the GNU General Public License
17 33231500 Michael Hanselmann
# along with this program; if not, write to the Free Software
18 33231500 Michael Hanselmann
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 33231500 Michael Hanselmann
# 02110-1301, USA.
20 33231500 Michael Hanselmann
21 33231500 Michael Hanselmann
22 33231500 Michael Hanselmann
"""Script for testing ganeti.rpc"""
23 33231500 Michael Hanselmann
24 33231500 Michael Hanselmann
import os
25 33231500 Michael Hanselmann
import sys
26 33231500 Michael Hanselmann
import unittest
27 33231500 Michael Hanselmann
28 33231500 Michael Hanselmann
from ganeti import constants
29 33231500 Michael Hanselmann
from ganeti import compat
30 33231500 Michael Hanselmann
from ganeti import rpc
31 33231500 Michael Hanselmann
from ganeti import http
32 33231500 Michael Hanselmann
from ganeti import errors
33 33231500 Michael Hanselmann
from ganeti import serializer
34 33231500 Michael Hanselmann
35 33231500 Michael Hanselmann
import testutils
36 33231500 Michael Hanselmann
37 33231500 Michael Hanselmann
38 33231500 Michael Hanselmann
class TestTimeouts(unittest.TestCase):
39 33231500 Michael Hanselmann
  def test(self):
40 33231500 Michael Hanselmann
    names = [name[len("call_"):] for name in dir(rpc.RpcRunner)
41 33231500 Michael Hanselmann
             if name.startswith("call_")]
42 33231500 Michael Hanselmann
    self.assertEqual(len(names), len(rpc._TIMEOUTS))
43 33231500 Michael Hanselmann
    self.assertFalse([name for name in names
44 33231500 Michael Hanselmann
                      if not (rpc._TIMEOUTS[name] is None or
45 33231500 Michael Hanselmann
                              rpc._TIMEOUTS[name] > 0)])
46 33231500 Michael Hanselmann
47 33231500 Michael Hanselmann
48 33231500 Michael Hanselmann
class FakeHttpPool:
49 33231500 Michael Hanselmann
  def __init__(self, response_fn):
50 33231500 Michael Hanselmann
    self._response_fn = response_fn
51 33231500 Michael Hanselmann
    self.reqcount = 0
52 33231500 Michael Hanselmann
53 33231500 Michael Hanselmann
  def ProcessRequests(self, reqs):
54 33231500 Michael Hanselmann
    for req in reqs:
55 33231500 Michael Hanselmann
      self.reqcount += 1
56 33231500 Michael Hanselmann
      self._response_fn(req)
57 33231500 Michael Hanselmann
58 33231500 Michael Hanselmann
59 eb202c13 Manuel Franceschini
def GetFakeSimpleStoreClass(fn):
60 eb202c13 Manuel Franceschini
  class FakeSimpleStore:
61 eb202c13 Manuel Franceschini
    GetNodePrimaryIPList = fn
62 b43dcc5a Manuel Franceschini
    GetPrimaryIPFamily = lambda _: None
63 eb202c13 Manuel Franceschini
64 eb202c13 Manuel Franceschini
  return FakeSimpleStore
65 eb202c13 Manuel Franceschini
66 eb202c13 Manuel Franceschini
67 33231500 Michael Hanselmann
class TestClient(unittest.TestCase):
68 eb202c13 Manuel Franceschini
  def _FakeAddressLookup(self, map):
69 eb202c13 Manuel Franceschini
    return lambda node_list: [map.get(node) for node in node_list]
70 eb202c13 Manuel Franceschini
71 33231500 Michael Hanselmann
  def _GetVersionResponse(self, req):
72 33231500 Michael Hanselmann
    self.assertEqual(req.host, "localhost")
73 33231500 Michael Hanselmann
    self.assertEqual(req.port, 24094)
74 33231500 Michael Hanselmann
    self.assertEqual(req.path, "/version")
75 33231500 Michael Hanselmann
    req.success = True
76 33231500 Michael Hanselmann
    req.resp_status_code = http.HTTP_OK
77 33231500 Michael Hanselmann
    req.resp_body = serializer.DumpJson((True, 123))
78 33231500 Michael Hanselmann
79 33231500 Michael Hanselmann
  def testVersionSuccess(self):
80 eb202c13 Manuel Franceschini
    fn = self._FakeAddressLookup({"localhost": "localhost"})
81 eb202c13 Manuel Franceschini
    client = rpc.Client("version", None, 24094, address_lookup_fn=fn)
82 33231500 Michael Hanselmann
    client.ConnectNode("localhost")
83 33231500 Michael Hanselmann
    pool = FakeHttpPool(self._GetVersionResponse)
84 33231500 Michael Hanselmann
    result = client.GetResults(http_pool=pool)
85 33231500 Michael Hanselmann
    self.assertEqual(result.keys(), ["localhost"])
86 33231500 Michael Hanselmann
    lhresp = result["localhost"]
87 33231500 Michael Hanselmann
    self.assertFalse(lhresp.offline)
88 33231500 Michael Hanselmann
    self.assertEqual(lhresp.node, "localhost")
89 33231500 Michael Hanselmann
    self.assertFalse(lhresp.fail_msg)
90 33231500 Michael Hanselmann
    self.assertEqual(lhresp.payload, 123)
91 33231500 Michael Hanselmann
    self.assertEqual(lhresp.call, "version")
92 33231500 Michael Hanselmann
    lhresp.Raise("should not raise")
93 33231500 Michael Hanselmann
    self.assertEqual(pool.reqcount, 1)
94 33231500 Michael Hanselmann
95 33231500 Michael Hanselmann
  def _GetMultiVersionResponse(self, req):
96 33231500 Michael Hanselmann
    self.assert_(req.host.startswith("node"))
97 33231500 Michael Hanselmann
    self.assertEqual(req.port, 23245)
98 33231500 Michael Hanselmann
    self.assertEqual(req.path, "/version")
99 33231500 Michael Hanselmann
    req.success = True
100 33231500 Michael Hanselmann
    req.resp_status_code = http.HTTP_OK
101 33231500 Michael Hanselmann
    req.resp_body = serializer.DumpJson((True, 987))
102 33231500 Michael Hanselmann
103 33231500 Michael Hanselmann
  def testMultiVersionSuccess(self):
104 33231500 Michael Hanselmann
    nodes = ["node%s" % i for i in range(50)]
105 eb202c13 Manuel Franceschini
    fn = self._FakeAddressLookup(dict(zip(nodes, nodes)))
106 eb202c13 Manuel Franceschini
    client = rpc.Client("version", None, 23245, address_lookup_fn=fn)
107 33231500 Michael Hanselmann
    client.ConnectList(nodes)
108 33231500 Michael Hanselmann
109 33231500 Michael Hanselmann
    pool = FakeHttpPool(self._GetMultiVersionResponse)
110 33231500 Michael Hanselmann
    result = client.GetResults(http_pool=pool)
111 33231500 Michael Hanselmann
    self.assertEqual(sorted(result.keys()), sorted(nodes))
112 33231500 Michael Hanselmann
113 33231500 Michael Hanselmann
    for name in nodes:
114 33231500 Michael Hanselmann
      lhresp = result[name]
115 33231500 Michael Hanselmann
      self.assertFalse(lhresp.offline)
116 33231500 Michael Hanselmann
      self.assertEqual(lhresp.node, name)
117 33231500 Michael Hanselmann
      self.assertFalse(lhresp.fail_msg)
118 33231500 Michael Hanselmann
      self.assertEqual(lhresp.payload, 987)
119 33231500 Michael Hanselmann
      self.assertEqual(lhresp.call, "version")
120 33231500 Michael Hanselmann
      lhresp.Raise("should not raise")
121 33231500 Michael Hanselmann
122 33231500 Michael Hanselmann
    self.assertEqual(pool.reqcount, len(nodes))
123 33231500 Michael Hanselmann
124 33231500 Michael Hanselmann
  def _GetVersionResponseFail(self, req):
125 33231500 Michael Hanselmann
    self.assertEqual(req.path, "/version")
126 33231500 Michael Hanselmann
    req.success = True
127 33231500 Michael Hanselmann
    req.resp_status_code = http.HTTP_OK
128 33231500 Michael Hanselmann
    req.resp_body = serializer.DumpJson((False, "Unknown error"))
129 33231500 Michael Hanselmann
130 33231500 Michael Hanselmann
  def testVersionFailure(self):
131 eb202c13 Manuel Franceschini
    lookup_map = {"aef9ur4i.example.com": "aef9ur4i.example.com"}
132 eb202c13 Manuel Franceschini
    fn = self._FakeAddressLookup(lookup_map)
133 eb202c13 Manuel Franceschini
    client = rpc.Client("version", None, 5903, address_lookup_fn=fn)
134 33231500 Michael Hanselmann
    client.ConnectNode("aef9ur4i.example.com")
135 33231500 Michael Hanselmann
    pool = FakeHttpPool(self._GetVersionResponseFail)
136 33231500 Michael Hanselmann
    result = client.GetResults(http_pool=pool)
137 33231500 Michael Hanselmann
    self.assertEqual(result.keys(), ["aef9ur4i.example.com"])
138 33231500 Michael Hanselmann
    lhresp = result["aef9ur4i.example.com"]
139 33231500 Michael Hanselmann
    self.assertFalse(lhresp.offline)
140 33231500 Michael Hanselmann
    self.assertEqual(lhresp.node, "aef9ur4i.example.com")
141 33231500 Michael Hanselmann
    self.assert_(lhresp.fail_msg)
142 33231500 Michael Hanselmann
    self.assertFalse(lhresp.payload)
143 33231500 Michael Hanselmann
    self.assertEqual(lhresp.call, "version")
144 33231500 Michael Hanselmann
    self.assertRaises(errors.OpExecError, lhresp.Raise, "failed")
145 33231500 Michael Hanselmann
    self.assertEqual(pool.reqcount, 1)
146 33231500 Michael Hanselmann
147 33231500 Michael Hanselmann
  def _GetHttpErrorResponse(self, httperrnodes, failnodes, req):
148 33231500 Michael Hanselmann
    self.assertEqual(req.path, "/vg_list")
149 33231500 Michael Hanselmann
    self.assertEqual(req.port, 15165)
150 33231500 Michael Hanselmann
151 33231500 Michael Hanselmann
    if req.host in httperrnodes:
152 33231500 Michael Hanselmann
      req.success = False
153 33231500 Michael Hanselmann
      req.error = "Node set up for HTTP errors"
154 33231500 Michael Hanselmann
155 33231500 Michael Hanselmann
    elif req.host in failnodes:
156 33231500 Michael Hanselmann
      req.success = True
157 33231500 Michael Hanselmann
      req.resp_status_code = 404
158 33231500 Michael Hanselmann
      req.resp_body = serializer.DumpJson({
159 33231500 Michael Hanselmann
        "code": 404,
160 33231500 Michael Hanselmann
        "message": "Method not found",
161 33231500 Michael Hanselmann
        "explain": "Explanation goes here",
162 33231500 Michael Hanselmann
        })
163 33231500 Michael Hanselmann
    else:
164 33231500 Michael Hanselmann
      req.success = True
165 33231500 Michael Hanselmann
      req.resp_status_code = http.HTTP_OK
166 33231500 Michael Hanselmann
      req.resp_body = serializer.DumpJson((True, hash(req.host)))
167 33231500 Michael Hanselmann
168 33231500 Michael Hanselmann
  def testHttpError(self):
169 33231500 Michael Hanselmann
    nodes = ["uaf6pbbv%s" % i for i in range(50)]
170 eb202c13 Manuel Franceschini
    fn = self._FakeAddressLookup(dict(zip(nodes, nodes)))
171 33231500 Michael Hanselmann
172 33231500 Michael Hanselmann
    httperrnodes = set(nodes[1::7])
173 33231500 Michael Hanselmann
    self.assertEqual(len(httperrnodes), 7)
174 33231500 Michael Hanselmann
175 33231500 Michael Hanselmann
    failnodes = set(nodes[2::3]) - httperrnodes
176 33231500 Michael Hanselmann
    self.assertEqual(len(failnodes), 14)
177 33231500 Michael Hanselmann
178 33231500 Michael Hanselmann
    self.assertEqual(len(set(nodes) - failnodes - httperrnodes), 29)
179 33231500 Michael Hanselmann
180 eb202c13 Manuel Franceschini
    client = rpc.Client("vg_list", None, 15165, address_lookup_fn=fn)
181 33231500 Michael Hanselmann
    client.ConnectList(nodes)
182 33231500 Michael Hanselmann
183 33231500 Michael Hanselmann
    pool = FakeHttpPool(compat.partial(self._GetHttpErrorResponse,
184 33231500 Michael Hanselmann
                                       httperrnodes, failnodes))
185 33231500 Michael Hanselmann
    result = client.GetResults(http_pool=pool)
186 33231500 Michael Hanselmann
    self.assertEqual(sorted(result.keys()), sorted(nodes))
187 33231500 Michael Hanselmann
188 33231500 Michael Hanselmann
    for name in nodes:
189 33231500 Michael Hanselmann
      lhresp = result[name]
190 33231500 Michael Hanselmann
      self.assertFalse(lhresp.offline)
191 33231500 Michael Hanselmann
      self.assertEqual(lhresp.node, name)
192 33231500 Michael Hanselmann
      self.assertEqual(lhresp.call, "vg_list")
193 33231500 Michael Hanselmann
194 33231500 Michael Hanselmann
      if name in httperrnodes:
195 33231500 Michael Hanselmann
        self.assert_(lhresp.fail_msg)
196 33231500 Michael Hanselmann
        self.assertRaises(errors.OpExecError, lhresp.Raise, "failed")
197 33231500 Michael Hanselmann
      elif name in failnodes:
198 33231500 Michael Hanselmann
        self.assert_(lhresp.fail_msg)
199 33231500 Michael Hanselmann
        self.assertRaises(errors.OpPrereqError, lhresp.Raise, "failed",
200 33231500 Michael Hanselmann
                          prereq=True, ecode=errors.ECODE_INVAL)
201 33231500 Michael Hanselmann
      else:
202 33231500 Michael Hanselmann
        self.assertFalse(lhresp.fail_msg)
203 33231500 Michael Hanselmann
        self.assertEqual(lhresp.payload, hash(name))
204 33231500 Michael Hanselmann
        lhresp.Raise("should not raise")
205 33231500 Michael Hanselmann
206 33231500 Michael Hanselmann
    self.assertEqual(pool.reqcount, len(nodes))
207 33231500 Michael Hanselmann
208 33231500 Michael Hanselmann
  def _GetInvalidResponseA(self, req):
209 33231500 Michael Hanselmann
    self.assertEqual(req.path, "/version")
210 33231500 Michael Hanselmann
    req.success = True
211 33231500 Michael Hanselmann
    req.resp_status_code = http.HTTP_OK
212 33231500 Michael Hanselmann
    req.resp_body = serializer.DumpJson(("This", "is", "an", "invalid",
213 33231500 Michael Hanselmann
                                         "response", "!", 1, 2, 3))
214 33231500 Michael Hanselmann
215 33231500 Michael Hanselmann
  def _GetInvalidResponseB(self, req):
216 33231500 Michael Hanselmann
    self.assertEqual(req.path, "/version")
217 33231500 Michael Hanselmann
    req.success = True
218 33231500 Michael Hanselmann
    req.resp_status_code = http.HTTP_OK
219 33231500 Michael Hanselmann
    req.resp_body = serializer.DumpJson("invalid response")
220 33231500 Michael Hanselmann
221 33231500 Michael Hanselmann
  def testInvalidResponse(self):
222 eb202c13 Manuel Franceschini
    lookup_map = {"oqo7lanhly.example.com": "oqo7lanhly.example.com"}
223 eb202c13 Manuel Franceschini
    fn = self._FakeAddressLookup(lookup_map)
224 eb202c13 Manuel Franceschini
    client = rpc.Client("version", None, 19978, address_lookup_fn=fn)
225 33231500 Michael Hanselmann
    for fn in [self._GetInvalidResponseA, self._GetInvalidResponseB]:
226 33231500 Michael Hanselmann
      client.ConnectNode("oqo7lanhly.example.com")
227 33231500 Michael Hanselmann
      pool = FakeHttpPool(fn)
228 33231500 Michael Hanselmann
      result = client.GetResults(http_pool=pool)
229 33231500 Michael Hanselmann
      self.assertEqual(result.keys(), ["oqo7lanhly.example.com"])
230 33231500 Michael Hanselmann
      lhresp = result["oqo7lanhly.example.com"]
231 33231500 Michael Hanselmann
      self.assertFalse(lhresp.offline)
232 33231500 Michael Hanselmann
      self.assertEqual(lhresp.node, "oqo7lanhly.example.com")
233 33231500 Michael Hanselmann
      self.assert_(lhresp.fail_msg)
234 33231500 Michael Hanselmann
      self.assertFalse(lhresp.payload)
235 33231500 Michael Hanselmann
      self.assertEqual(lhresp.call, "version")
236 33231500 Michael Hanselmann
      self.assertRaises(errors.OpExecError, lhresp.Raise, "failed")
237 33231500 Michael Hanselmann
      self.assertEqual(pool.reqcount, 1)
238 33231500 Michael Hanselmann
239 eb202c13 Manuel Franceschini
  def testAddressLookupSimpleStore(self):
240 eb202c13 Manuel Franceschini
    addr_list = ["192.0.2.%d" % n for n in range(0, 255, 13)]
241 eb202c13 Manuel Franceschini
    node_list = ["node%d.example.com" % n for n in range(0, 255, 13)]
242 eb202c13 Manuel Franceschini
    node_addr_list = [ " ".join(t) for t in zip(node_list, addr_list)]
243 b43dcc5a Manuel Franceschini
    ssc = GetFakeSimpleStoreClass(lambda _: node_addr_list)
244 eb202c13 Manuel Franceschini
    result = rpc._AddressLookup(node_list, ssc=ssc)
245 eb202c13 Manuel Franceschini
    self.assertEqual(result, addr_list)
246 eb202c13 Manuel Franceschini
247 eb202c13 Manuel Franceschini
  def testAddressLookupNSLookup(self):
248 eb202c13 Manuel Franceschini
    addr_list = ["192.0.2.%d" % n for n in range(0, 255, 13)]
249 eb202c13 Manuel Franceschini
    node_list = ["node%d.example.com" % n for n in range(0, 255, 13)]
250 b43dcc5a Manuel Franceschini
    ssc = GetFakeSimpleStoreClass(lambda _: [])
251 eb202c13 Manuel Franceschini
    node_addr_map = dict(zip(node_list, addr_list))
252 b43dcc5a Manuel Franceschini
    nslookup_fn = lambda name, family=None: node_addr_map.get(name)
253 eb202c13 Manuel Franceschini
    result = rpc._AddressLookup(node_list, ssc=ssc, nslookup_fn=nslookup_fn)
254 eb202c13 Manuel Franceschini
    self.assertEqual(result, addr_list)
255 eb202c13 Manuel Franceschini
256 eb202c13 Manuel Franceschini
  def testAddressLookupBoth(self):
257 eb202c13 Manuel Franceschini
    addr_list = ["192.0.2.%d" % n for n in range(0, 255, 13)]
258 eb202c13 Manuel Franceschini
    node_list = ["node%d.example.com" % n for n in range(0, 255, 13)]
259 eb202c13 Manuel Franceschini
    n = len(addr_list) / 2
260 eb202c13 Manuel Franceschini
    node_addr_list = [ " ".join(t) for t in zip(node_list[n:], addr_list[n:])]
261 b43dcc5a Manuel Franceschini
    ssc = GetFakeSimpleStoreClass(lambda _: node_addr_list)
262 eb202c13 Manuel Franceschini
    node_addr_map = dict(zip(node_list[:n], addr_list[:n]))
263 b43dcc5a Manuel Franceschini
    nslookup_fn = lambda name, family=None: node_addr_map.get(name)
264 eb202c13 Manuel Franceschini
    result = rpc._AddressLookup(node_list, ssc=ssc, nslookup_fn=nslookup_fn)
265 eb202c13 Manuel Franceschini
    self.assertEqual(result, addr_list)
266 eb202c13 Manuel Franceschini
267 b43dcc5a Manuel Franceschini
  def testAddressLookupIPv6(self):
268 b43dcc5a Manuel Franceschini
    addr_list = ["2001:db8::%d" % n for n in range(0, 255, 13)]
269 b43dcc5a Manuel Franceschini
    node_list = ["node%d.example.com" % n for n in range(0, 255, 13)]
270 b43dcc5a Manuel Franceschini
    node_addr_list = [ " ".join(t) for t in zip(node_list, addr_list)]
271 b43dcc5a Manuel Franceschini
    ssc = GetFakeSimpleStoreClass(lambda _: node_addr_list)
272 b43dcc5a Manuel Franceschini
    result = rpc._AddressLookup(node_list, ssc=ssc)
273 b43dcc5a Manuel Franceschini
    self.assertEqual(result, addr_list)
274 b43dcc5a Manuel Franceschini
275 33231500 Michael Hanselmann
276 33231500 Michael Hanselmann
if __name__ == "__main__":
277 33231500 Michael Hanselmann
  testutils.GanetiTestProgram()