Statistics
| Branch: | Tag: | Revision:

root / test / ganeti.rapi.client_unittest.py @ b82d4c5e

History | View | Annotate | Download (42.7 kB)

1
#!/usr/bin/python
2
#
3

    
4
# Copyright (C) 2010 Google Inc.
5
#
6
# This program is free software; you can redistribute it and/or modify
7
# it under the terms of the GNU General Public License as published by
8
# the Free Software Foundation; either version 2 of the License, or
9
# (at your option) any later version.
10
#
11
# This program is distributed in the hope that it will be useful, but
12
# WITHOUT ANY WARRANTY; without even the implied warranty of
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
# General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License
17
# along with this program; if not, write to the Free Software
18
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19
# 02110-1301, USA.
20

    
21

    
22
"""Script for unittesting the RAPI client module"""
23

    
24

    
25
import re
26
import unittest
27
import warnings
28
import pycurl
29

    
30
from ganeti import constants
31
from ganeti import http
32
from ganeti import serializer
33
from ganeti import utils
34

    
35
from ganeti.rapi import connector
36
from ganeti.rapi import rlib2
37
from ganeti.rapi import client
38

    
39
import testutils
40

    
41

    
42
_URI_RE = re.compile(r"https://(?P<host>.*):(?P<port>\d+)(?P<path>/.*)")
43

    
44
# List of resource handlers which aren't used by the RAPI client
45
_KNOWN_UNUSED = set([
46
  connector.R_root,
47
  connector.R_2,
48
  ])
49

    
50
# Global variable for collecting used handlers
51
_used_handlers = None
52

    
53

    
54
def _GetPathFromUri(uri):
55
  """Gets the path and query from a URI.
56

57
  """
58
  match = _URI_RE.match(uri)
59
  if match:
60
    return match.groupdict()["path"]
61
  else:
62
    return None
63

    
64

    
65
class FakeCurl:
66
  def __init__(self, rapi):
67
    self._rapi = rapi
68
    self._opts = {}
69
    self._info = {}
70

    
71
  def setopt(self, opt, value):
72
    self._opts[opt] = value
73

    
74
  def getopt(self, opt):
75
    return self._opts.get(opt)
76

    
77
  def unsetopt(self, opt):
78
    self._opts.pop(opt, None)
79

    
80
  def getinfo(self, info):
81
    return self._info[info]
82

    
83
  def perform(self):
84
    method = self._opts[pycurl.CUSTOMREQUEST]
85
    url = self._opts[pycurl.URL]
86
    request_body = self._opts[pycurl.POSTFIELDS]
87
    writefn = self._opts[pycurl.WRITEFUNCTION]
88

    
89
    path = _GetPathFromUri(url)
90
    (code, resp_body) = self._rapi.FetchResponse(path, method, request_body)
91

    
92
    self._info[pycurl.RESPONSE_CODE] = code
93
    if resp_body is not None:
94
      writefn(resp_body)
95

    
96

    
97
class RapiMock(object):
98
  def __init__(self):
99
    self._mapper = connector.Mapper()
100
    self._responses = []
101
    self._last_handler = None
102
    self._last_req_data = None
103

    
104
  def AddResponse(self, response, code=200):
105
    self._responses.insert(0, (code, response))
106

    
107
  def CountPending(self):
108
    return len(self._responses)
109

    
110
  def GetLastHandler(self):
111
    return self._last_handler
112

    
113
  def GetLastRequestData(self):
114
    return self._last_req_data
115

    
116
  def FetchResponse(self, path, method, request_body):
117
    self._last_req_data = request_body
118

    
119
    try:
120
      (handler_cls, items, args) = self._mapper.getController(path)
121

    
122
      # Record handler as used
123
      _used_handlers.add(handler_cls)
124

    
125
      self._last_handler = handler_cls(items, args, None)
126
      if not hasattr(self._last_handler, method.upper()):
127
        raise http.HttpNotImplemented(message="Method not implemented")
128

    
129
    except http.HttpException, ex:
130
      code = ex.code
131
      response = ex.message
132
    else:
133
      if not self._responses:
134
        raise Exception("No responses")
135

    
136
      (code, response) = self._responses.pop()
137

    
138
    return code, response
139

    
140

    
141
class TestConstants(unittest.TestCase):
142
  def test(self):
143
    self.assertEqual(client.GANETI_RAPI_PORT, constants.DEFAULT_RAPI_PORT)
144
    self.assertEqual(client.GANETI_RAPI_VERSION, constants.RAPI_VERSION)
145
    self.assertEqual(client.HTTP_APP_JSON, http.HTTP_APP_JSON)
146
    self.assertEqual(client._REQ_DATA_VERSION_FIELD, rlib2._REQ_DATA_VERSION)
147
    self.assertEqual(client._INST_CREATE_REQV1, rlib2._INST_CREATE_REQV1)
148
    self.assertEqual(client._INST_REINSTALL_REQV1, rlib2._INST_REINSTALL_REQV1)
149
    self.assertEqual(client._INST_NIC_PARAMS, constants.INIC_PARAMS)
150

    
151

    
152
class RapiMockTest(unittest.TestCase):
153
  def test(self):
154
    rapi = RapiMock()
155
    path = "/version"
156
    self.assertEqual((404, None), rapi.FetchResponse("/foo", "GET", None))
157
    self.assertEqual((501, "Method not implemented"),
158
                     rapi.FetchResponse("/version", "POST", None))
159
    rapi.AddResponse("2")
160
    code, response = rapi.FetchResponse("/version", "GET", None)
161
    self.assertEqual(200, code)
162
    self.assertEqual("2", response)
163
    self.failUnless(isinstance(rapi.GetLastHandler(), rlib2.R_version))
164

    
165

    
166
def _FakeNoSslPycurlVersion():
167
  # Note: incomplete version tuple
168
  return (3, "7.16.0", 462848, "mysystem", 1581, None, 0)
169

    
170

    
171
def _FakeFancySslPycurlVersion():
172
  # Note: incomplete version tuple
173
  return (3, "7.16.0", 462848, "mysystem", 1581, "FancySSL/1.2.3", 0)
174

    
175

    
176
def _FakeOpenSslPycurlVersion():
177
  # Note: incomplete version tuple
178
  return (2, "7.15.5", 462597, "othersystem", 668, "OpenSSL/0.9.8c", 0)
179

    
180

    
181
def _FakeGnuTlsPycurlVersion():
182
  # Note: incomplete version tuple
183
  return (3, "7.18.0", 463360, "somesystem", 1581, "GnuTLS/2.0.4", 0)
184

    
185

    
186
class TestExtendedConfig(unittest.TestCase):
187
  def testAuth(self):
188
    cl = client.GanetiRapiClient("master.example.com",
189
                                 username="user", password="pw",
190
                                 curl_factory=lambda: FakeCurl(RapiMock()))
191

    
192
    curl = cl._CreateCurl()
193
    self.assertEqual(curl.getopt(pycurl.HTTPAUTH), pycurl.HTTPAUTH_BASIC)
194
    self.assertEqual(curl.getopt(pycurl.USERPWD), "user:pw")
195

    
196
  def testInvalidAuth(self):
197
    # No username
198
    self.assertRaises(client.Error, client.GanetiRapiClient,
199
                      "master-a.example.com", password="pw")
200
    # No password
201
    self.assertRaises(client.Error, client.GanetiRapiClient,
202
                      "master-b.example.com", username="user")
203

    
204
  def testCertVerifyInvalidCombinations(self):
205
    self.assertRaises(client.Error, client.GenericCurlConfig,
206
                      use_curl_cabundle=True, cafile="cert1.pem")
207
    self.assertRaises(client.Error, client.GenericCurlConfig,
208
                      use_curl_cabundle=True, capath="certs/")
209
    self.assertRaises(client.Error, client.GenericCurlConfig,
210
                      use_curl_cabundle=True,
211
                      cafile="cert1.pem", capath="certs/")
212

    
213
  def testProxySignalVerifyHostname(self):
214
    for use_gnutls in [False, True]:
215
      if use_gnutls:
216
        pcverfn = _FakeGnuTlsPycurlVersion
217
      else:
218
        pcverfn = _FakeOpenSslPycurlVersion
219

    
220
      for proxy in ["", "http://127.0.0.1:1234"]:
221
        for use_signal in [False, True]:
222
          for verify_hostname in [False, True]:
223
            cfgfn = client.GenericCurlConfig(proxy=proxy, use_signal=use_signal,
224
                                             verify_hostname=verify_hostname,
225
                                             _pycurl_version_fn=pcverfn)
226

    
227
            curl_factory = lambda: FakeCurl(RapiMock())
228
            cl = client.GanetiRapiClient("master.example.com",
229
                                         curl_config_fn=cfgfn,
230
                                         curl_factory=curl_factory)
231

    
232
            curl = cl._CreateCurl()
233
            self.assertEqual(curl.getopt(pycurl.PROXY), proxy)
234
            self.assertEqual(curl.getopt(pycurl.NOSIGNAL), not use_signal)
235

    
236
            if verify_hostname:
237
              self.assertEqual(curl.getopt(pycurl.SSL_VERIFYHOST), 2)
238
            else:
239
              self.assertEqual(curl.getopt(pycurl.SSL_VERIFYHOST), 0)
240

    
241
  def testNoCertVerify(self):
242
    cfgfn = client.GenericCurlConfig()
243

    
244
    curl_factory = lambda: FakeCurl(RapiMock())
245
    cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
246
                                 curl_factory=curl_factory)
247

    
248
    curl = cl._CreateCurl()
249
    self.assertFalse(curl.getopt(pycurl.SSL_VERIFYPEER))
250
    self.assertFalse(curl.getopt(pycurl.CAINFO))
251
    self.assertFalse(curl.getopt(pycurl.CAPATH))
252

    
253
  def testCertVerifyCurlBundle(self):
254
    cfgfn = client.GenericCurlConfig(use_curl_cabundle=True)
255

    
256
    curl_factory = lambda: FakeCurl(RapiMock())
257
    cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
258
                                 curl_factory=curl_factory)
259

    
260
    curl = cl._CreateCurl()
261
    self.assert_(curl.getopt(pycurl.SSL_VERIFYPEER))
262
    self.assertFalse(curl.getopt(pycurl.CAINFO))
263
    self.assertFalse(curl.getopt(pycurl.CAPATH))
264

    
265
  def testCertVerifyCafile(self):
266
    mycert = "/tmp/some/UNUSED/cert/file.pem"
267
    cfgfn = client.GenericCurlConfig(cafile=mycert)
268

    
269
    curl_factory = lambda: FakeCurl(RapiMock())
270
    cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
271
                                 curl_factory=curl_factory)
272

    
273
    curl = cl._CreateCurl()
274
    self.assert_(curl.getopt(pycurl.SSL_VERIFYPEER))
275
    self.assertEqual(curl.getopt(pycurl.CAINFO), mycert)
276
    self.assertFalse(curl.getopt(pycurl.CAPATH))
277

    
278
  def testCertVerifyCapath(self):
279
    certdir = "/tmp/some/UNUSED/cert/directory"
280
    pcverfn = _FakeOpenSslPycurlVersion
281
    cfgfn = client.GenericCurlConfig(capath=certdir,
282
                                     _pycurl_version_fn=pcverfn)
283

    
284
    curl_factory = lambda: FakeCurl(RapiMock())
285
    cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
286
                                 curl_factory=curl_factory)
287

    
288
    curl = cl._CreateCurl()
289
    self.assert_(curl.getopt(pycurl.SSL_VERIFYPEER))
290
    self.assertEqual(curl.getopt(pycurl.CAPATH), certdir)
291
    self.assertFalse(curl.getopt(pycurl.CAINFO))
292

    
293
  def testCertVerifyCapathGnuTls(self):
294
    certdir = "/tmp/some/UNUSED/cert/directory"
295
    pcverfn = _FakeGnuTlsPycurlVersion
296
    cfgfn = client.GenericCurlConfig(capath=certdir,
297
                                     _pycurl_version_fn=pcverfn)
298

    
299
    curl_factory = lambda: FakeCurl(RapiMock())
300
    cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
301
                                 curl_factory=curl_factory)
302

    
303
    self.assertRaises(client.Error, cl._CreateCurl)
304

    
305
  def testCertVerifyNoSsl(self):
306
    certdir = "/tmp/some/UNUSED/cert/directory"
307
    pcverfn = _FakeNoSslPycurlVersion
308
    cfgfn = client.GenericCurlConfig(capath=certdir,
309
                                     _pycurl_version_fn=pcverfn)
310

    
311
    curl_factory = lambda: FakeCurl(RapiMock())
312
    cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
313
                                 curl_factory=curl_factory)
314

    
315
    self.assertRaises(client.Error, cl._CreateCurl)
316

    
317
  def testCertVerifyFancySsl(self):
318
    certdir = "/tmp/some/UNUSED/cert/directory"
319
    pcverfn = _FakeFancySslPycurlVersion
320
    cfgfn = client.GenericCurlConfig(capath=certdir,
321
                                     _pycurl_version_fn=pcverfn)
322

    
323
    curl_factory = lambda: FakeCurl(RapiMock())
324
    cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
325
                                 curl_factory=curl_factory)
326

    
327
    self.assertRaises(NotImplementedError, cl._CreateCurl)
328

    
329
  def testCertVerifyCapath(self):
330
    for connect_timeout in [None, 1, 5, 10, 30, 60, 300]:
331
      for timeout in [None, 1, 30, 60, 3600, 24 * 3600]:
332
        cfgfn = client.GenericCurlConfig(connect_timeout=connect_timeout,
333
                                         timeout=timeout)
334

    
335
        curl_factory = lambda: FakeCurl(RapiMock())
336
        cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
337
                                     curl_factory=curl_factory)
338

    
339
        curl = cl._CreateCurl()
340
        self.assertEqual(curl.getopt(pycurl.CONNECTTIMEOUT), connect_timeout)
341
        self.assertEqual(curl.getopt(pycurl.TIMEOUT), timeout)
342

    
343

    
344
class GanetiRapiClientTests(testutils.GanetiTestCase):
345
  def setUp(self):
346
    testutils.GanetiTestCase.setUp(self)
347

    
348
    self.rapi = RapiMock()
349
    self.curl = FakeCurl(self.rapi)
350
    self.client = client.GanetiRapiClient("master.example.com",
351
                                          curl_factory=lambda: self.curl)
352

    
353
  def assertHandler(self, handler_cls):
354
    self.failUnless(isinstance(self.rapi.GetLastHandler(), handler_cls))
355

    
356
  def assertQuery(self, key, value):
357
    self.assertEqual(value, self.rapi.GetLastHandler().queryargs.get(key, None))
358

    
359
  def assertItems(self, items):
360
    self.assertEqual(items, self.rapi.GetLastHandler().items)
361

    
362
  def assertBulk(self):
363
    self.assertTrue(self.rapi.GetLastHandler().useBulk())
364

    
365
  def assertDryRun(self):
366
    self.assertTrue(self.rapi.GetLastHandler().dryRun())
367

    
368
  def assertUseForce(self):
369
    self.assertTrue(self.rapi.GetLastHandler().useForce())
370

    
371
  def testEncodeQuery(self):
372
    query = [
373
      ("a", None),
374
      ("b", 1),
375
      ("c", 2),
376
      ("d", "Foo"),
377
      ("e", True),
378
      ]
379

    
380
    expected = [
381
      ("a", ""),
382
      ("b", 1),
383
      ("c", 2),
384
      ("d", "Foo"),
385
      ("e", 1),
386
      ]
387

    
388
    self.assertEqualValues(self.client._EncodeQuery(query),
389
                           expected)
390

    
391
    # invalid types
392
    for i in [[1, 2, 3], {"moo": "boo"}, (1, 2, 3)]:
393
      self.assertRaises(ValueError, self.client._EncodeQuery, [("x", i)])
394

    
395
  def testCurlSettings(self):
396
    self.rapi.AddResponse("2")
397
    self.assertEqual(2, self.client.GetVersion())
398
    self.assertHandler(rlib2.R_version)
399

    
400
    # Signals should be disabled by default
401
    self.assert_(self.curl.getopt(pycurl.NOSIGNAL))
402

    
403
    # No auth and no proxy
404
    self.assertFalse(self.curl.getopt(pycurl.USERPWD))
405
    self.assert_(self.curl.getopt(pycurl.PROXY) is None)
406

    
407
    # Content-type is required for requests
408
    headers = self.curl.getopt(pycurl.HTTPHEADER)
409
    self.assert_("Content-type: application/json" in headers)
410

    
411
  def testHttpError(self):
412
    self.rapi.AddResponse(None, code=404)
413
    try:
414
      self.client.GetJobStatus(15140)
415
    except client.GanetiApiError, err:
416
      self.assertEqual(err.code, 404)
417
    else:
418
      self.fail("Didn't raise exception")
419

    
420
  def testGetVersion(self):
421
    self.rapi.AddResponse("2")
422
    self.assertEqual(2, self.client.GetVersion())
423
    self.assertHandler(rlib2.R_version)
424

    
425
  def testGetFeatures(self):
426
    for features in [[], ["foo", "bar", "baz"]]:
427
      self.rapi.AddResponse(serializer.DumpJson(features))
428
      self.assertEqual(features, self.client.GetFeatures())
429
      self.assertHandler(rlib2.R_2_features)
430

    
431
  def testGetFeaturesNotFound(self):
432
    self.rapi.AddResponse(None, code=404)
433
    self.assertEqual([], self.client.GetFeatures())
434

    
435
  def testGetOperatingSystems(self):
436
    self.rapi.AddResponse("[\"beos\"]")
437
    self.assertEqual(["beos"], self.client.GetOperatingSystems())
438
    self.assertHandler(rlib2.R_2_os)
439

    
440
  def testGetClusterTags(self):
441
    self.rapi.AddResponse("[\"tag\"]")
442
    self.assertEqual(["tag"], self.client.GetClusterTags())
443
    self.assertHandler(rlib2.R_2_tags)
444

    
445
  def testAddClusterTags(self):
446
    self.rapi.AddResponse("1234")
447
    self.assertEqual(1234,
448
        self.client.AddClusterTags(["awesome"], dry_run=True))
449
    self.assertHandler(rlib2.R_2_tags)
450
    self.assertDryRun()
451
    self.assertQuery("tag", ["awesome"])
452

    
453
  def testDeleteClusterTags(self):
454
    self.rapi.AddResponse("5107")
455
    self.assertEqual(5107, self.client.DeleteClusterTags(["awesome"],
456
                                                         dry_run=True))
457
    self.assertHandler(rlib2.R_2_tags)
458
    self.assertDryRun()
459
    self.assertQuery("tag", ["awesome"])
460

    
461
  def testGetInfo(self):
462
    self.rapi.AddResponse("{}")
463
    self.assertEqual({}, self.client.GetInfo())
464
    self.assertHandler(rlib2.R_2_info)
465

    
466
  def testGetInstances(self):
467
    self.rapi.AddResponse("[]")
468
    self.assertEqual([], self.client.GetInstances(bulk=True))
469
    self.assertHandler(rlib2.R_2_instances)
470
    self.assertBulk()
471

    
472
  def testGetInstance(self):
473
    self.rapi.AddResponse("[]")
474
    self.assertEqual([], self.client.GetInstance("instance"))
475
    self.assertHandler(rlib2.R_2_instances_name)
476
    self.assertItems(["instance"])
477

    
478
  def testGetInstanceInfo(self):
479
    self.rapi.AddResponse("21291")
480
    self.assertEqual(21291, self.client.GetInstanceInfo("inst3"))
481
    self.assertHandler(rlib2.R_2_instances_name_info)
482
    self.assertItems(["inst3"])
483
    self.assertQuery("static", None)
484

    
485
    self.rapi.AddResponse("3428")
486
    self.assertEqual(3428, self.client.GetInstanceInfo("inst31", static=False))
487
    self.assertHandler(rlib2.R_2_instances_name_info)
488
    self.assertItems(["inst31"])
489
    self.assertQuery("static", ["0"])
490

    
491
    self.rapi.AddResponse("15665")
492
    self.assertEqual(15665, self.client.GetInstanceInfo("inst32", static=True))
493
    self.assertHandler(rlib2.R_2_instances_name_info)
494
    self.assertItems(["inst32"])
495
    self.assertQuery("static", ["1"])
496

    
497
  def testCreateInstanceOldVersion(self):
498
    # No NICs
499
    self.rapi.AddResponse(None, code=404)
500
    self.assertRaises(client.GanetiApiError, self.client.CreateInstance,
501
                      "create", "inst1.example.com", "plain", [], [])
502
    self.assertEqual(self.rapi.CountPending(), 0)
503

    
504
    # More than one NIC
505
    self.rapi.AddResponse(None, code=404)
506
    self.assertRaises(client.GanetiApiError, self.client.CreateInstance,
507
                      "create", "inst1.example.com", "plain", [],
508
                      [{}, {}, {}])
509
    self.assertEqual(self.rapi.CountPending(), 0)
510

    
511
    # Unsupported NIC fields
512
    self.rapi.AddResponse(None, code=404)
513
    self.assertRaises(client.GanetiApiError, self.client.CreateInstance,
514
                      "create", "inst1.example.com", "plain", [],
515
                      [{"x": True, "y": False}])
516
    self.assertEqual(self.rapi.CountPending(), 0)
517

    
518
    # Unsupported disk fields
519
    self.rapi.AddResponse(None, code=404)
520
    self.assertRaises(client.GanetiApiError, self.client.CreateInstance,
521
                      "create", "inst1.example.com", "plain",
522
                      [{}, {"moo": "foo",}], [{}])
523
    self.assertEqual(self.rapi.CountPending(), 0)
524

    
525
    # Unsupported fields
526
    self.rapi.AddResponse(None, code=404)
527
    self.assertRaises(client.GanetiApiError, self.client.CreateInstance,
528
                      "create", "inst1.example.com", "plain", [], [{}],
529
                      hello_world=123)
530
    self.assertEqual(self.rapi.CountPending(), 0)
531

    
532
    self.rapi.AddResponse(None, code=404)
533
    self.assertRaises(client.GanetiApiError, self.client.CreateInstance,
534
                      "create", "inst1.example.com", "plain", [], [{}],
535
                      memory=128)
536
    self.assertEqual(self.rapi.CountPending(), 0)
537

    
538
    # Normal creation
539
    testnics = [
540
      [{}],
541
      [{ "mac": constants.VALUE_AUTO, }],
542
      [{ "ip": "192.0.2.99", "mode": constants.NIC_MODE_ROUTED, }],
543
      ]
544

    
545
    testdisks = [
546
      [],
547
      [{ "size": 128, }],
548
      [{ "size": 321, }, { "size": 4096, }],
549
      ]
550

    
551
    for idx, nics in enumerate(testnics):
552
      for disks in testdisks:
553
        beparams = {
554
          constants.BE_MEMORY: 512,
555
          constants.BE_AUTO_BALANCE: False,
556
          }
557
        hvparams = {
558
          constants.HV_MIGRATION_PORT: 9876,
559
          constants.HV_VNC_TLS: True,
560
          }
561

    
562
        self.rapi.AddResponse(None, code=404)
563
        self.rapi.AddResponse(serializer.DumpJson(3122617 + idx))
564
        job_id = self.client.CreateInstance("create", "inst1.example.com",
565
                                            "plain", disks, nics,
566
                                            pnode="node99", dry_run=True,
567
                                            hvparams=hvparams,
568
                                            beparams=beparams)
569
        self.assertEqual(job_id, 3122617 + idx)
570
        self.assertHandler(rlib2.R_2_instances)
571
        self.assertDryRun()
572
        self.assertEqual(self.rapi.CountPending(), 0)
573

    
574
        data = serializer.LoadJson(self.rapi.GetLastRequestData())
575
        self.assertEqual(data["name"], "inst1.example.com")
576
        self.assertEqual(data["disk_template"], "plain")
577
        self.assertEqual(data["pnode"], "node99")
578
        self.assertEqual(data[constants.BE_MEMORY], 512)
579
        self.assertEqual(data[constants.BE_AUTO_BALANCE], False)
580
        self.assertEqual(data[constants.HV_MIGRATION_PORT], 9876)
581
        self.assertEqual(data[constants.HV_VNC_TLS], True)
582
        self.assertEqual(data["disks"], [disk["size"] for disk in disks])
583

    
584
  def testCreateInstance(self):
585
    self.rapi.AddResponse(serializer.DumpJson([rlib2._INST_CREATE_REQV1]))
586
    self.rapi.AddResponse("23030")
587
    job_id = self.client.CreateInstance("create", "inst1.example.com",
588
                                        "plain", [], [], dry_run=True)
589
    self.assertEqual(job_id, 23030)
590
    self.assertHandler(rlib2.R_2_instances)
591
    self.assertDryRun()
592

    
593
    data = serializer.LoadJson(self.rapi.GetLastRequestData())
594

    
595
    for field in ["dry_run", "beparams", "hvparams", "start"]:
596
      self.assertFalse(field in data)
597

    
598
    self.assertEqual(data["name"], "inst1.example.com")
599
    self.assertEqual(data["disk_template"], "plain")
600

    
601
  def testCreateInstance2(self):
602
    self.rapi.AddResponse(serializer.DumpJson([rlib2._INST_CREATE_REQV1]))
603
    self.rapi.AddResponse("24740")
604
    job_id = self.client.CreateInstance("import", "inst2.example.com",
605
                                        "drbd8", [{"size": 100,}],
606
                                        [{}, {"bridge": "br1", }],
607
                                        dry_run=False, start=True,
608
                                        pnode="node1", snode="node9",
609
                                        ip_check=False)
610
    self.assertEqual(job_id, 24740)
611
    self.assertHandler(rlib2.R_2_instances)
612

    
613
    data = serializer.LoadJson(self.rapi.GetLastRequestData())
614
    self.assertEqual(data[rlib2._REQ_DATA_VERSION], 1)
615
    self.assertEqual(data["name"], "inst2.example.com")
616
    self.assertEqual(data["disk_template"], "drbd8")
617
    self.assertEqual(data["start"], True)
618
    self.assertEqual(data["ip_check"], False)
619
    self.assertEqualValues(data["disks"], [{"size": 100,}])
620
    self.assertEqualValues(data["nics"], [{}, {"bridge": "br1", }])
621

    
622
  def testDeleteInstance(self):
623
    self.rapi.AddResponse("1234")
624
    self.assertEqual(1234, self.client.DeleteInstance("instance", dry_run=True))
625
    self.assertHandler(rlib2.R_2_instances_name)
626
    self.assertItems(["instance"])
627
    self.assertDryRun()
628

    
629
  def testGetInstanceTags(self):
630
    self.rapi.AddResponse("[]")
631
    self.assertEqual([], self.client.GetInstanceTags("fooinstance"))
632
    self.assertHandler(rlib2.R_2_instances_name_tags)
633
    self.assertItems(["fooinstance"])
634

    
635
  def testAddInstanceTags(self):
636
    self.rapi.AddResponse("1234")
637
    self.assertEqual(1234,
638
        self.client.AddInstanceTags("fooinstance", ["awesome"], dry_run=True))
639
    self.assertHandler(rlib2.R_2_instances_name_tags)
640
    self.assertItems(["fooinstance"])
641
    self.assertDryRun()
642
    self.assertQuery("tag", ["awesome"])
643

    
644
  def testDeleteInstanceTags(self):
645
    self.rapi.AddResponse("25826")
646
    self.assertEqual(25826, self.client.DeleteInstanceTags("foo", ["awesome"],
647
                                                           dry_run=True))
648
    self.assertHandler(rlib2.R_2_instances_name_tags)
649
    self.assertItems(["foo"])
650
    self.assertDryRun()
651
    self.assertQuery("tag", ["awesome"])
652

    
653
  def testRebootInstance(self):
654
    self.rapi.AddResponse("6146")
655
    job_id = self.client.RebootInstance("i-bar", reboot_type="hard",
656
                                        ignore_secondaries=True, dry_run=True)
657
    self.assertEqual(6146, job_id)
658
    self.assertHandler(rlib2.R_2_instances_name_reboot)
659
    self.assertItems(["i-bar"])
660
    self.assertDryRun()
661
    self.assertQuery("type", ["hard"])
662
    self.assertQuery("ignore_secondaries", ["1"])
663

    
664
  def testShutdownInstance(self):
665
    self.rapi.AddResponse("1487")
666
    self.assertEqual(1487, self.client.ShutdownInstance("foo-instance",
667
                                                        dry_run=True))
668
    self.assertHandler(rlib2.R_2_instances_name_shutdown)
669
    self.assertItems(["foo-instance"])
670
    self.assertDryRun()
671

    
672
  def testStartupInstance(self):
673
    self.rapi.AddResponse("27149")
674
    self.assertEqual(27149, self.client.StartupInstance("bar-instance",
675
                                                        dry_run=True))
676
    self.assertHandler(rlib2.R_2_instances_name_startup)
677
    self.assertItems(["bar-instance"])
678
    self.assertDryRun()
679

    
680
  def testReinstallInstance(self):
681
    self.rapi.AddResponse(serializer.DumpJson([]))
682
    self.rapi.AddResponse("19119")
683
    self.assertEqual(19119, self.client.ReinstallInstance("baz-instance",
684
                                                          os="DOS",
685
                                                          no_startup=True))
686
    self.assertHandler(rlib2.R_2_instances_name_reinstall)
687
    self.assertItems(["baz-instance"])
688
    self.assertQuery("os", ["DOS"])
689
    self.assertQuery("nostartup", ["1"])
690
    self.assertEqual(self.rapi.CountPending(), 0)
691

    
692
  def testReinstallInstanceNew(self):
693
    self.rapi.AddResponse(serializer.DumpJson([rlib2._INST_REINSTALL_REQV1]))
694
    self.rapi.AddResponse("25689")
695
    self.assertEqual(25689, self.client.ReinstallInstance("moo-instance",
696
                                                          os="Debian",
697
                                                          no_startup=True))
698
    self.assertHandler(rlib2.R_2_instances_name_reinstall)
699
    self.assertItems(["moo-instance"])
700
    data = serializer.LoadJson(self.rapi.GetLastRequestData())
701
    self.assertEqual(len(data), 2)
702
    self.assertEqual(data["os"], "Debian")
703
    self.assertEqual(data["start"], False)
704
    self.assertEqual(self.rapi.CountPending(), 0)
705

    
706
  def testReinstallInstanceWithOsparams1(self):
707
    self.rapi.AddResponse(serializer.DumpJson([]))
708
    self.assertRaises(client.GanetiApiError, self.client.ReinstallInstance,
709
                      "doo-instance", osparams={"x": "y"})
710
    self.assertEqual(self.rapi.CountPending(), 0)
711

    
712
  def testReinstallInstanceWithOsparams2(self):
713
    osparams = {
714
      "Hello": "World",
715
      "foo": "bar",
716
      }
717
    self.rapi.AddResponse(serializer.DumpJson([rlib2._INST_REINSTALL_REQV1]))
718
    self.rapi.AddResponse("1717")
719
    self.assertEqual(1717, self.client.ReinstallInstance("zoo-instance",
720
                                                         osparams=osparams))
721
    self.assertHandler(rlib2.R_2_instances_name_reinstall)
722
    self.assertItems(["zoo-instance"])
723
    data = serializer.LoadJson(self.rapi.GetLastRequestData())
724
    self.assertEqual(len(data), 2)
725
    self.assertEqual(data["osparams"], osparams)
726
    self.assertEqual(data["start"], True)
727
    self.assertEqual(self.rapi.CountPending(), 0)
728

    
729
  def testReplaceInstanceDisks(self):
730
    self.rapi.AddResponse("999")
731
    job_id = self.client.ReplaceInstanceDisks("instance-name",
732
        disks=[0, 1], dry_run=True, iallocator="hail")
733
    self.assertEqual(999, job_id)
734
    self.assertHandler(rlib2.R_2_instances_name_replace_disks)
735
    self.assertItems(["instance-name"])
736
    self.assertQuery("disks", ["0,1"])
737
    self.assertQuery("mode", ["replace_auto"])
738
    self.assertQuery("iallocator", ["hail"])
739
    self.assertDryRun()
740

    
741
    self.rapi.AddResponse("1000")
742
    job_id = self.client.ReplaceInstanceDisks("instance-bar",
743
        disks=[1], mode="replace_on_secondary", remote_node="foo-node",
744
        dry_run=True)
745
    self.assertEqual(1000, job_id)
746
    self.assertItems(["instance-bar"])
747
    self.assertQuery("disks", ["1"])
748
    self.assertQuery("remote_node", ["foo-node"])
749
    self.assertDryRun()
750

    
751
    self.rapi.AddResponse("5175")
752
    self.assertEqual(5175, self.client.ReplaceInstanceDisks("instance-moo"))
753
    self.assertItems(["instance-moo"])
754
    self.assertQuery("disks", None)
755

    
756
  def testPrepareExport(self):
757
    self.rapi.AddResponse("8326")
758
    self.assertEqual(8326, self.client.PrepareExport("inst1", "local"))
759
    self.assertHandler(rlib2.R_2_instances_name_prepare_export)
760
    self.assertItems(["inst1"])
761
    self.assertQuery("mode", ["local"])
762

    
763
  def testExportInstance(self):
764
    self.rapi.AddResponse("19695")
765
    job_id = self.client.ExportInstance("inst2", "local", "nodeX",
766
                                        shutdown=True)
767
    self.assertEqual(job_id, 19695)
768
    self.assertHandler(rlib2.R_2_instances_name_export)
769
    self.assertItems(["inst2"])
770

    
771
    data = serializer.LoadJson(self.rapi.GetLastRequestData())
772
    self.assertEqual(data["mode"], "local")
773
    self.assertEqual(data["destination"], "nodeX")
774
    self.assertEqual(data["shutdown"], True)
775

    
776
  def testMigrateInstanceDefaults(self):
777
    self.rapi.AddResponse("24873")
778
    job_id = self.client.MigrateInstance("inst91")
779
    self.assertEqual(job_id, 24873)
780
    self.assertHandler(rlib2.R_2_instances_name_migrate)
781
    self.assertItems(["inst91"])
782

    
783
    data = serializer.LoadJson(self.rapi.GetLastRequestData())
784
    self.assertFalse(data)
785

    
786
  def testMigrateInstance(self):
787
    for mode in constants.HT_MIGRATION_MODES:
788
      for cleanup in [False, True]:
789
        self.rapi.AddResponse("31910")
790
        job_id = self.client.MigrateInstance("inst289", mode=mode,
791
                                             cleanup=cleanup)
792
        self.assertEqual(job_id, 31910)
793
        self.assertHandler(rlib2.R_2_instances_name_migrate)
794
        self.assertItems(["inst289"])
795

    
796
        data = serializer.LoadJson(self.rapi.GetLastRequestData())
797
        self.assertEqual(len(data), 2)
798
        self.assertEqual(data["mode"], mode)
799
        self.assertEqual(data["cleanup"], cleanup)
800

    
801
  def testRenameInstanceDefaults(self):
802
    new_name = "newnametha7euqu"
803
    self.rapi.AddResponse("8791")
804
    job_id = self.client.RenameInstance("inst18821", new_name)
805
    self.assertEqual(job_id, 8791)
806
    self.assertHandler(rlib2.R_2_instances_name_rename)
807
    self.assertItems(["inst18821"])
808

    
809
    data = serializer.LoadJson(self.rapi.GetLastRequestData())
810
    self.assertEqualValues(data, {"new_name": new_name, })
811

    
812
  def testRenameInstance(self):
813
    new_name = "new-name-yiux1iin"
814
    for ip_check in [False, True]:
815
      for name_check in [False, True]:
816
        self.rapi.AddResponse("24776")
817
        job_id = self.client.RenameInstance("inst20967", new_name,
818
                                             ip_check=ip_check,
819
                                             name_check=name_check)
820
        self.assertEqual(job_id, 24776)
821
        self.assertHandler(rlib2.R_2_instances_name_rename)
822
        self.assertItems(["inst20967"])
823

    
824
        data = serializer.LoadJson(self.rapi.GetLastRequestData())
825
        self.assertEqual(len(data), 3)
826
        self.assertEqual(data["new_name"], new_name)
827
        self.assertEqual(data["ip_check"], ip_check)
828
        self.assertEqual(data["name_check"], name_check)
829

    
830
  def testGetJobs(self):
831
    self.rapi.AddResponse('[ { "id": "123", "uri": "\\/2\\/jobs\\/123" },'
832
                          '  { "id": "124", "uri": "\\/2\\/jobs\\/124" } ]')
833
    self.assertEqual([123, 124], self.client.GetJobs())
834
    self.assertHandler(rlib2.R_2_jobs)
835

    
836
  def testGetJobStatus(self):
837
    self.rapi.AddResponse("{\"foo\": \"bar\"}")
838
    self.assertEqual({"foo": "bar"}, self.client.GetJobStatus(1234))
839
    self.assertHandler(rlib2.R_2_jobs_id)
840
    self.assertItems(["1234"])
841

    
842
  def testWaitForJobChange(self):
843
    fields = ["id", "summary"]
844
    expected = {
845
      "job_info": [123, "something"],
846
      "log_entries": [],
847
      }
848

    
849
    self.rapi.AddResponse(serializer.DumpJson(expected))
850
    result = self.client.WaitForJobChange(123, fields, [], -1)
851
    self.assertEqualValues(expected, result)
852
    self.assertHandler(rlib2.R_2_jobs_id_wait)
853
    self.assertItems(["123"])
854

    
855
  def testCancelJob(self):
856
    self.rapi.AddResponse("[true, \"Job 123 will be canceled\"]")
857
    self.assertEqual([True, "Job 123 will be canceled"],
858
                     self.client.CancelJob(999, dry_run=True))
859
    self.assertHandler(rlib2.R_2_jobs_id)
860
    self.assertItems(["999"])
861
    self.assertDryRun()
862

    
863
  def testGetNodes(self):
864
    self.rapi.AddResponse("[ { \"id\": \"node1\", \"uri\": \"uri1\" },"
865
                          " { \"id\": \"node2\", \"uri\": \"uri2\" } ]")
866
    self.assertEqual(["node1", "node2"], self.client.GetNodes())
867
    self.assertHandler(rlib2.R_2_nodes)
868

    
869
    self.rapi.AddResponse("[ { \"id\": \"node1\", \"uri\": \"uri1\" },"
870
                          " { \"id\": \"node2\", \"uri\": \"uri2\" } ]")
871
    self.assertEqual([{"id": "node1", "uri": "uri1"},
872
                      {"id": "node2", "uri": "uri2"}],
873
                     self.client.GetNodes(bulk=True))
874
    self.assertHandler(rlib2.R_2_nodes)
875
    self.assertBulk()
876

    
877
  def testGetNode(self):
878
    self.rapi.AddResponse("{}")
879
    self.assertEqual({}, self.client.GetNode("node-foo"))
880
    self.assertHandler(rlib2.R_2_nodes_name)
881
    self.assertItems(["node-foo"])
882

    
883
  def testEvacuateNode(self):
884
    self.rapi.AddResponse("9876")
885
    job_id = self.client.EvacuateNode("node-1", remote_node="node-2")
886
    self.assertEqual(9876, job_id)
887
    self.assertHandler(rlib2.R_2_nodes_name_evacuate)
888
    self.assertItems(["node-1"])
889
    self.assertQuery("remote_node", ["node-2"])
890

    
891
    self.rapi.AddResponse("8888")
892
    job_id = self.client.EvacuateNode("node-3", iallocator="hail", dry_run=True)
893
    self.assertEqual(8888, job_id)
894
    self.assertItems(["node-3"])
895
    self.assertQuery("iallocator", ["hail"])
896
    self.assertDryRun()
897

    
898
    self.assertRaises(client.GanetiApiError,
899
                      self.client.EvacuateNode,
900
                      "node-4", iallocator="hail", remote_node="node-5")
901

    
902
  def testMigrateNode(self):
903
    self.rapi.AddResponse("1111")
904
    self.assertEqual(1111, self.client.MigrateNode("node-a", dry_run=True))
905
    self.assertHandler(rlib2.R_2_nodes_name_migrate)
906
    self.assertItems(["node-a"])
907
    self.assert_("mode" not in self.rapi.GetLastHandler().queryargs)
908
    self.assertDryRun()
909

    
910
    self.rapi.AddResponse("1112")
911
    self.assertEqual(1112, self.client.MigrateNode("node-a", dry_run=True,
912
                                                   mode="live"))
913
    self.assertHandler(rlib2.R_2_nodes_name_migrate)
914
    self.assertItems(["node-a"])
915
    self.assertQuery("mode", ["live"])
916
    self.assertDryRun()
917

    
918
  def testGetNodeRole(self):
919
    self.rapi.AddResponse("\"master\"")
920
    self.assertEqual("master", self.client.GetNodeRole("node-a"))
921
    self.assertHandler(rlib2.R_2_nodes_name_role)
922
    self.assertItems(["node-a"])
923

    
924
  def testSetNodeRole(self):
925
    self.rapi.AddResponse("789")
926
    self.assertEqual(789,
927
        self.client.SetNodeRole("node-foo", "master-candidate", force=True))
928
    self.assertHandler(rlib2.R_2_nodes_name_role)
929
    self.assertItems(["node-foo"])
930
    self.assertQuery("force", ["1"])
931
    self.assertEqual("\"master-candidate\"", self.rapi.GetLastRequestData())
932

    
933
  def testGetNodeStorageUnits(self):
934
    self.rapi.AddResponse("42")
935
    self.assertEqual(42,
936
        self.client.GetNodeStorageUnits("node-x", "lvm-pv", "fields"))
937
    self.assertHandler(rlib2.R_2_nodes_name_storage)
938
    self.assertItems(["node-x"])
939
    self.assertQuery("storage_type", ["lvm-pv"])
940
    self.assertQuery("output_fields", ["fields"])
941

    
942
  def testModifyNodeStorageUnits(self):
943
    self.rapi.AddResponse("14")
944
    self.assertEqual(14,
945
        self.client.ModifyNodeStorageUnits("node-z", "lvm-pv", "hda"))
946
    self.assertHandler(rlib2.R_2_nodes_name_storage_modify)
947
    self.assertItems(["node-z"])
948
    self.assertQuery("storage_type", ["lvm-pv"])
949
    self.assertQuery("name", ["hda"])
950
    self.assertQuery("allocatable", None)
951

    
952
    for allocatable, query_allocatable in [(True, "1"), (False, "0")]:
953
      self.rapi.AddResponse("7205")
954
      job_id = self.client.ModifyNodeStorageUnits("node-z", "lvm-pv", "hda",
955
                                                  allocatable=allocatable)
956
      self.assertEqual(7205, job_id)
957
      self.assertHandler(rlib2.R_2_nodes_name_storage_modify)
958
      self.assertItems(["node-z"])
959
      self.assertQuery("storage_type", ["lvm-pv"])
960
      self.assertQuery("name", ["hda"])
961
      self.assertQuery("allocatable", [query_allocatable])
962

    
963
  def testRepairNodeStorageUnits(self):
964
    self.rapi.AddResponse("99")
965
    self.assertEqual(99, self.client.RepairNodeStorageUnits("node-z", "lvm-pv",
966
                                                            "hda"))
967
    self.assertHandler(rlib2.R_2_nodes_name_storage_repair)
968
    self.assertItems(["node-z"])
969
    self.assertQuery("storage_type", ["lvm-pv"])
970
    self.assertQuery("name", ["hda"])
971

    
972
  def testGetNodeTags(self):
973
    self.rapi.AddResponse("[\"fry\", \"bender\"]")
974
    self.assertEqual(["fry", "bender"], self.client.GetNodeTags("node-k"))
975
    self.assertHandler(rlib2.R_2_nodes_name_tags)
976
    self.assertItems(["node-k"])
977

    
978
  def testAddNodeTags(self):
979
    self.rapi.AddResponse("1234")
980
    self.assertEqual(1234,
981
        self.client.AddNodeTags("node-v", ["awesome"], dry_run=True))
982
    self.assertHandler(rlib2.R_2_nodes_name_tags)
983
    self.assertItems(["node-v"])
984
    self.assertDryRun()
985
    self.assertQuery("tag", ["awesome"])
986

    
987
  def testDeleteNodeTags(self):
988
    self.rapi.AddResponse("16861")
989
    self.assertEqual(16861, self.client.DeleteNodeTags("node-w", ["awesome"],
990
                                                       dry_run=True))
991
    self.assertHandler(rlib2.R_2_nodes_name_tags)
992
    self.assertItems(["node-w"])
993
    self.assertDryRun()
994
    self.assertQuery("tag", ["awesome"])
995

    
996
  def testGetGroups(self):
997
    groups = [{"name": "group1",
998
               "uri": "/2/groups/group1",
999
               },
1000
              {"name": "group2",
1001
               "uri": "/2/groups/group2",
1002
               },
1003
              ]
1004
    self.rapi.AddResponse(serializer.DumpJson(groups))
1005
    self.assertEqual(["group1", "group2"], self.client.GetGroups())
1006
    self.assertHandler(rlib2.R_2_groups)
1007

    
1008
  def testGetGroupsBulk(self):
1009
    groups = [{"name": "group1",
1010
               "uri": "/2/groups/group1",
1011
               "node_cnt": 2,
1012
               "node_list": ["gnt1.test",
1013
                             "gnt2.test",
1014
                             ],
1015
               },
1016
              {"name": "group2",
1017
               "uri": "/2/groups/group2",
1018
               "node_cnt": 1,
1019
               "node_list": ["gnt3.test",
1020
                             ],
1021
               },
1022
              ]
1023
    self.rapi.AddResponse(serializer.DumpJson(groups))
1024

    
1025
    self.assertEqual(groups, self.client.GetGroups(bulk=True))
1026
    self.assertHandler(rlib2.R_2_groups)
1027
    self.assertBulk()
1028

    
1029
  def testGetGroup(self):
1030
    group = {"ctime": None,
1031
             "name": "default",
1032
             }
1033
    self.rapi.AddResponse(serializer.DumpJson(group))
1034
    self.assertEqual({"ctime": None, "name": "default"},
1035
                     self.client.GetGroup("default"))
1036
    self.assertHandler(rlib2.R_2_groups_name)
1037
    self.assertItems(["default"])
1038

    
1039
  def testCreateGroup(self):
1040
    self.rapi.AddResponse("12345")
1041
    job_id = self.client.CreateGroup("newgroup", dry_run=True)
1042
    self.assertEqual(job_id, 12345)
1043
    self.assertHandler(rlib2.R_2_groups)
1044
    self.assertDryRun()
1045

    
1046
  def testDeleteGroup(self):
1047
    self.rapi.AddResponse("12346")
1048
    job_id = self.client.DeleteGroup("newgroup", dry_run=True)
1049
    self.assertEqual(job_id, 12346)
1050
    self.assertHandler(rlib2.R_2_groups_name)
1051
    self.assertDryRun()
1052

    
1053
  def testRenameGroup(self):
1054
    self.rapi.AddResponse("12347")
1055
    job_id = self.client.RenameGroup("oldname", "newname")
1056
    self.assertEqual(job_id, 12347)
1057
    self.assertHandler(rlib2.R_2_groups_name_rename)
1058

    
1059
  def testModifyGroup(self):
1060
    self.rapi.AddResponse("12348")
1061
    job_id = self.client.ModifyGroup("mygroup", alloc_policy="foo")
1062
    self.assertEqual(job_id, 12348)
1063
    self.assertHandler(rlib2.R_2_groups_name_modify)
1064

    
1065
  def testAssignGroupNodes(self):
1066
    self.rapi.AddResponse("12349")
1067
    job_id = self.client.AssignGroupNodes("mygroup", ["node1", "node2"],
1068
                                          force=True, dry_run=True)
1069
    self.assertEqual(job_id, 12349)
1070
    self.assertHandler(rlib2.R_2_groups_name_assign_nodes)
1071
    self.assertDryRun()
1072
    self.assertUseForce()
1073

    
1074
  def testModifyInstance(self):
1075
    self.rapi.AddResponse("23681")
1076
    job_id = self.client.ModifyInstance("inst7210", os_name="linux")
1077
    self.assertEqual(job_id, 23681)
1078
    self.assertItems(["inst7210"])
1079
    self.assertHandler(rlib2.R_2_instances_name_modify)
1080
    self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
1081
                     { "os_name": "linux", })
1082

    
1083
  def testModifyCluster(self):
1084
    for mnh in [None, False, True]:
1085
      self.rapi.AddResponse("14470")
1086
      self.assertEqual(14470,
1087
        self.client.ModifyCluster(maintain_node_health=mnh))
1088
      self.assertHandler(rlib2.R_2_cluster_modify)
1089
      self.assertItems([])
1090
      data = serializer.LoadJson(self.rapi.GetLastRequestData())
1091
      self.assertEqual(len(data), 1)
1092
      self.assertEqual(data["maintain_node_health"], mnh)
1093
      self.assertEqual(self.rapi.CountPending(), 0)
1094

    
1095
  def testRedistributeConfig(self):
1096
    self.rapi.AddResponse("3364")
1097
    job_id = self.client.RedistributeConfig()
1098
    self.assertEqual(job_id, 3364)
1099
    self.assertItems([])
1100
    self.assertHandler(rlib2.R_2_redist_config)
1101

    
1102
  def testActivateInstanceDisks(self):
1103
    self.rapi.AddResponse("23547")
1104
    job_id = self.client.ActivateInstanceDisks("inst28204")
1105
    self.assertEqual(job_id, 23547)
1106
    self.assertItems(["inst28204"])
1107
    self.assertHandler(rlib2.R_2_instances_name_activate_disks)
1108
    self.assertFalse(self.rapi.GetLastHandler().queryargs)
1109

    
1110
  def testActivateInstanceDisksIgnoreSize(self):
1111
    self.rapi.AddResponse("11044")
1112
    job_id = self.client.ActivateInstanceDisks("inst28204", ignore_size=True)
1113
    self.assertEqual(job_id, 11044)
1114
    self.assertItems(["inst28204"])
1115
    self.assertHandler(rlib2.R_2_instances_name_activate_disks)
1116
    self.assertQuery("ignore_size", ["1"])
1117

    
1118
  def testDeactivateInstanceDisks(self):
1119
    self.rapi.AddResponse("14591")
1120
    job_id = self.client.DeactivateInstanceDisks("inst28234")
1121
    self.assertEqual(job_id, 14591)
1122
    self.assertItems(["inst28234"])
1123
    self.assertHandler(rlib2.R_2_instances_name_deactivate_disks)
1124
    self.assertFalse(self.rapi.GetLastHandler().queryargs)
1125

    
1126
  def testGetInstanceConsole(self):
1127
    self.rapi.AddResponse("26876")
1128
    job_id = self.client.GetInstanceConsole("inst21491")
1129
    self.assertEqual(job_id, 26876)
1130
    self.assertItems(["inst21491"])
1131
    self.assertHandler(rlib2.R_2_instances_name_console)
1132
    self.assertFalse(self.rapi.GetLastHandler().queryargs)
1133
    self.assertFalse(self.rapi.GetLastRequestData())
1134

    
1135
  def testGrowInstanceDisk(self):
1136
    for idx, wait_for_sync in enumerate([None, False, True]):
1137
      amount = 128 + (512 * idx)
1138
      self.assertEqual(self.rapi.CountPending(), 0)
1139
      self.rapi.AddResponse("30783")
1140
      self.assertEqual(30783,
1141
        self.client.GrowInstanceDisk("eze8ch", idx, amount,
1142
                                     wait_for_sync=wait_for_sync))
1143
      self.assertHandler(rlib2.R_2_instances_name_disk_grow)
1144
      self.assertItems(["eze8ch", str(idx)])
1145
      data = serializer.LoadJson(self.rapi.GetLastRequestData())
1146
      if wait_for_sync is None:
1147
        self.assertEqual(len(data), 1)
1148
        self.assert_("wait_for_sync" not in data)
1149
      else:
1150
        self.assertEqual(len(data), 2)
1151
        self.assertEqual(data["wait_for_sync"], wait_for_sync)
1152
      self.assertEqual(data["amount"], amount)
1153
      self.assertEqual(self.rapi.CountPending(), 0)
1154

    
1155

    
1156
class RapiTestRunner(unittest.TextTestRunner):
1157
  def run(self, *args):
1158
    global _used_handlers
1159
    assert _used_handlers is None
1160

    
1161
    _used_handlers = set()
1162
    try:
1163
      # Run actual tests
1164
      result = unittest.TextTestRunner.run(self, *args)
1165

    
1166
      diff = (set(connector.CONNECTOR.values()) - _used_handlers -
1167
             _KNOWN_UNUSED)
1168
      if diff:
1169
        raise AssertionError("The following RAPI resources were not used by the"
1170
                             " RAPI client: %r" % utils.CommaJoin(diff))
1171
    finally:
1172
      # Reset global variable
1173
      _used_handlers = None
1174

    
1175
    return result
1176

    
1177

    
1178
if __name__ == '__main__':
1179
  client.UsesRapiClient(testutils.GanetiTestProgram)(testRunner=RapiTestRunner)