Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (47.4 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 ResetResponses(self):
107
    del self._responses[:]
108

    
109
  def AddResponse(self, response, code=200):
110
    self._responses.insert(0, (code, response))
111

    
112
  def CountPending(self):
113
    return len(self._responses)
114

    
115
  def GetLastHandler(self):
116
    return self._last_handler
117

    
118
  def GetLastRequestData(self):
119
    return self._last_req_data
120

    
121
  def FetchResponse(self, path, method, request_body):
122
    self._last_req_data = request_body
123

    
124
    try:
125
      (handler_cls, items, args) = self._mapper.getController(path)
126

    
127
      # Record handler as used
128
      _used_handlers.add(handler_cls)
129

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

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

    
141
      (code, response) = self._responses.pop()
142

    
143
    return code, response
144

    
145

    
146
class TestConstants(unittest.TestCase):
147
  def test(self):
148
    self.assertEqual(client.GANETI_RAPI_PORT, constants.DEFAULT_RAPI_PORT)
149
    self.assertEqual(client.GANETI_RAPI_VERSION, constants.RAPI_VERSION)
150
    self.assertEqual(client.HTTP_APP_JSON, http.HTTP_APP_JSON)
151
    self.assertEqual(client._REQ_DATA_VERSION_FIELD, rlib2._REQ_DATA_VERSION)
152
    self.assertEqual(client._INST_CREATE_REQV1, rlib2._INST_CREATE_REQV1)
153
    self.assertEqual(client._INST_REINSTALL_REQV1, rlib2._INST_REINSTALL_REQV1)
154
    self.assertEqual(client._NODE_MIGRATE_REQV1, rlib2._NODE_MIGRATE_REQV1)
155
    self.assertEqual(client._INST_NIC_PARAMS, constants.INIC_PARAMS)
156
    self.assertEqual(client.JOB_STATUS_QUEUED, constants.JOB_STATUS_QUEUED)
157
    self.assertEqual(client.JOB_STATUS_WAITLOCK, constants.JOB_STATUS_WAITLOCK)
158
    self.assertEqual(client.JOB_STATUS_CANCELING,
159
                     constants.JOB_STATUS_CANCELING)
160
    self.assertEqual(client.JOB_STATUS_RUNNING, constants.JOB_STATUS_RUNNING)
161
    self.assertEqual(client.JOB_STATUS_CANCELED, constants.JOB_STATUS_CANCELED)
162
    self.assertEqual(client.JOB_STATUS_SUCCESS, constants.JOB_STATUS_SUCCESS)
163
    self.assertEqual(client.JOB_STATUS_ERROR, constants.JOB_STATUS_ERROR)
164
    self.assertEqual(client.JOB_STATUS_FINALIZED, constants.JOBS_FINALIZED)
165
    self.assertEqual(client.JOB_STATUS_ALL, constants.JOB_STATUS_ALL)
166

    
167

    
168
class RapiMockTest(unittest.TestCase):
169
  def test(self):
170
    rapi = RapiMock()
171
    path = "/version"
172
    self.assertEqual((404, None), rapi.FetchResponse("/foo", "GET", None))
173
    self.assertEqual((501, "Method not implemented"),
174
                     rapi.FetchResponse("/version", "POST", None))
175
    rapi.AddResponse("2")
176
    code, response = rapi.FetchResponse("/version", "GET", None)
177
    self.assertEqual(200, code)
178
    self.assertEqual("2", response)
179
    self.failUnless(isinstance(rapi.GetLastHandler(), rlib2.R_version))
180

    
181

    
182
def _FakeNoSslPycurlVersion():
183
  # Note: incomplete version tuple
184
  return (3, "7.16.0", 462848, "mysystem", 1581, None, 0)
185

    
186

    
187
def _FakeFancySslPycurlVersion():
188
  # Note: incomplete version tuple
189
  return (3, "7.16.0", 462848, "mysystem", 1581, "FancySSL/1.2.3", 0)
190

    
191

    
192
def _FakeOpenSslPycurlVersion():
193
  # Note: incomplete version tuple
194
  return (2, "7.15.5", 462597, "othersystem", 668, "OpenSSL/0.9.8c", 0)
195

    
196

    
197
def _FakeGnuTlsPycurlVersion():
198
  # Note: incomplete version tuple
199
  return (3, "7.18.0", 463360, "somesystem", 1581, "GnuTLS/2.0.4", 0)
200

    
201

    
202
class TestExtendedConfig(unittest.TestCase):
203
  def testAuth(self):
204
    cl = client.GanetiRapiClient("master.example.com",
205
                                 username="user", password="pw",
206
                                 curl_factory=lambda: FakeCurl(RapiMock()))
207

    
208
    curl = cl._CreateCurl()
209
    self.assertEqual(curl.getopt(pycurl.HTTPAUTH), pycurl.HTTPAUTH_BASIC)
210
    self.assertEqual(curl.getopt(pycurl.USERPWD), "user:pw")
211

    
212
  def testInvalidAuth(self):
213
    # No username
214
    self.assertRaises(client.Error, client.GanetiRapiClient,
215
                      "master-a.example.com", password="pw")
216
    # No password
217
    self.assertRaises(client.Error, client.GanetiRapiClient,
218
                      "master-b.example.com", username="user")
219

    
220
  def testCertVerifyInvalidCombinations(self):
221
    self.assertRaises(client.Error, client.GenericCurlConfig,
222
                      use_curl_cabundle=True, cafile="cert1.pem")
223
    self.assertRaises(client.Error, client.GenericCurlConfig,
224
                      use_curl_cabundle=True, capath="certs/")
225
    self.assertRaises(client.Error, client.GenericCurlConfig,
226
                      use_curl_cabundle=True,
227
                      cafile="cert1.pem", capath="certs/")
228

    
229
  def testProxySignalVerifyHostname(self):
230
    for use_gnutls in [False, True]:
231
      if use_gnutls:
232
        pcverfn = _FakeGnuTlsPycurlVersion
233
      else:
234
        pcverfn = _FakeOpenSslPycurlVersion
235

    
236
      for proxy in ["", "http://127.0.0.1:1234"]:
237
        for use_signal in [False, True]:
238
          for verify_hostname in [False, True]:
239
            cfgfn = client.GenericCurlConfig(proxy=proxy, use_signal=use_signal,
240
                                             verify_hostname=verify_hostname,
241
                                             _pycurl_version_fn=pcverfn)
242

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

    
248
            curl = cl._CreateCurl()
249
            self.assertEqual(curl.getopt(pycurl.PROXY), proxy)
250
            self.assertEqual(curl.getopt(pycurl.NOSIGNAL), not use_signal)
251

    
252
            if verify_hostname:
253
              self.assertEqual(curl.getopt(pycurl.SSL_VERIFYHOST), 2)
254
            else:
255
              self.assertEqual(curl.getopt(pycurl.SSL_VERIFYHOST), 0)
256

    
257
  def testNoCertVerify(self):
258
    cfgfn = client.GenericCurlConfig()
259

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

    
264
    curl = cl._CreateCurl()
265
    self.assertFalse(curl.getopt(pycurl.SSL_VERIFYPEER))
266
    self.assertFalse(curl.getopt(pycurl.CAINFO))
267
    self.assertFalse(curl.getopt(pycurl.CAPATH))
268

    
269
  def testCertVerifyCurlBundle(self):
270
    cfgfn = client.GenericCurlConfig(use_curl_cabundle=True)
271

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

    
276
    curl = cl._CreateCurl()
277
    self.assert_(curl.getopt(pycurl.SSL_VERIFYPEER))
278
    self.assertFalse(curl.getopt(pycurl.CAINFO))
279
    self.assertFalse(curl.getopt(pycurl.CAPATH))
280

    
281
  def testCertVerifyCafile(self):
282
    mycert = "/tmp/some/UNUSED/cert/file.pem"
283
    cfgfn = client.GenericCurlConfig(cafile=mycert)
284

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

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

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

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

    
304
    curl = cl._CreateCurl()
305
    self.assert_(curl.getopt(pycurl.SSL_VERIFYPEER))
306
    self.assertEqual(curl.getopt(pycurl.CAPATH), certdir)
307
    self.assertFalse(curl.getopt(pycurl.CAINFO))
308

    
309
  def testCertVerifyCapathGnuTls(self):
310
    certdir = "/tmp/some/UNUSED/cert/directory"
311
    pcverfn = _FakeGnuTlsPycurlVersion
312
    cfgfn = client.GenericCurlConfig(capath=certdir,
313
                                     _pycurl_version_fn=pcverfn)
314

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

    
319
    self.assertRaises(client.Error, cl._CreateCurl)
320

    
321
  def testCertVerifyNoSsl(self):
322
    certdir = "/tmp/some/UNUSED/cert/directory"
323
    pcverfn = _FakeNoSslPycurlVersion
324
    cfgfn = client.GenericCurlConfig(capath=certdir,
325
                                     _pycurl_version_fn=pcverfn)
326

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

    
331
    self.assertRaises(client.Error, cl._CreateCurl)
332

    
333
  def testCertVerifyFancySsl(self):
334
    certdir = "/tmp/some/UNUSED/cert/directory"
335
    pcverfn = _FakeFancySslPycurlVersion
336
    cfgfn = client.GenericCurlConfig(capath=certdir,
337
                                     _pycurl_version_fn=pcverfn)
338

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

    
343
    self.assertRaises(NotImplementedError, cl._CreateCurl)
344

    
345
  def testCertVerifyCapath(self):
346
    for connect_timeout in [None, 1, 5, 10, 30, 60, 300]:
347
      for timeout in [None, 1, 30, 60, 3600, 24 * 3600]:
348
        cfgfn = client.GenericCurlConfig(connect_timeout=connect_timeout,
349
                                         timeout=timeout)
350

    
351
        curl_factory = lambda: FakeCurl(RapiMock())
352
        cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
353
                                     curl_factory=curl_factory)
354

    
355
        curl = cl._CreateCurl()
356
        self.assertEqual(curl.getopt(pycurl.CONNECTTIMEOUT), connect_timeout)
357
        self.assertEqual(curl.getopt(pycurl.TIMEOUT), timeout)
358

    
359

    
360
class GanetiRapiClientTests(testutils.GanetiTestCase):
361
  def setUp(self):
362
    testutils.GanetiTestCase.setUp(self)
363

    
364
    self.rapi = RapiMock()
365
    self.curl = FakeCurl(self.rapi)
366
    self.client = client.GanetiRapiClient("master.example.com",
367
                                          curl_factory=lambda: self.curl)
368

    
369
  def assertHandler(self, handler_cls):
370
    self.failUnless(isinstance(self.rapi.GetLastHandler(), handler_cls))
371

    
372
  def assertQuery(self, key, value):
373
    self.assertEqual(value, self.rapi.GetLastHandler().queryargs.get(key, None))
374

    
375
  def assertItems(self, items):
376
    self.assertEqual(items, self.rapi.GetLastHandler().items)
377

    
378
  def assertBulk(self):
379
    self.assertTrue(self.rapi.GetLastHandler().useBulk())
380

    
381
  def assertDryRun(self):
382
    self.assertTrue(self.rapi.GetLastHandler().dryRun())
383

    
384
  def assertUseForce(self):
385
    self.assertTrue(self.rapi.GetLastHandler().useForce())
386

    
387
  def testEncodeQuery(self):
388
    query = [
389
      ("a", None),
390
      ("b", 1),
391
      ("c", 2),
392
      ("d", "Foo"),
393
      ("e", True),
394
      ]
395

    
396
    expected = [
397
      ("a", ""),
398
      ("b", 1),
399
      ("c", 2),
400
      ("d", "Foo"),
401
      ("e", 1),
402
      ]
403

    
404
    self.assertEqualValues(self.client._EncodeQuery(query),
405
                           expected)
406

    
407
    # invalid types
408
    for i in [[1, 2, 3], {"moo": "boo"}, (1, 2, 3)]:
409
      self.assertRaises(ValueError, self.client._EncodeQuery, [("x", i)])
410

    
411
  def testCurlSettings(self):
412
    self.rapi.AddResponse("2")
413
    self.assertEqual(2, self.client.GetVersion())
414
    self.assertHandler(rlib2.R_version)
415

    
416
    # Signals should be disabled by default
417
    self.assert_(self.curl.getopt(pycurl.NOSIGNAL))
418

    
419
    # No auth and no proxy
420
    self.assertFalse(self.curl.getopt(pycurl.USERPWD))
421
    self.assert_(self.curl.getopt(pycurl.PROXY) is None)
422

    
423
    # Content-type is required for requests
424
    headers = self.curl.getopt(pycurl.HTTPHEADER)
425
    self.assert_("Content-type: application/json" in headers)
426

    
427
  def testHttpError(self):
428
    self.rapi.AddResponse(None, code=404)
429
    try:
430
      self.client.GetJobStatus(15140)
431
    except client.GanetiApiError, err:
432
      self.assertEqual(err.code, 404)
433
    else:
434
      self.fail("Didn't raise exception")
435

    
436
  def testGetVersion(self):
437
    self.rapi.AddResponse("2")
438
    self.assertEqual(2, self.client.GetVersion())
439
    self.assertHandler(rlib2.R_version)
440

    
441
  def testGetFeatures(self):
442
    for features in [[], ["foo", "bar", "baz"]]:
443
      self.rapi.AddResponse(serializer.DumpJson(features))
444
      self.assertEqual(features, self.client.GetFeatures())
445
      self.assertHandler(rlib2.R_2_features)
446

    
447
  def testGetFeaturesNotFound(self):
448
    self.rapi.AddResponse(None, code=404)
449
    self.assertEqual([], self.client.GetFeatures())
450

    
451
  def testGetOperatingSystems(self):
452
    self.rapi.AddResponse("[\"beos\"]")
453
    self.assertEqual(["beos"], self.client.GetOperatingSystems())
454
    self.assertHandler(rlib2.R_2_os)
455

    
456
  def testGetClusterTags(self):
457
    self.rapi.AddResponse("[\"tag\"]")
458
    self.assertEqual(["tag"], self.client.GetClusterTags())
459
    self.assertHandler(rlib2.R_2_tags)
460

    
461
  def testAddClusterTags(self):
462
    self.rapi.AddResponse("1234")
463
    self.assertEqual(1234,
464
        self.client.AddClusterTags(["awesome"], dry_run=True))
465
    self.assertHandler(rlib2.R_2_tags)
466
    self.assertDryRun()
467
    self.assertQuery("tag", ["awesome"])
468

    
469
  def testDeleteClusterTags(self):
470
    self.rapi.AddResponse("5107")
471
    self.assertEqual(5107, self.client.DeleteClusterTags(["awesome"],
472
                                                         dry_run=True))
473
    self.assertHandler(rlib2.R_2_tags)
474
    self.assertDryRun()
475
    self.assertQuery("tag", ["awesome"])
476

    
477
  def testGetInfo(self):
478
    self.rapi.AddResponse("{}")
479
    self.assertEqual({}, self.client.GetInfo())
480
    self.assertHandler(rlib2.R_2_info)
481

    
482
  def testGetInstances(self):
483
    self.rapi.AddResponse("[]")
484
    self.assertEqual([], self.client.GetInstances(bulk=True))
485
    self.assertHandler(rlib2.R_2_instances)
486
    self.assertBulk()
487

    
488
  def testGetInstance(self):
489
    self.rapi.AddResponse("[]")
490
    self.assertEqual([], self.client.GetInstance("instance"))
491
    self.assertHandler(rlib2.R_2_instances_name)
492
    self.assertItems(["instance"])
493

    
494
  def testGetInstanceInfo(self):
495
    self.rapi.AddResponse("21291")
496
    self.assertEqual(21291, self.client.GetInstanceInfo("inst3"))
497
    self.assertHandler(rlib2.R_2_instances_name_info)
498
    self.assertItems(["inst3"])
499
    self.assertQuery("static", None)
500

    
501
    self.rapi.AddResponse("3428")
502
    self.assertEqual(3428, self.client.GetInstanceInfo("inst31", static=False))
503
    self.assertHandler(rlib2.R_2_instances_name_info)
504
    self.assertItems(["inst31"])
505
    self.assertQuery("static", ["0"])
506

    
507
    self.rapi.AddResponse("15665")
508
    self.assertEqual(15665, self.client.GetInstanceInfo("inst32", static=True))
509
    self.assertHandler(rlib2.R_2_instances_name_info)
510
    self.assertItems(["inst32"])
511
    self.assertQuery("static", ["1"])
512

    
513
  def testCreateInstanceOldVersion(self):
514
    # The old request format, version 0, is no longer supported
515
    self.rapi.AddResponse(None, code=404)
516
    self.assertRaises(client.GanetiApiError, self.client.CreateInstance,
517
                      "create", "inst1.example.com", "plain", [], [])
518
    self.assertEqual(self.rapi.CountPending(), 0)
519

    
520
  def testCreateInstance(self):
521
    self.rapi.AddResponse(serializer.DumpJson([rlib2._INST_CREATE_REQV1]))
522
    self.rapi.AddResponse("23030")
523
    job_id = self.client.CreateInstance("create", "inst1.example.com",
524
                                        "plain", [], [], dry_run=True)
525
    self.assertEqual(job_id, 23030)
526
    self.assertHandler(rlib2.R_2_instances)
527
    self.assertDryRun()
528

    
529
    data = serializer.LoadJson(self.rapi.GetLastRequestData())
530

    
531
    for field in ["dry_run", "beparams", "hvparams", "start"]:
532
      self.assertFalse(field in data)
533

    
534
    self.assertEqual(data["name"], "inst1.example.com")
535
    self.assertEqual(data["disk_template"], "plain")
536

    
537
  def testCreateInstance2(self):
538
    self.rapi.AddResponse(serializer.DumpJson([rlib2._INST_CREATE_REQV1]))
539
    self.rapi.AddResponse("24740")
540
    job_id = self.client.CreateInstance("import", "inst2.example.com",
541
                                        "drbd8", [{"size": 100,}],
542
                                        [{}, {"bridge": "br1", }],
543
                                        dry_run=False, start=True,
544
                                        pnode="node1", snode="node9",
545
                                        ip_check=False)
546
    self.assertEqual(job_id, 24740)
547
    self.assertHandler(rlib2.R_2_instances)
548

    
549
    data = serializer.LoadJson(self.rapi.GetLastRequestData())
550
    self.assertEqual(data[rlib2._REQ_DATA_VERSION], 1)
551
    self.assertEqual(data["name"], "inst2.example.com")
552
    self.assertEqual(data["disk_template"], "drbd8")
553
    self.assertEqual(data["start"], True)
554
    self.assertEqual(data["ip_check"], False)
555
    self.assertEqualValues(data["disks"], [{"size": 100,}])
556
    self.assertEqualValues(data["nics"], [{}, {"bridge": "br1", }])
557

    
558
  def testDeleteInstance(self):
559
    self.rapi.AddResponse("1234")
560
    self.assertEqual(1234, self.client.DeleteInstance("instance", dry_run=True))
561
    self.assertHandler(rlib2.R_2_instances_name)
562
    self.assertItems(["instance"])
563
    self.assertDryRun()
564

    
565
  def testGetInstanceTags(self):
566
    self.rapi.AddResponse("[]")
567
    self.assertEqual([], self.client.GetInstanceTags("fooinstance"))
568
    self.assertHandler(rlib2.R_2_instances_name_tags)
569
    self.assertItems(["fooinstance"])
570

    
571
  def testAddInstanceTags(self):
572
    self.rapi.AddResponse("1234")
573
    self.assertEqual(1234,
574
        self.client.AddInstanceTags("fooinstance", ["awesome"], dry_run=True))
575
    self.assertHandler(rlib2.R_2_instances_name_tags)
576
    self.assertItems(["fooinstance"])
577
    self.assertDryRun()
578
    self.assertQuery("tag", ["awesome"])
579

    
580
  def testDeleteInstanceTags(self):
581
    self.rapi.AddResponse("25826")
582
    self.assertEqual(25826, self.client.DeleteInstanceTags("foo", ["awesome"],
583
                                                           dry_run=True))
584
    self.assertHandler(rlib2.R_2_instances_name_tags)
585
    self.assertItems(["foo"])
586
    self.assertDryRun()
587
    self.assertQuery("tag", ["awesome"])
588

    
589
  def testRebootInstance(self):
590
    self.rapi.AddResponse("6146")
591
    job_id = self.client.RebootInstance("i-bar", reboot_type="hard",
592
                                        ignore_secondaries=True, dry_run=True)
593
    self.assertEqual(6146, job_id)
594
    self.assertHandler(rlib2.R_2_instances_name_reboot)
595
    self.assertItems(["i-bar"])
596
    self.assertDryRun()
597
    self.assertQuery("type", ["hard"])
598
    self.assertQuery("ignore_secondaries", ["1"])
599

    
600
  def testShutdownInstance(self):
601
    self.rapi.AddResponse("1487")
602
    self.assertEqual(1487, self.client.ShutdownInstance("foo-instance",
603
                                                        dry_run=True))
604
    self.assertHandler(rlib2.R_2_instances_name_shutdown)
605
    self.assertItems(["foo-instance"])
606
    self.assertDryRun()
607

    
608
  def testStartupInstance(self):
609
    self.rapi.AddResponse("27149")
610
    self.assertEqual(27149, self.client.StartupInstance("bar-instance",
611
                                                        dry_run=True))
612
    self.assertHandler(rlib2.R_2_instances_name_startup)
613
    self.assertItems(["bar-instance"])
614
    self.assertDryRun()
615

    
616
  def testReinstallInstance(self):
617
    self.rapi.AddResponse(serializer.DumpJson([]))
618
    self.rapi.AddResponse("19119")
619
    self.assertEqual(19119, self.client.ReinstallInstance("baz-instance",
620
                                                          os="DOS",
621
                                                          no_startup=True))
622
    self.assertHandler(rlib2.R_2_instances_name_reinstall)
623
    self.assertItems(["baz-instance"])
624
    self.assertQuery("os", ["DOS"])
625
    self.assertQuery("nostartup", ["1"])
626
    self.assertEqual(self.rapi.CountPending(), 0)
627

    
628
  def testReinstallInstanceNew(self):
629
    self.rapi.AddResponse(serializer.DumpJson([rlib2._INST_REINSTALL_REQV1]))
630
    self.rapi.AddResponse("25689")
631
    self.assertEqual(25689, self.client.ReinstallInstance("moo-instance",
632
                                                          os="Debian",
633
                                                          no_startup=True))
634
    self.assertHandler(rlib2.R_2_instances_name_reinstall)
635
    self.assertItems(["moo-instance"])
636
    data = serializer.LoadJson(self.rapi.GetLastRequestData())
637
    self.assertEqual(len(data), 2)
638
    self.assertEqual(data["os"], "Debian")
639
    self.assertEqual(data["start"], False)
640
    self.assertEqual(self.rapi.CountPending(), 0)
641

    
642
  def testReinstallInstanceWithOsparams1(self):
643
    self.rapi.AddResponse(serializer.DumpJson([]))
644
    self.assertRaises(client.GanetiApiError, self.client.ReinstallInstance,
645
                      "doo-instance", osparams={"x": "y"})
646
    self.assertEqual(self.rapi.CountPending(), 0)
647

    
648
  def testReinstallInstanceWithOsparams2(self):
649
    osparams = {
650
      "Hello": "World",
651
      "foo": "bar",
652
      }
653
    self.rapi.AddResponse(serializer.DumpJson([rlib2._INST_REINSTALL_REQV1]))
654
    self.rapi.AddResponse("1717")
655
    self.assertEqual(1717, self.client.ReinstallInstance("zoo-instance",
656
                                                         osparams=osparams))
657
    self.assertHandler(rlib2.R_2_instances_name_reinstall)
658
    self.assertItems(["zoo-instance"])
659
    data = serializer.LoadJson(self.rapi.GetLastRequestData())
660
    self.assertEqual(len(data), 2)
661
    self.assertEqual(data["osparams"], osparams)
662
    self.assertEqual(data["start"], True)
663
    self.assertEqual(self.rapi.CountPending(), 0)
664

    
665
  def testReplaceInstanceDisks(self):
666
    self.rapi.AddResponse("999")
667
    job_id = self.client.ReplaceInstanceDisks("instance-name",
668
        disks=[0, 1], dry_run=True, iallocator="hail")
669
    self.assertEqual(999, job_id)
670
    self.assertHandler(rlib2.R_2_instances_name_replace_disks)
671
    self.assertItems(["instance-name"])
672
    self.assertQuery("disks", ["0,1"])
673
    self.assertQuery("mode", ["replace_auto"])
674
    self.assertQuery("iallocator", ["hail"])
675
    self.assertDryRun()
676

    
677
    self.rapi.AddResponse("1000")
678
    job_id = self.client.ReplaceInstanceDisks("instance-bar",
679
        disks=[1], mode="replace_on_secondary", remote_node="foo-node",
680
        dry_run=True)
681
    self.assertEqual(1000, job_id)
682
    self.assertItems(["instance-bar"])
683
    self.assertQuery("disks", ["1"])
684
    self.assertQuery("remote_node", ["foo-node"])
685
    self.assertDryRun()
686

    
687
    self.rapi.AddResponse("5175")
688
    self.assertEqual(5175, self.client.ReplaceInstanceDisks("instance-moo"))
689
    self.assertItems(["instance-moo"])
690
    self.assertQuery("disks", None)
691

    
692
  def testPrepareExport(self):
693
    self.rapi.AddResponse("8326")
694
    self.assertEqual(8326, self.client.PrepareExport("inst1", "local"))
695
    self.assertHandler(rlib2.R_2_instances_name_prepare_export)
696
    self.assertItems(["inst1"])
697
    self.assertQuery("mode", ["local"])
698

    
699
  def testExportInstance(self):
700
    self.rapi.AddResponse("19695")
701
    job_id = self.client.ExportInstance("inst2", "local", "nodeX",
702
                                        shutdown=True)
703
    self.assertEqual(job_id, 19695)
704
    self.assertHandler(rlib2.R_2_instances_name_export)
705
    self.assertItems(["inst2"])
706

    
707
    data = serializer.LoadJson(self.rapi.GetLastRequestData())
708
    self.assertEqual(data["mode"], "local")
709
    self.assertEqual(data["destination"], "nodeX")
710
    self.assertEqual(data["shutdown"], True)
711

    
712
  def testMigrateInstanceDefaults(self):
713
    self.rapi.AddResponse("24873")
714
    job_id = self.client.MigrateInstance("inst91")
715
    self.assertEqual(job_id, 24873)
716
    self.assertHandler(rlib2.R_2_instances_name_migrate)
717
    self.assertItems(["inst91"])
718

    
719
    data = serializer.LoadJson(self.rapi.GetLastRequestData())
720
    self.assertFalse(data)
721

    
722
  def testMigrateInstance(self):
723
    for mode in constants.HT_MIGRATION_MODES:
724
      for cleanup in [False, True]:
725
        self.rapi.AddResponse("31910")
726
        job_id = self.client.MigrateInstance("inst289", mode=mode,
727
                                             cleanup=cleanup)
728
        self.assertEqual(job_id, 31910)
729
        self.assertHandler(rlib2.R_2_instances_name_migrate)
730
        self.assertItems(["inst289"])
731

    
732
        data = serializer.LoadJson(self.rapi.GetLastRequestData())
733
        self.assertEqual(len(data), 2)
734
        self.assertEqual(data["mode"], mode)
735
        self.assertEqual(data["cleanup"], cleanup)
736

    
737
  def testRenameInstanceDefaults(self):
738
    new_name = "newnametha7euqu"
739
    self.rapi.AddResponse("8791")
740
    job_id = self.client.RenameInstance("inst18821", new_name)
741
    self.assertEqual(job_id, 8791)
742
    self.assertHandler(rlib2.R_2_instances_name_rename)
743
    self.assertItems(["inst18821"])
744

    
745
    data = serializer.LoadJson(self.rapi.GetLastRequestData())
746
    self.assertEqualValues(data, {"new_name": new_name, })
747

    
748
  def testRenameInstance(self):
749
    new_name = "new-name-yiux1iin"
750
    for ip_check in [False, True]:
751
      for name_check in [False, True]:
752
        self.rapi.AddResponse("24776")
753
        job_id = self.client.RenameInstance("inst20967", new_name,
754
                                             ip_check=ip_check,
755
                                             name_check=name_check)
756
        self.assertEqual(job_id, 24776)
757
        self.assertHandler(rlib2.R_2_instances_name_rename)
758
        self.assertItems(["inst20967"])
759

    
760
        data = serializer.LoadJson(self.rapi.GetLastRequestData())
761
        self.assertEqual(len(data), 3)
762
        self.assertEqual(data["new_name"], new_name)
763
        self.assertEqual(data["ip_check"], ip_check)
764
        self.assertEqual(data["name_check"], name_check)
765

    
766
  def testGetJobs(self):
767
    self.rapi.AddResponse('[ { "id": "123", "uri": "\\/2\\/jobs\\/123" },'
768
                          '  { "id": "124", "uri": "\\/2\\/jobs\\/124" } ]')
769
    self.assertEqual([123, 124], self.client.GetJobs())
770
    self.assertHandler(rlib2.R_2_jobs)
771

    
772
  def testGetJobStatus(self):
773
    self.rapi.AddResponse("{\"foo\": \"bar\"}")
774
    self.assertEqual({"foo": "bar"}, self.client.GetJobStatus(1234))
775
    self.assertHandler(rlib2.R_2_jobs_id)
776
    self.assertItems(["1234"])
777

    
778
  def testWaitForJobChange(self):
779
    fields = ["id", "summary"]
780
    expected = {
781
      "job_info": [123, "something"],
782
      "log_entries": [],
783
      }
784

    
785
    self.rapi.AddResponse(serializer.DumpJson(expected))
786
    result = self.client.WaitForJobChange(123, fields, [], -1)
787
    self.assertEqualValues(expected, result)
788
    self.assertHandler(rlib2.R_2_jobs_id_wait)
789
    self.assertItems(["123"])
790

    
791
  def testCancelJob(self):
792
    self.rapi.AddResponse("[true, \"Job 123 will be canceled\"]")
793
    self.assertEqual([True, "Job 123 will be canceled"],
794
                     self.client.CancelJob(999, dry_run=True))
795
    self.assertHandler(rlib2.R_2_jobs_id)
796
    self.assertItems(["999"])
797
    self.assertDryRun()
798

    
799
  def testGetNodes(self):
800
    self.rapi.AddResponse("[ { \"id\": \"node1\", \"uri\": \"uri1\" },"
801
                          " { \"id\": \"node2\", \"uri\": \"uri2\" } ]")
802
    self.assertEqual(["node1", "node2"], self.client.GetNodes())
803
    self.assertHandler(rlib2.R_2_nodes)
804

    
805
    self.rapi.AddResponse("[ { \"id\": \"node1\", \"uri\": \"uri1\" },"
806
                          " { \"id\": \"node2\", \"uri\": \"uri2\" } ]")
807
    self.assertEqual([{"id": "node1", "uri": "uri1"},
808
                      {"id": "node2", "uri": "uri2"}],
809
                     self.client.GetNodes(bulk=True))
810
    self.assertHandler(rlib2.R_2_nodes)
811
    self.assertBulk()
812

    
813
  def testGetNode(self):
814
    self.rapi.AddResponse("{}")
815
    self.assertEqual({}, self.client.GetNode("node-foo"))
816
    self.assertHandler(rlib2.R_2_nodes_name)
817
    self.assertItems(["node-foo"])
818

    
819
  def testEvacuateNode(self):
820
    self.rapi.AddResponse("9876")
821
    job_id = self.client.EvacuateNode("node-1", remote_node="node-2")
822
    self.assertEqual(9876, job_id)
823
    self.assertHandler(rlib2.R_2_nodes_name_evacuate)
824
    self.assertItems(["node-1"])
825
    self.assertQuery("remote_node", ["node-2"])
826

    
827
    self.rapi.AddResponse("8888")
828
    job_id = self.client.EvacuateNode("node-3", iallocator="hail", dry_run=True)
829
    self.assertEqual(8888, job_id)
830
    self.assertItems(["node-3"])
831
    self.assertQuery("iallocator", ["hail"])
832
    self.assertDryRun()
833

    
834
    self.assertRaises(client.GanetiApiError,
835
                      self.client.EvacuateNode,
836
                      "node-4", iallocator="hail", remote_node="node-5")
837

    
838
  def testMigrateNode(self):
839
    self.rapi.AddResponse(serializer.DumpJson([]))
840
    self.rapi.AddResponse("1111")
841
    self.assertEqual(1111, self.client.MigrateNode("node-a", dry_run=True))
842
    self.assertHandler(rlib2.R_2_nodes_name_migrate)
843
    self.assertItems(["node-a"])
844
    self.assert_("mode" not in self.rapi.GetLastHandler().queryargs)
845
    self.assertDryRun()
846
    self.assertFalse(self.rapi.GetLastRequestData())
847

    
848
    self.rapi.AddResponse(serializer.DumpJson([]))
849
    self.rapi.AddResponse("1112")
850
    self.assertEqual(1112, self.client.MigrateNode("node-a", dry_run=True,
851
                                                   mode="live"))
852
    self.assertHandler(rlib2.R_2_nodes_name_migrate)
853
    self.assertItems(["node-a"])
854
    self.assertQuery("mode", ["live"])
855
    self.assertDryRun()
856
    self.assertFalse(self.rapi.GetLastRequestData())
857

    
858
    self.rapi.AddResponse(serializer.DumpJson([]))
859
    self.assertRaises(client.GanetiApiError, self.client.MigrateNode,
860
                      "node-c", target_node="foonode")
861
    self.assertEqual(self.rapi.CountPending(), 0)
862

    
863
  def testMigrateNodeBodyData(self):
864
    self.rapi.AddResponse(serializer.DumpJson([rlib2._NODE_MIGRATE_REQV1]))
865
    self.rapi.AddResponse("27539")
866
    self.assertEqual(27539, self.client.MigrateNode("node-a", dry_run=False,
867
                                                    mode="live"))
868
    self.assertHandler(rlib2.R_2_nodes_name_migrate)
869
    self.assertItems(["node-a"])
870
    self.assertFalse(self.rapi.GetLastHandler().queryargs)
871
    self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
872
                     { "mode": "live", })
873

    
874
    self.rapi.AddResponse(serializer.DumpJson([rlib2._NODE_MIGRATE_REQV1]))
875
    self.rapi.AddResponse("14219")
876
    self.assertEqual(14219, self.client.MigrateNode("node-x", dry_run=True,
877
                                                    target_node="node9",
878
                                                    iallocator="ial"))
879
    self.assertHandler(rlib2.R_2_nodes_name_migrate)
880
    self.assertItems(["node-x"])
881
    self.assertDryRun()
882
    self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
883
                     { "target_node": "node9", "iallocator": "ial", })
884

    
885
    self.assertEqual(self.rapi.CountPending(), 0)
886

    
887
  def testGetNodeRole(self):
888
    self.rapi.AddResponse("\"master\"")
889
    self.assertEqual("master", self.client.GetNodeRole("node-a"))
890
    self.assertHandler(rlib2.R_2_nodes_name_role)
891
    self.assertItems(["node-a"])
892

    
893
  def testSetNodeRole(self):
894
    self.rapi.AddResponse("789")
895
    self.assertEqual(789,
896
        self.client.SetNodeRole("node-foo", "master-candidate", force=True))
897
    self.assertHandler(rlib2.R_2_nodes_name_role)
898
    self.assertItems(["node-foo"])
899
    self.assertQuery("force", ["1"])
900
    self.assertEqual("\"master-candidate\"", self.rapi.GetLastRequestData())
901

    
902
  def testGetNodeStorageUnits(self):
903
    self.rapi.AddResponse("42")
904
    self.assertEqual(42,
905
        self.client.GetNodeStorageUnits("node-x", "lvm-pv", "fields"))
906
    self.assertHandler(rlib2.R_2_nodes_name_storage)
907
    self.assertItems(["node-x"])
908
    self.assertQuery("storage_type", ["lvm-pv"])
909
    self.assertQuery("output_fields", ["fields"])
910

    
911
  def testModifyNodeStorageUnits(self):
912
    self.rapi.AddResponse("14")
913
    self.assertEqual(14,
914
        self.client.ModifyNodeStorageUnits("node-z", "lvm-pv", "hda"))
915
    self.assertHandler(rlib2.R_2_nodes_name_storage_modify)
916
    self.assertItems(["node-z"])
917
    self.assertQuery("storage_type", ["lvm-pv"])
918
    self.assertQuery("name", ["hda"])
919
    self.assertQuery("allocatable", None)
920

    
921
    for allocatable, query_allocatable in [(True, "1"), (False, "0")]:
922
      self.rapi.AddResponse("7205")
923
      job_id = self.client.ModifyNodeStorageUnits("node-z", "lvm-pv", "hda",
924
                                                  allocatable=allocatable)
925
      self.assertEqual(7205, job_id)
926
      self.assertHandler(rlib2.R_2_nodes_name_storage_modify)
927
      self.assertItems(["node-z"])
928
      self.assertQuery("storage_type", ["lvm-pv"])
929
      self.assertQuery("name", ["hda"])
930
      self.assertQuery("allocatable", [query_allocatable])
931

    
932
  def testRepairNodeStorageUnits(self):
933
    self.rapi.AddResponse("99")
934
    self.assertEqual(99, self.client.RepairNodeStorageUnits("node-z", "lvm-pv",
935
                                                            "hda"))
936
    self.assertHandler(rlib2.R_2_nodes_name_storage_repair)
937
    self.assertItems(["node-z"])
938
    self.assertQuery("storage_type", ["lvm-pv"])
939
    self.assertQuery("name", ["hda"])
940

    
941
  def testGetNodeTags(self):
942
    self.rapi.AddResponse("[\"fry\", \"bender\"]")
943
    self.assertEqual(["fry", "bender"], self.client.GetNodeTags("node-k"))
944
    self.assertHandler(rlib2.R_2_nodes_name_tags)
945
    self.assertItems(["node-k"])
946

    
947
  def testAddNodeTags(self):
948
    self.rapi.AddResponse("1234")
949
    self.assertEqual(1234,
950
        self.client.AddNodeTags("node-v", ["awesome"], dry_run=True))
951
    self.assertHandler(rlib2.R_2_nodes_name_tags)
952
    self.assertItems(["node-v"])
953
    self.assertDryRun()
954
    self.assertQuery("tag", ["awesome"])
955

    
956
  def testDeleteNodeTags(self):
957
    self.rapi.AddResponse("16861")
958
    self.assertEqual(16861, self.client.DeleteNodeTags("node-w", ["awesome"],
959
                                                       dry_run=True))
960
    self.assertHandler(rlib2.R_2_nodes_name_tags)
961
    self.assertItems(["node-w"])
962
    self.assertDryRun()
963
    self.assertQuery("tag", ["awesome"])
964

    
965
  def testGetGroups(self):
966
    groups = [{"name": "group1",
967
               "uri": "/2/groups/group1",
968
               },
969
              {"name": "group2",
970
               "uri": "/2/groups/group2",
971
               },
972
              ]
973
    self.rapi.AddResponse(serializer.DumpJson(groups))
974
    self.assertEqual(["group1", "group2"], self.client.GetGroups())
975
    self.assertHandler(rlib2.R_2_groups)
976

    
977
  def testGetGroupsBulk(self):
978
    groups = [{"name": "group1",
979
               "uri": "/2/groups/group1",
980
               "node_cnt": 2,
981
               "node_list": ["gnt1.test",
982
                             "gnt2.test",
983
                             ],
984
               },
985
              {"name": "group2",
986
               "uri": "/2/groups/group2",
987
               "node_cnt": 1,
988
               "node_list": ["gnt3.test",
989
                             ],
990
               },
991
              ]
992
    self.rapi.AddResponse(serializer.DumpJson(groups))
993

    
994
    self.assertEqual(groups, self.client.GetGroups(bulk=True))
995
    self.assertHandler(rlib2.R_2_groups)
996
    self.assertBulk()
997

    
998
  def testGetGroup(self):
999
    group = {"ctime": None,
1000
             "name": "default",
1001
             }
1002
    self.rapi.AddResponse(serializer.DumpJson(group))
1003
    self.assertEqual({"ctime": None, "name": "default"},
1004
                     self.client.GetGroup("default"))
1005
    self.assertHandler(rlib2.R_2_groups_name)
1006
    self.assertItems(["default"])
1007

    
1008
  def testCreateGroup(self):
1009
    self.rapi.AddResponse("12345")
1010
    job_id = self.client.CreateGroup("newgroup", dry_run=True)
1011
    self.assertEqual(job_id, 12345)
1012
    self.assertHandler(rlib2.R_2_groups)
1013
    self.assertDryRun()
1014

    
1015
  def testDeleteGroup(self):
1016
    self.rapi.AddResponse("12346")
1017
    job_id = self.client.DeleteGroup("newgroup", dry_run=True)
1018
    self.assertEqual(job_id, 12346)
1019
    self.assertHandler(rlib2.R_2_groups_name)
1020
    self.assertDryRun()
1021

    
1022
  def testRenameGroup(self):
1023
    self.rapi.AddResponse("12347")
1024
    job_id = self.client.RenameGroup("oldname", "newname")
1025
    self.assertEqual(job_id, 12347)
1026
    self.assertHandler(rlib2.R_2_groups_name_rename)
1027

    
1028
  def testModifyGroup(self):
1029
    self.rapi.AddResponse("12348")
1030
    job_id = self.client.ModifyGroup("mygroup", alloc_policy="foo")
1031
    self.assertEqual(job_id, 12348)
1032
    self.assertHandler(rlib2.R_2_groups_name_modify)
1033

    
1034
  def testAssignGroupNodes(self):
1035
    self.rapi.AddResponse("12349")
1036
    job_id = self.client.AssignGroupNodes("mygroup", ["node1", "node2"],
1037
                                          force=True, dry_run=True)
1038
    self.assertEqual(job_id, 12349)
1039
    self.assertHandler(rlib2.R_2_groups_name_assign_nodes)
1040
    self.assertDryRun()
1041
    self.assertUseForce()
1042

    
1043
  def testModifyInstance(self):
1044
    self.rapi.AddResponse("23681")
1045
    job_id = self.client.ModifyInstance("inst7210", os_name="linux")
1046
    self.assertEqual(job_id, 23681)
1047
    self.assertItems(["inst7210"])
1048
    self.assertHandler(rlib2.R_2_instances_name_modify)
1049
    self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
1050
                     { "os_name": "linux", })
1051

    
1052
  def testModifyCluster(self):
1053
    for mnh in [None, False, True]:
1054
      self.rapi.AddResponse("14470")
1055
      self.assertEqual(14470,
1056
        self.client.ModifyCluster(maintain_node_health=mnh))
1057
      self.assertHandler(rlib2.R_2_cluster_modify)
1058
      self.assertItems([])
1059
      data = serializer.LoadJson(self.rapi.GetLastRequestData())
1060
      self.assertEqual(len(data), 1)
1061
      self.assertEqual(data["maintain_node_health"], mnh)
1062
      self.assertEqual(self.rapi.CountPending(), 0)
1063

    
1064
  def testRedistributeConfig(self):
1065
    self.rapi.AddResponse("3364")
1066
    job_id = self.client.RedistributeConfig()
1067
    self.assertEqual(job_id, 3364)
1068
    self.assertItems([])
1069
    self.assertHandler(rlib2.R_2_redist_config)
1070

    
1071
  def testActivateInstanceDisks(self):
1072
    self.rapi.AddResponse("23547")
1073
    job_id = self.client.ActivateInstanceDisks("inst28204")
1074
    self.assertEqual(job_id, 23547)
1075
    self.assertItems(["inst28204"])
1076
    self.assertHandler(rlib2.R_2_instances_name_activate_disks)
1077
    self.assertFalse(self.rapi.GetLastHandler().queryargs)
1078

    
1079
  def testActivateInstanceDisksIgnoreSize(self):
1080
    self.rapi.AddResponse("11044")
1081
    job_id = self.client.ActivateInstanceDisks("inst28204", ignore_size=True)
1082
    self.assertEqual(job_id, 11044)
1083
    self.assertItems(["inst28204"])
1084
    self.assertHandler(rlib2.R_2_instances_name_activate_disks)
1085
    self.assertQuery("ignore_size", ["1"])
1086

    
1087
  def testDeactivateInstanceDisks(self):
1088
    self.rapi.AddResponse("14591")
1089
    job_id = self.client.DeactivateInstanceDisks("inst28234")
1090
    self.assertEqual(job_id, 14591)
1091
    self.assertItems(["inst28234"])
1092
    self.assertHandler(rlib2.R_2_instances_name_deactivate_disks)
1093
    self.assertFalse(self.rapi.GetLastHandler().queryargs)
1094

    
1095
  def testGetInstanceConsole(self):
1096
    self.rapi.AddResponse("26876")
1097
    job_id = self.client.GetInstanceConsole("inst21491")
1098
    self.assertEqual(job_id, 26876)
1099
    self.assertItems(["inst21491"])
1100
    self.assertHandler(rlib2.R_2_instances_name_console)
1101
    self.assertFalse(self.rapi.GetLastHandler().queryargs)
1102
    self.assertFalse(self.rapi.GetLastRequestData())
1103

    
1104
  def testGrowInstanceDisk(self):
1105
    for idx, wait_for_sync in enumerate([None, False, True]):
1106
      amount = 128 + (512 * idx)
1107
      self.assertEqual(self.rapi.CountPending(), 0)
1108
      self.rapi.AddResponse("30783")
1109
      self.assertEqual(30783,
1110
        self.client.GrowInstanceDisk("eze8ch", idx, amount,
1111
                                     wait_for_sync=wait_for_sync))
1112
      self.assertHandler(rlib2.R_2_instances_name_disk_grow)
1113
      self.assertItems(["eze8ch", str(idx)])
1114
      data = serializer.LoadJson(self.rapi.GetLastRequestData())
1115
      if wait_for_sync is None:
1116
        self.assertEqual(len(data), 1)
1117
        self.assert_("wait_for_sync" not in data)
1118
      else:
1119
        self.assertEqual(len(data), 2)
1120
        self.assertEqual(data["wait_for_sync"], wait_for_sync)
1121
      self.assertEqual(data["amount"], amount)
1122
      self.assertEqual(self.rapi.CountPending(), 0)
1123

    
1124
  def testGetGroupTags(self):
1125
    self.rapi.AddResponse("[]")
1126
    self.assertEqual([], self.client.GetGroupTags("fooGroup"))
1127
    self.assertHandler(rlib2.R_2_groups_name_tags)
1128
    self.assertItems(["fooGroup"])
1129

    
1130
  def testAddGroupTags(self):
1131
    self.rapi.AddResponse("1234")
1132
    self.assertEqual(1234,
1133
        self.client.AddGroupTags("fooGroup", ["awesome"], dry_run=True))
1134
    self.assertHandler(rlib2.R_2_groups_name_tags)
1135
    self.assertItems(["fooGroup"])
1136
    self.assertDryRun()
1137
    self.assertQuery("tag", ["awesome"])
1138

    
1139
  def testDeleteGroupTags(self):
1140
    self.rapi.AddResponse("25826")
1141
    self.assertEqual(25826, self.client.DeleteGroupTags("foo", ["awesome"],
1142
                                                        dry_run=True))
1143
    self.assertHandler(rlib2.R_2_groups_name_tags)
1144
    self.assertItems(["foo"])
1145
    self.assertDryRun()
1146
    self.assertQuery("tag", ["awesome"])
1147

    
1148
  def testQuery(self):
1149
    for idx, what in enumerate(constants.QR_VIA_RAPI):
1150
      for idx2, filter_ in enumerate([None, ["?", "name"]]):
1151
        job_id = 11010 + (idx << 4) + (idx2 << 16)
1152
        fields = sorted(query.ALL_FIELDS[what].keys())[:10]
1153

    
1154
        self.rapi.AddResponse(str(job_id))
1155
        self.assertEqual(self.client.Query(what, fields, filter_=filter_),
1156
                         job_id)
1157
        self.assertItems([what])
1158
        self.assertHandler(rlib2.R_2_query)
1159
        self.assertFalse(self.rapi.GetLastHandler().queryargs)
1160
        data = serializer.LoadJson(self.rapi.GetLastRequestData())
1161
        self.assertEqual(data["fields"], fields)
1162
        if filter_ is None:
1163
          self.assertTrue("filter" not in data)
1164
        else:
1165
          self.assertEqual(data["filter"], filter_)
1166
        self.assertEqual(self.rapi.CountPending(), 0)
1167

    
1168
  def testQueryFields(self):
1169
    exp_result = objects.QueryFieldsResponse(fields=[
1170
      objects.QueryFieldDefinition(name="pnode", title="PNode",
1171
                                   kind=constants.QFT_NUMBER),
1172
      objects.QueryFieldDefinition(name="other", title="Other",
1173
                                   kind=constants.QFT_BOOL),
1174
      ])
1175

    
1176
    for what in constants.QR_VIA_RAPI:
1177
      for fields in [None, ["name", "_unknown_"], ["&", "?|"]]:
1178
        self.rapi.AddResponse(serializer.DumpJson(exp_result.ToDict()))
1179
        result = self.client.QueryFields(what, fields=fields)
1180
        self.assertItems([what])
1181
        self.assertHandler(rlib2.R_2_query_fields)
1182
        self.assertFalse(self.rapi.GetLastRequestData())
1183

    
1184
        queryargs = self.rapi.GetLastHandler().queryargs
1185
        if fields is None:
1186
          self.assertFalse(queryargs)
1187
        else:
1188
          self.assertEqual(queryargs, {
1189
            "fields": [",".join(fields)],
1190
            })
1191

    
1192
        self.assertEqual(objects.QueryFieldsResponse.FromDict(result).ToDict(),
1193
                         exp_result.ToDict())
1194

    
1195
        self.assertEqual(self.rapi.CountPending(), 0)
1196

    
1197
  def testWaitForJobCompletionNoChange(self):
1198
    resp = serializer.DumpJson({
1199
      "status": constants.JOB_STATUS_WAITLOCK,
1200
      })
1201

    
1202
    for retries in [1, 5, 25]:
1203
      for _ in range(retries):
1204
        self.rapi.AddResponse(resp)
1205

    
1206
      self.assertFalse(self.client.WaitForJobCompletion(22789, period=None,
1207
                                                        retries=retries))
1208
      self.assertHandler(rlib2.R_2_jobs_id)
1209
      self.assertItems(["22789"])
1210

    
1211
      self.assertEqual(self.rapi.CountPending(), 0)
1212

    
1213
  def testWaitForJobCompletionAlreadyFinished(self):
1214
    self.rapi.AddResponse(serializer.DumpJson({
1215
      "status": constants.JOB_STATUS_SUCCESS,
1216
      }))
1217

    
1218
    self.assertTrue(self.client.WaitForJobCompletion(22793, period=None,
1219
                                                     retries=1))
1220
    self.assertHandler(rlib2.R_2_jobs_id)
1221
    self.assertItems(["22793"])
1222

    
1223
    self.assertEqual(self.rapi.CountPending(), 0)
1224

    
1225
  def testWaitForJobCompletionEmptyResponse(self):
1226
    self.rapi.AddResponse("{}")
1227
    self.assertFalse(self.client.WaitForJobCompletion(22793, period=None,
1228
                                                     retries=10))
1229
    self.assertHandler(rlib2.R_2_jobs_id)
1230
    self.assertItems(["22793"])
1231

    
1232
    self.assertEqual(self.rapi.CountPending(), 0)
1233

    
1234
  def testWaitForJobCompletionOutOfRetries(self):
1235
    for retries in [3, 10, 21]:
1236
      for _ in range(retries):
1237
        self.rapi.AddResponse(serializer.DumpJson({
1238
          "status": constants.JOB_STATUS_RUNNING,
1239
          }))
1240

    
1241
      self.assertFalse(self.client.WaitForJobCompletion(30948, period=None,
1242
                                                        retries=retries - 1))
1243
      self.assertHandler(rlib2.R_2_jobs_id)
1244
      self.assertItems(["30948"])
1245

    
1246
      self.assertEqual(self.rapi.CountPending(), 1)
1247
      self.rapi.ResetResponses()
1248

    
1249
  def testWaitForJobCompletionSuccessAndFailure(self):
1250
    for retries in [1, 4, 13]:
1251
      for (success, end_status) in [(False, constants.JOB_STATUS_ERROR),
1252
                                    (True, constants.JOB_STATUS_SUCCESS)]:
1253
        for _ in range(retries):
1254
          self.rapi.AddResponse(serializer.DumpJson({
1255
            "status": constants.JOB_STATUS_RUNNING,
1256
            }))
1257

    
1258
        self.rapi.AddResponse(serializer.DumpJson({
1259
          "status": end_status,
1260
          }))
1261

    
1262
        result = self.client.WaitForJobCompletion(3187, period=None,
1263
                                                  retries=retries + 1)
1264
        self.assertEqual(result, success)
1265
        self.assertHandler(rlib2.R_2_jobs_id)
1266
        self.assertItems(["3187"])
1267

    
1268
        self.assertEqual(self.rapi.CountPending(), 0)
1269

    
1270

    
1271
class RapiTestRunner(unittest.TextTestRunner):
1272
  def run(self, *args):
1273
    global _used_handlers
1274
    assert _used_handlers is None
1275

    
1276
    _used_handlers = set()
1277
    try:
1278
      # Run actual tests
1279
      result = unittest.TextTestRunner.run(self, *args)
1280

    
1281
      diff = (set(connector.CONNECTOR.values()) - _used_handlers -
1282
             _KNOWN_UNUSED)
1283
      if diff:
1284
        raise AssertionError("The following RAPI resources were not used by the"
1285
                             " RAPI client: %r" % utils.CommaJoin(diff))
1286
    finally:
1287
      # Reset global variable
1288
      _used_handlers = None
1289

    
1290
    return result
1291

    
1292

    
1293
if __name__ == '__main__':
1294
  client.UsesRapiClient(testutils.GanetiTestProgram)(testRunner=RapiTestRunner)