Statistics
| Branch: | Tag: | Revision:

root / test / ganeti.rapi.client_unittest.py @ 208a6cff

History | View | Annotate | Download (44.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
from ganeti import query
35
from ganeti import objects
36

    
37
from ganeti.rapi import connector
38
from ganeti.rapi import rlib2
39
from ganeti.rapi import client
40

    
41
import testutils
42

    
43

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

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

    
52
# Global variable for collecting used handlers
53
_used_handlers = None
54

    
55

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

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

    
66

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

    
73
  def setopt(self, opt, value):
74
    self._opts[opt] = value
75

    
76
  def getopt(self, opt):
77
    return self._opts.get(opt)
78

    
79
  def unsetopt(self, opt):
80
    self._opts.pop(opt, None)
81

    
82
  def getinfo(self, info):
83
    return self._info[info]
84

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

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

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

    
98

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

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

    
109
  def CountPending(self):
110
    return len(self._responses)
111

    
112
  def GetLastHandler(self):
113
    return self._last_handler
114

    
115
  def GetLastRequestData(self):
116
    return self._last_req_data
117

    
118
  def FetchResponse(self, path, method, request_body):
119
    self._last_req_data = request_body
120

    
121
    try:
122
      (handler_cls, items, args) = self._mapper.getController(path)
123

    
124
      # Record handler as used
125
      _used_handlers.add(handler_cls)
126

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

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

    
138
      (code, response) = self._responses.pop()
139

    
140
    return code, response
141

    
142

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

    
153

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

    
167

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

    
172

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

    
177

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

    
182

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

    
187

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

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

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

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

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

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

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

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

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

    
243
  def testNoCertVerify(self):
244
    cfgfn = client.GenericCurlConfig()
245

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

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

    
255
  def testCertVerifyCurlBundle(self):
256
    cfgfn = client.GenericCurlConfig(use_curl_cabundle=True)
257

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

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

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

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

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

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

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

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

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

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

    
305
    self.assertRaises(client.Error, cl._CreateCurl)
306

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

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

    
317
    self.assertRaises(client.Error, cl._CreateCurl)
318

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

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

    
329
    self.assertRaises(NotImplementedError, cl._CreateCurl)
330

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

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

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

    
345

    
346
class GanetiRapiClientTests(testutils.GanetiTestCase):
347
  def setUp(self):
348
    testutils.GanetiTestCase.setUp(self)
349

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

    
355
  def assertHandler(self, handler_cls):
356
    self.failUnless(isinstance(self.rapi.GetLastHandler(), handler_cls))
357

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

    
361
  def assertItems(self, items):
362
    self.assertEqual(items, self.rapi.GetLastHandler().items)
363

    
364
  def assertBulk(self):
365
    self.assertTrue(self.rapi.GetLastHandler().useBulk())
366

    
367
  def assertDryRun(self):
368
    self.assertTrue(self.rapi.GetLastHandler().dryRun())
369

    
370
  def assertUseForce(self):
371
    self.assertTrue(self.rapi.GetLastHandler().useForce())
372

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

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

    
390
    self.assertEqualValues(self.client._EncodeQuery(query),
391
                           expected)
392

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
595
    data = serializer.LoadJson(self.rapi.GetLastRequestData())
596

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
785
    data = serializer.LoadJson(self.rapi.GetLastRequestData())
786
    self.assertFalse(data)
787

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1157
  def testQuery(self):
1158
    for idx, what in enumerate(constants.QR_VIA_RAPI):
1159
      for idx2, filter_ in enumerate([None, ["?", "name"]]):
1160
        job_id = 11010 + (idx << 4) + (idx2 << 16)
1161
        fields = sorted(query.ALL_FIELDS[what].keys())[:10]
1162

    
1163
        self.rapi.AddResponse(str(job_id))
1164
        self.assertEqual(self.client.Query(what, fields, filter_=filter_),
1165
                         job_id)
1166
        self.assertItems([what])
1167
        self.assertHandler(rlib2.R_2_query)
1168
        self.assertFalse(self.rapi.GetLastHandler().queryargs)
1169
        data = serializer.LoadJson(self.rapi.GetLastRequestData())
1170
        self.assertEqual(data["fields"], fields)
1171
        if filter_ is None:
1172
          self.assertTrue("filter" not in data)
1173
        else:
1174
          self.assertEqual(data["filter"], filter_)
1175
        self.assertEqual(self.rapi.CountPending(), 0)
1176

    
1177
  def testQueryFields(self):
1178
    exp_result = objects.QueryFieldsResponse(fields=[
1179
      objects.QueryFieldDefinition(name="pnode", title="PNode",
1180
                                   kind=constants.QFT_NUMBER),
1181
      objects.QueryFieldDefinition(name="other", title="Other",
1182
                                   kind=constants.QFT_BOOL),
1183
      ])
1184

    
1185
    for what in constants.QR_VIA_RAPI:
1186
      for fields in [None, ["name", "_unknown_"], ["&", "?|"]]:
1187
        self.rapi.AddResponse(serializer.DumpJson(exp_result.ToDict()))
1188
        result = self.client.QueryFields(what, fields=fields)
1189
        self.assertItems([what])
1190
        self.assertHandler(rlib2.R_2_query_fields)
1191
        self.assertFalse(self.rapi.GetLastRequestData())
1192

    
1193
        queryargs = self.rapi.GetLastHandler().queryargs
1194
        if fields is None:
1195
          self.assertFalse(queryargs)
1196
        else:
1197
          self.assertEqual(queryargs, {
1198
            "fields": [",".join(fields)],
1199
            })
1200

    
1201
        self.assertEqual(objects.QueryFieldsResponse.FromDict(result).ToDict(),
1202
                         exp_result.ToDict())
1203

    
1204
        self.assertEqual(self.rapi.CountPending(), 0)
1205

    
1206

    
1207
class RapiTestRunner(unittest.TextTestRunner):
1208
  def run(self, *args):
1209
    global _used_handlers
1210
    assert _used_handlers is None
1211

    
1212
    _used_handlers = set()
1213
    try:
1214
      # Run actual tests
1215
      result = unittest.TextTestRunner.run(self, *args)
1216

    
1217
      diff = (set(connector.CONNECTOR.values()) - _used_handlers -
1218
             _KNOWN_UNUSED)
1219
      if diff:
1220
        raise AssertionError("The following RAPI resources were not used by the"
1221
                             " RAPI client: %r" % utils.CommaJoin(diff))
1222
    finally:
1223
      # Reset global variable
1224
      _used_handlers = None
1225

    
1226
    return result
1227

    
1228

    
1229
if __name__ == '__main__':
1230
  client.UsesRapiClient(testutils.GanetiTestProgram)(testRunner=RapiTestRunner)