Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (51.2 kB)

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

    
4
# Copyright (C) 2010, 2011 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 unittest
26
import warnings
27
import pycurl
28

    
29
from ganeti import constants
30
from ganeti import http
31
from ganeti import serializer
32
from ganeti import utils
33
from ganeti import query
34
from ganeti import objects
35
from ganeti import rapi
36

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

    
42
import testutils
43

    
44

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

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

    
54

    
55
class RapiMock(object):
56
  def __init__(self):
57
    self._mapper = connector.Mapper()
58
    self._responses = []
59
    self._last_handler = None
60
    self._last_req_data = None
61

    
62
  def ResetResponses(self):
63
    del self._responses[:]
64

    
65
  def AddResponse(self, response, code=200):
66
    self._responses.insert(0, (code, response))
67

    
68
  def CountPending(self):
69
    return len(self._responses)
70

    
71
  def GetLastHandler(self):
72
    return self._last_handler
73

    
74
  def GetLastRequestData(self):
75
    return self._last_req_data
76

    
77
  def FetchResponse(self, path, method, headers, request_body):
78
    self._last_req_data = request_body
79

    
80
    try:
81
      (handler_cls, items, args) = self._mapper.getController(path)
82

    
83
      # Record handler as used
84
      _used_handlers.add(handler_cls)
85

    
86
      self._last_handler = handler_cls(items, args, None)
87
      if not hasattr(self._last_handler, method.upper()):
88
        raise http.HttpNotImplemented(message="Method not implemented")
89

    
90
    except http.HttpException, ex:
91
      code = ex.code
92
      response = ex.message
93
    else:
94
      if not self._responses:
95
        raise Exception("No responses")
96

    
97
      (code, response) = self._responses.pop()
98

    
99
    return code, response
100

    
101

    
102
class TestConstants(unittest.TestCase):
103
  def test(self):
104
    self.assertEqual(client.GANETI_RAPI_PORT, constants.DEFAULT_RAPI_PORT)
105
    self.assertEqual(client.GANETI_RAPI_VERSION, constants.RAPI_VERSION)
106
    self.assertEqual(client.HTTP_APP_JSON, http.HTTP_APP_JSON)
107
    self.assertEqual(client._REQ_DATA_VERSION_FIELD, rlib2._REQ_DATA_VERSION)
108
    self.assertEqual(client.JOB_STATUS_QUEUED, constants.JOB_STATUS_QUEUED)
109
    self.assertEqual(client.JOB_STATUS_WAITING, constants.JOB_STATUS_WAITING)
110
    self.assertEqual(client.JOB_STATUS_CANCELING,
111
                     constants.JOB_STATUS_CANCELING)
112
    self.assertEqual(client.JOB_STATUS_RUNNING, constants.JOB_STATUS_RUNNING)
113
    self.assertEqual(client.JOB_STATUS_CANCELED, constants.JOB_STATUS_CANCELED)
114
    self.assertEqual(client.JOB_STATUS_SUCCESS, constants.JOB_STATUS_SUCCESS)
115
    self.assertEqual(client.JOB_STATUS_ERROR, constants.JOB_STATUS_ERROR)
116
    self.assertEqual(client.JOB_STATUS_FINALIZED, constants.JOBS_FINALIZED)
117
    self.assertEqual(client.JOB_STATUS_ALL, constants.JOB_STATUS_ALL)
118

    
119
    # Node evacuation
120
    self.assertEqual(client.NODE_EVAC_PRI, constants.NODE_EVAC_PRI)
121
    self.assertEqual(client.NODE_EVAC_SEC, constants.NODE_EVAC_SEC)
122
    self.assertEqual(client.NODE_EVAC_ALL, constants.NODE_EVAC_ALL)
123

    
124
    # Legacy name
125
    self.assertEqual(client.JOB_STATUS_WAITLOCK, constants.JOB_STATUS_WAITING)
126

    
127
    # RAPI feature strings
128
    self.assertEqual(client._INST_CREATE_REQV1, rlib2._INST_CREATE_REQV1)
129
    self.assertEqual(client.INST_CREATE_REQV1, rlib2._INST_CREATE_REQV1)
130
    self.assertEqual(client._INST_REINSTALL_REQV1, rlib2._INST_REINSTALL_REQV1)
131
    self.assertEqual(client.INST_REINSTALL_REQV1, rlib2._INST_REINSTALL_REQV1)
132
    self.assertEqual(client._NODE_MIGRATE_REQV1, rlib2._NODE_MIGRATE_REQV1)
133
    self.assertEqual(client.NODE_MIGRATE_REQV1, rlib2._NODE_MIGRATE_REQV1)
134
    self.assertEqual(client._NODE_EVAC_RES1, rlib2._NODE_EVAC_RES1)
135
    self.assertEqual(client.NODE_EVAC_RES1, rlib2._NODE_EVAC_RES1)
136

    
137

    
138
class RapiMockTest(unittest.TestCase):
139
  def test(self):
140
    rapi = RapiMock()
141
    path = "/version"
142
    self.assertEqual((404, None), rapi.FetchResponse("/foo", "GET", None, None))
143
    self.assertEqual((501, "Method not implemented"),
144
                     rapi.FetchResponse("/version", "POST", None, None))
145
    rapi.AddResponse("2")
146
    code, response = rapi.FetchResponse("/version", "GET", None, None)
147
    self.assertEqual(200, code)
148
    self.assertEqual("2", response)
149
    self.failUnless(isinstance(rapi.GetLastHandler(), rlib2.R_version))
150

    
151

    
152
def _FakeNoSslPycurlVersion():
153
  # Note: incomplete version tuple
154
  return (3, "7.16.0", 462848, "mysystem", 1581, None, 0)
155

    
156

    
157
def _FakeFancySslPycurlVersion():
158
  # Note: incomplete version tuple
159
  return (3, "7.16.0", 462848, "mysystem", 1581, "FancySSL/1.2.3", 0)
160

    
161

    
162
def _FakeOpenSslPycurlVersion():
163
  # Note: incomplete version tuple
164
  return (2, "7.15.5", 462597, "othersystem", 668, "OpenSSL/0.9.8c", 0)
165

    
166

    
167
def _FakeGnuTlsPycurlVersion():
168
  # Note: incomplete version tuple
169
  return (3, "7.18.0", 463360, "somesystem", 1581, "GnuTLS/2.0.4", 0)
170

    
171

    
172
class TestExtendedConfig(unittest.TestCase):
173
  def testAuth(self):
174
    cl = client.GanetiRapiClient("master.example.com",
175
      username="user", password="pw",
176
      curl_factory=lambda: rapi.testutils.FakeCurl(RapiMock()))
177

    
178
    curl = cl._CreateCurl()
179
    self.assertEqual(curl.getopt(pycurl.HTTPAUTH), pycurl.HTTPAUTH_BASIC)
180
    self.assertEqual(curl.getopt(pycurl.USERPWD), "user:pw")
181

    
182
  def testInvalidAuth(self):
183
    # No username
184
    self.assertRaises(client.Error, client.GanetiRapiClient,
185
                      "master-a.example.com", password="pw")
186
    # No password
187
    self.assertRaises(client.Error, client.GanetiRapiClient,
188
                      "master-b.example.com", username="user")
189

    
190
  def testCertVerifyInvalidCombinations(self):
191
    self.assertRaises(client.Error, client.GenericCurlConfig,
192
                      use_curl_cabundle=True, cafile="cert1.pem")
193
    self.assertRaises(client.Error, client.GenericCurlConfig,
194
                      use_curl_cabundle=True, capath="certs/")
195
    self.assertRaises(client.Error, client.GenericCurlConfig,
196
                      use_curl_cabundle=True,
197
                      cafile="cert1.pem", capath="certs/")
198

    
199
  def testProxySignalVerifyHostname(self):
200
    for use_gnutls in [False, True]:
201
      if use_gnutls:
202
        pcverfn = _FakeGnuTlsPycurlVersion
203
      else:
204
        pcverfn = _FakeOpenSslPycurlVersion
205

    
206
      for proxy in ["", "http://127.0.0.1:1234"]:
207
        for use_signal in [False, True]:
208
          for verify_hostname in [False, True]:
209
            cfgfn = client.GenericCurlConfig(proxy=proxy, use_signal=use_signal,
210
                                             verify_hostname=verify_hostname,
211
                                             _pycurl_version_fn=pcverfn)
212

    
213
            curl_factory = lambda: rapi.testutils.FakeCurl(RapiMock())
214
            cl = client.GanetiRapiClient("master.example.com",
215
                                         curl_config_fn=cfgfn,
216
                                         curl_factory=curl_factory)
217

    
218
            curl = cl._CreateCurl()
219
            self.assertEqual(curl.getopt(pycurl.PROXY), proxy)
220
            self.assertEqual(curl.getopt(pycurl.NOSIGNAL), not use_signal)
221

    
222
            if verify_hostname:
223
              self.assertEqual(curl.getopt(pycurl.SSL_VERIFYHOST), 2)
224
            else:
225
              self.assertEqual(curl.getopt(pycurl.SSL_VERIFYHOST), 0)
226

    
227
  def testNoCertVerify(self):
228
    cfgfn = client.GenericCurlConfig()
229

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

    
234
    curl = cl._CreateCurl()
235
    self.assertFalse(curl.getopt(pycurl.SSL_VERIFYPEER))
236
    self.assertFalse(curl.getopt(pycurl.CAINFO))
237
    self.assertFalse(curl.getopt(pycurl.CAPATH))
238

    
239
  def testCertVerifyCurlBundle(self):
240
    cfgfn = client.GenericCurlConfig(use_curl_cabundle=True)
241

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

    
246
    curl = cl._CreateCurl()
247
    self.assert_(curl.getopt(pycurl.SSL_VERIFYPEER))
248
    self.assertFalse(curl.getopt(pycurl.CAINFO))
249
    self.assertFalse(curl.getopt(pycurl.CAPATH))
250

    
251
  def testCertVerifyCafile(self):
252
    mycert = "/tmp/some/UNUSED/cert/file.pem"
253
    cfgfn = client.GenericCurlConfig(cafile=mycert)
254

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

    
259
    curl = cl._CreateCurl()
260
    self.assert_(curl.getopt(pycurl.SSL_VERIFYPEER))
261
    self.assertEqual(curl.getopt(pycurl.CAINFO), mycert)
262
    self.assertFalse(curl.getopt(pycurl.CAPATH))
263

    
264
  def testCertVerifyCapath(self):
265
    certdir = "/tmp/some/UNUSED/cert/directory"
266
    pcverfn = _FakeOpenSslPycurlVersion
267
    cfgfn = client.GenericCurlConfig(capath=certdir,
268
                                     _pycurl_version_fn=pcverfn)
269

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

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

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

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

    
289
    self.assertRaises(client.Error, cl._CreateCurl)
290

    
291
  def testCertVerifyNoSsl(self):
292
    certdir = "/tmp/some/UNUSED/cert/directory"
293
    pcverfn = _FakeNoSslPycurlVersion
294
    cfgfn = client.GenericCurlConfig(capath=certdir,
295
                                     _pycurl_version_fn=pcverfn)
296

    
297
    curl_factory = lambda: rapi.testutils.FakeCurl(RapiMock())
298
    cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
299
                                 curl_factory=curl_factory)
300

    
301
    self.assertRaises(client.Error, cl._CreateCurl)
302

    
303
  def testCertVerifyFancySsl(self):
304
    certdir = "/tmp/some/UNUSED/cert/directory"
305
    pcverfn = _FakeFancySslPycurlVersion
306
    cfgfn = client.GenericCurlConfig(capath=certdir,
307
                                     _pycurl_version_fn=pcverfn)
308

    
309
    curl_factory = lambda: rapi.testutils.FakeCurl(RapiMock())
310
    cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
311
                                 curl_factory=curl_factory)
312

    
313
    self.assertRaises(NotImplementedError, cl._CreateCurl)
314

    
315
  def testCertVerifyCapath(self):
316
    for connect_timeout in [None, 1, 5, 10, 30, 60, 300]:
317
      for timeout in [None, 1, 30, 60, 3600, 24 * 3600]:
318
        cfgfn = client.GenericCurlConfig(connect_timeout=connect_timeout,
319
                                         timeout=timeout)
320

    
321
        curl_factory = lambda: rapi.testutils.FakeCurl(RapiMock())
322
        cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
323
                                     curl_factory=curl_factory)
324

    
325
        curl = cl._CreateCurl()
326
        self.assertEqual(curl.getopt(pycurl.CONNECTTIMEOUT), connect_timeout)
327
        self.assertEqual(curl.getopt(pycurl.TIMEOUT), timeout)
328

    
329

    
330
class GanetiRapiClientTests(testutils.GanetiTestCase):
331
  def setUp(self):
332
    testutils.GanetiTestCase.setUp(self)
333

    
334
    self.rapi = RapiMock()
335
    self.curl = rapi.testutils.FakeCurl(self.rapi)
336
    self.client = client.GanetiRapiClient("master.example.com",
337
                                          curl_factory=lambda: self.curl)
338

    
339
  def assertHandler(self, handler_cls):
340
    self.failUnless(isinstance(self.rapi.GetLastHandler(), handler_cls))
341

    
342
  def assertQuery(self, key, value):
343
    self.assertEqual(value, self.rapi.GetLastHandler().queryargs.get(key, None))
344

    
345
  def assertItems(self, items):
346
    self.assertEqual(items, self.rapi.GetLastHandler().items)
347

    
348
  def assertBulk(self):
349
    self.assertTrue(self.rapi.GetLastHandler().useBulk())
350

    
351
  def assertDryRun(self):
352
    self.assertTrue(self.rapi.GetLastHandler().dryRun())
353

    
354
  def assertUseForce(self):
355
    self.assertTrue(self.rapi.GetLastHandler().useForce())
356

    
357
  def testEncodeQuery(self):
358
    query = [
359
      ("a", None),
360
      ("b", 1),
361
      ("c", 2),
362
      ("d", "Foo"),
363
      ("e", True),
364
      ]
365

    
366
    expected = [
367
      ("a", ""),
368
      ("b", 1),
369
      ("c", 2),
370
      ("d", "Foo"),
371
      ("e", 1),
372
      ]
373

    
374
    self.assertEqualValues(self.client._EncodeQuery(query),
375
                           expected)
376

    
377
    # invalid types
378
    for i in [[1, 2, 3], {"moo": "boo"}, (1, 2, 3)]:
379
      self.assertRaises(ValueError, self.client._EncodeQuery, [("x", i)])
380

    
381
  def testCurlSettings(self):
382
    self.rapi.AddResponse("2")
383
    self.assertEqual(2, self.client.GetVersion())
384
    self.assertHandler(rlib2.R_version)
385

    
386
    # Signals should be disabled by default
387
    self.assert_(self.curl.getopt(pycurl.NOSIGNAL))
388

    
389
    # No auth and no proxy
390
    self.assertFalse(self.curl.getopt(pycurl.USERPWD))
391
    self.assert_(self.curl.getopt(pycurl.PROXY) is None)
392

    
393
    # Content-type is required for requests
394
    headers = self.curl.getopt(pycurl.HTTPHEADER)
395
    self.assert_("Content-type: application/json" in headers)
396

    
397
  def testHttpError(self):
398
    self.rapi.AddResponse(None, code=404)
399
    try:
400
      self.client.GetJobStatus(15140)
401
    except client.GanetiApiError, err:
402
      self.assertEqual(err.code, 404)
403
    else:
404
      self.fail("Didn't raise exception")
405

    
406
  def testGetVersion(self):
407
    self.rapi.AddResponse("2")
408
    self.assertEqual(2, self.client.GetVersion())
409
    self.assertHandler(rlib2.R_version)
410

    
411
  def testGetFeatures(self):
412
    for features in [[], ["foo", "bar", "baz"]]:
413
      self.rapi.AddResponse(serializer.DumpJson(features))
414
      self.assertEqual(features, self.client.GetFeatures())
415
      self.assertHandler(rlib2.R_2_features)
416

    
417
  def testGetFeaturesNotFound(self):
418
    self.rapi.AddResponse(None, code=404)
419
    self.assertEqual([], self.client.GetFeatures())
420

    
421
  def testGetOperatingSystems(self):
422
    self.rapi.AddResponse("[\"beos\"]")
423
    self.assertEqual(["beos"], self.client.GetOperatingSystems())
424
    self.assertHandler(rlib2.R_2_os)
425

    
426
  def testGetClusterTags(self):
427
    self.rapi.AddResponse("[\"tag\"]")
428
    self.assertEqual(["tag"], self.client.GetClusterTags())
429
    self.assertHandler(rlib2.R_2_tags)
430

    
431
  def testAddClusterTags(self):
432
    self.rapi.AddResponse("1234")
433
    self.assertEqual(1234,
434
        self.client.AddClusterTags(["awesome"], dry_run=True))
435
    self.assertHandler(rlib2.R_2_tags)
436
    self.assertDryRun()
437
    self.assertQuery("tag", ["awesome"])
438

    
439
  def testDeleteClusterTags(self):
440
    self.rapi.AddResponse("5107")
441
    self.assertEqual(5107, self.client.DeleteClusterTags(["awesome"],
442
                                                         dry_run=True))
443
    self.assertHandler(rlib2.R_2_tags)
444
    self.assertDryRun()
445
    self.assertQuery("tag", ["awesome"])
446

    
447
  def testGetInfo(self):
448
    self.rapi.AddResponse("{}")
449
    self.assertEqual({}, self.client.GetInfo())
450
    self.assertHandler(rlib2.R_2_info)
451

    
452
  def testGetInstances(self):
453
    self.rapi.AddResponse("[]")
454
    self.assertEqual([], self.client.GetInstances(bulk=True))
455
    self.assertHandler(rlib2.R_2_instances)
456
    self.assertBulk()
457

    
458
  def testGetInstance(self):
459
    self.rapi.AddResponse("[]")
460
    self.assertEqual([], self.client.GetInstance("instance"))
461
    self.assertHandler(rlib2.R_2_instances_name)
462
    self.assertItems(["instance"])
463

    
464
  def testGetInstanceInfo(self):
465
    self.rapi.AddResponse("21291")
466
    self.assertEqual(21291, self.client.GetInstanceInfo("inst3"))
467
    self.assertHandler(rlib2.R_2_instances_name_info)
468
    self.assertItems(["inst3"])
469
    self.assertQuery("static", None)
470

    
471
    self.rapi.AddResponse("3428")
472
    self.assertEqual(3428, self.client.GetInstanceInfo("inst31", static=False))
473
    self.assertHandler(rlib2.R_2_instances_name_info)
474
    self.assertItems(["inst31"])
475
    self.assertQuery("static", ["0"])
476

    
477
    self.rapi.AddResponse("15665")
478
    self.assertEqual(15665, self.client.GetInstanceInfo("inst32", static=True))
479
    self.assertHandler(rlib2.R_2_instances_name_info)
480
    self.assertItems(["inst32"])
481
    self.assertQuery("static", ["1"])
482

    
483
  def testCreateInstanceOldVersion(self):
484
    # The old request format, version 0, is no longer supported
485
    self.rapi.AddResponse(None, code=404)
486
    self.assertRaises(client.GanetiApiError, self.client.CreateInstance,
487
                      "create", "inst1.example.com", "plain", [], [])
488
    self.assertEqual(self.rapi.CountPending(), 0)
489

    
490
  def testCreateInstance(self):
491
    self.rapi.AddResponse(serializer.DumpJson([rlib2._INST_CREATE_REQV1]))
492
    self.rapi.AddResponse("23030")
493
    job_id = self.client.CreateInstance("create", "inst1.example.com",
494
                                        "plain", [], [], dry_run=True)
495
    self.assertEqual(job_id, 23030)
496
    self.assertHandler(rlib2.R_2_instances)
497
    self.assertDryRun()
498

    
499
    data = serializer.LoadJson(self.rapi.GetLastRequestData())
500

    
501
    for field in ["dry_run", "beparams", "hvparams", "start"]:
502
      self.assertFalse(field in data)
503

    
504
    self.assertEqual(data["name"], "inst1.example.com")
505
    self.assertEqual(data["disk_template"], "plain")
506

    
507
  def testCreateInstance2(self):
508
    self.rapi.AddResponse(serializer.DumpJson([rlib2._INST_CREATE_REQV1]))
509
    self.rapi.AddResponse("24740")
510
    job_id = self.client.CreateInstance("import", "inst2.example.com",
511
                                        "drbd8", [{"size": 100,}],
512
                                        [{}, {"bridge": "br1", }],
513
                                        dry_run=False, start=True,
514
                                        pnode="node1", snode="node9",
515
                                        ip_check=False)
516
    self.assertEqual(job_id, 24740)
517
    self.assertHandler(rlib2.R_2_instances)
518

    
519
    data = serializer.LoadJson(self.rapi.GetLastRequestData())
520
    self.assertEqual(data[rlib2._REQ_DATA_VERSION], 1)
521
    self.assertEqual(data["name"], "inst2.example.com")
522
    self.assertEqual(data["disk_template"], "drbd8")
523
    self.assertEqual(data["start"], True)
524
    self.assertEqual(data["ip_check"], False)
525
    self.assertEqualValues(data["disks"], [{"size": 100,}])
526
    self.assertEqualValues(data["nics"], [{}, {"bridge": "br1", }])
527

    
528
  def testDeleteInstance(self):
529
    self.rapi.AddResponse("1234")
530
    self.assertEqual(1234, self.client.DeleteInstance("instance", dry_run=True))
531
    self.assertHandler(rlib2.R_2_instances_name)
532
    self.assertItems(["instance"])
533
    self.assertDryRun()
534

    
535
  def testGetInstanceTags(self):
536
    self.rapi.AddResponse("[]")
537
    self.assertEqual([], self.client.GetInstanceTags("fooinstance"))
538
    self.assertHandler(rlib2.R_2_instances_name_tags)
539
    self.assertItems(["fooinstance"])
540

    
541
  def testAddInstanceTags(self):
542
    self.rapi.AddResponse("1234")
543
    self.assertEqual(1234,
544
        self.client.AddInstanceTags("fooinstance", ["awesome"], dry_run=True))
545
    self.assertHandler(rlib2.R_2_instances_name_tags)
546
    self.assertItems(["fooinstance"])
547
    self.assertDryRun()
548
    self.assertQuery("tag", ["awesome"])
549

    
550
  def testDeleteInstanceTags(self):
551
    self.rapi.AddResponse("25826")
552
    self.assertEqual(25826, self.client.DeleteInstanceTags("foo", ["awesome"],
553
                                                           dry_run=True))
554
    self.assertHandler(rlib2.R_2_instances_name_tags)
555
    self.assertItems(["foo"])
556
    self.assertDryRun()
557
    self.assertQuery("tag", ["awesome"])
558

    
559
  def testRebootInstance(self):
560
    self.rapi.AddResponse("6146")
561
    job_id = self.client.RebootInstance("i-bar", reboot_type="hard",
562
                                        ignore_secondaries=True, dry_run=True)
563
    self.assertEqual(6146, job_id)
564
    self.assertHandler(rlib2.R_2_instances_name_reboot)
565
    self.assertItems(["i-bar"])
566
    self.assertDryRun()
567
    self.assertQuery("type", ["hard"])
568
    self.assertQuery("ignore_secondaries", ["1"])
569

    
570
  def testShutdownInstance(self):
571
    self.rapi.AddResponse("1487")
572
    self.assertEqual(1487, self.client.ShutdownInstance("foo-instance",
573
                                                        dry_run=True))
574
    self.assertHandler(rlib2.R_2_instances_name_shutdown)
575
    self.assertItems(["foo-instance"])
576
    self.assertDryRun()
577

    
578
  def testStartupInstance(self):
579
    self.rapi.AddResponse("27149")
580
    self.assertEqual(27149, self.client.StartupInstance("bar-instance",
581
                                                        dry_run=True))
582
    self.assertHandler(rlib2.R_2_instances_name_startup)
583
    self.assertItems(["bar-instance"])
584
    self.assertDryRun()
585

    
586
  def testReinstallInstance(self):
587
    self.rapi.AddResponse(serializer.DumpJson([]))
588
    self.rapi.AddResponse("19119")
589
    self.assertEqual(19119, self.client.ReinstallInstance("baz-instance",
590
                                                          os="DOS",
591
                                                          no_startup=True))
592
    self.assertHandler(rlib2.R_2_instances_name_reinstall)
593
    self.assertItems(["baz-instance"])
594
    self.assertQuery("os", ["DOS"])
595
    self.assertQuery("nostartup", ["1"])
596
    self.assertEqual(self.rapi.CountPending(), 0)
597

    
598
  def testReinstallInstanceNew(self):
599
    self.rapi.AddResponse(serializer.DumpJson([rlib2._INST_REINSTALL_REQV1]))
600
    self.rapi.AddResponse("25689")
601
    self.assertEqual(25689, self.client.ReinstallInstance("moo-instance",
602
                                                          os="Debian",
603
                                                          no_startup=True))
604
    self.assertHandler(rlib2.R_2_instances_name_reinstall)
605
    self.assertItems(["moo-instance"])
606
    data = serializer.LoadJson(self.rapi.GetLastRequestData())
607
    self.assertEqual(len(data), 2)
608
    self.assertEqual(data["os"], "Debian")
609
    self.assertEqual(data["start"], False)
610
    self.assertEqual(self.rapi.CountPending(), 0)
611

    
612
  def testReinstallInstanceWithOsparams1(self):
613
    self.rapi.AddResponse(serializer.DumpJson([]))
614
    self.assertRaises(client.GanetiApiError, self.client.ReinstallInstance,
615
                      "doo-instance", osparams={"x": "y"})
616
    self.assertEqual(self.rapi.CountPending(), 0)
617

    
618
  def testReinstallInstanceWithOsparams2(self):
619
    osparams = {
620
      "Hello": "World",
621
      "foo": "bar",
622
      }
623
    self.rapi.AddResponse(serializer.DumpJson([rlib2._INST_REINSTALL_REQV1]))
624
    self.rapi.AddResponse("1717")
625
    self.assertEqual(1717, self.client.ReinstallInstance("zoo-instance",
626
                                                         osparams=osparams))
627
    self.assertHandler(rlib2.R_2_instances_name_reinstall)
628
    self.assertItems(["zoo-instance"])
629
    data = serializer.LoadJson(self.rapi.GetLastRequestData())
630
    self.assertEqual(len(data), 2)
631
    self.assertEqual(data["osparams"], osparams)
632
    self.assertEqual(data["start"], True)
633
    self.assertEqual(self.rapi.CountPending(), 0)
634

    
635
  def testReplaceInstanceDisks(self):
636
    self.rapi.AddResponse("999")
637
    job_id = self.client.ReplaceInstanceDisks("instance-name",
638
        disks=[0, 1], iallocator="hail")
639
    self.assertEqual(999, job_id)
640
    self.assertHandler(rlib2.R_2_instances_name_replace_disks)
641
    self.assertItems(["instance-name"])
642
    self.assertQuery("disks", ["0,1"])
643
    self.assertQuery("mode", ["replace_auto"])
644
    self.assertQuery("iallocator", ["hail"])
645

    
646
    self.rapi.AddResponse("1000")
647
    job_id = self.client.ReplaceInstanceDisks("instance-bar",
648
        disks=[1], mode="replace_on_secondary", remote_node="foo-node")
649
    self.assertEqual(1000, job_id)
650
    self.assertItems(["instance-bar"])
651
    self.assertQuery("disks", ["1"])
652
    self.assertQuery("remote_node", ["foo-node"])
653

    
654
    self.rapi.AddResponse("5175")
655
    self.assertEqual(5175, self.client.ReplaceInstanceDisks("instance-moo"))
656
    self.assertItems(["instance-moo"])
657
    self.assertQuery("disks", None)
658

    
659
  def testPrepareExport(self):
660
    self.rapi.AddResponse("8326")
661
    self.assertEqual(8326, self.client.PrepareExport("inst1", "local"))
662
    self.assertHandler(rlib2.R_2_instances_name_prepare_export)
663
    self.assertItems(["inst1"])
664
    self.assertQuery("mode", ["local"])
665

    
666
  def testExportInstance(self):
667
    self.rapi.AddResponse("19695")
668
    job_id = self.client.ExportInstance("inst2", "local", "nodeX",
669
                                        shutdown=True)
670
    self.assertEqual(job_id, 19695)
671
    self.assertHandler(rlib2.R_2_instances_name_export)
672
    self.assertItems(["inst2"])
673

    
674
    data = serializer.LoadJson(self.rapi.GetLastRequestData())
675
    self.assertEqual(data["mode"], "local")
676
    self.assertEqual(data["destination"], "nodeX")
677
    self.assertEqual(data["shutdown"], True)
678

    
679
  def testMigrateInstanceDefaults(self):
680
    self.rapi.AddResponse("24873")
681
    job_id = self.client.MigrateInstance("inst91")
682
    self.assertEqual(job_id, 24873)
683
    self.assertHandler(rlib2.R_2_instances_name_migrate)
684
    self.assertItems(["inst91"])
685

    
686
    data = serializer.LoadJson(self.rapi.GetLastRequestData())
687
    self.assertFalse(data)
688

    
689
  def testMigrateInstance(self):
690
    for mode in constants.HT_MIGRATION_MODES:
691
      for cleanup in [False, True]:
692
        self.rapi.AddResponse("31910")
693
        job_id = self.client.MigrateInstance("inst289", mode=mode,
694
                                             cleanup=cleanup)
695
        self.assertEqual(job_id, 31910)
696
        self.assertHandler(rlib2.R_2_instances_name_migrate)
697
        self.assertItems(["inst289"])
698

    
699
        data = serializer.LoadJson(self.rapi.GetLastRequestData())
700
        self.assertEqual(len(data), 2)
701
        self.assertEqual(data["mode"], mode)
702
        self.assertEqual(data["cleanup"], cleanup)
703

    
704
  def testFailoverInstanceDefaults(self):
705
    self.rapi.AddResponse("7639")
706
    job_id = self.client.FailoverInstance("inst13579")
707
    self.assertEqual(job_id, 7639)
708
    self.assertHandler(rlib2.R_2_instances_name_failover)
709
    self.assertItems(["inst13579"])
710

    
711
    data = serializer.LoadJson(self.rapi.GetLastRequestData())
712
    self.assertFalse(data)
713

    
714
  def testFailoverInstance(self):
715
    for iallocator in ["dumb", "hail"]:
716
      for ignore_consistency in [False, True]:
717
        for target_node in ["node-a", "node2"]:
718
          self.rapi.AddResponse("19161")
719
          job_id = \
720
            self.client.FailoverInstance("inst251", iallocator=iallocator,
721
                                         ignore_consistency=ignore_consistency,
722
                                         target_node=target_node)
723
          self.assertEqual(job_id, 19161)
724
          self.assertHandler(rlib2.R_2_instances_name_failover)
725
          self.assertItems(["inst251"])
726

    
727
          data = serializer.LoadJson(self.rapi.GetLastRequestData())
728
          self.assertEqual(len(data), 3)
729
          self.assertEqual(data["iallocator"], iallocator)
730
          self.assertEqual(data["ignore_consistency"], ignore_consistency)
731
          self.assertEqual(data["target_node"], target_node)
732
          self.assertEqual(self.rapi.CountPending(), 0)
733

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

    
742
    data = serializer.LoadJson(self.rapi.GetLastRequestData())
743
    self.assertEqualValues(data, {"new_name": new_name, })
744

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

    
757
        data = serializer.LoadJson(self.rapi.GetLastRequestData())
758
        self.assertEqual(len(data), 3)
759
        self.assertEqual(data["new_name"], new_name)
760
        self.assertEqual(data["ip_check"], ip_check)
761
        self.assertEqual(data["name_check"], name_check)
762

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

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

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

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

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

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

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

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

    
816
  def testEvacuateNode(self):
817
    self.rapi.AddResponse(serializer.DumpJson([rlib2._NODE_EVAC_RES1]))
818
    self.rapi.AddResponse("9876")
819
    job_id = self.client.EvacuateNode("node-1", remote_node="node-2")
820
    self.assertEqual(9876, job_id)
821
    self.assertHandler(rlib2.R_2_nodes_name_evacuate)
822
    self.assertItems(["node-1"])
823
    self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
824
                     { "remote_node": "node-2", })
825
    self.assertEqual(self.rapi.CountPending(), 0)
826

    
827
    self.rapi.AddResponse(serializer.DumpJson([rlib2._NODE_EVAC_RES1]))
828
    self.rapi.AddResponse("8888")
829
    job_id = self.client.EvacuateNode("node-3", iallocator="hail", dry_run=True,
830
                                      mode=constants.NODE_EVAC_ALL,
831
                                      early_release=True)
832
    self.assertEqual(8888, job_id)
833
    self.assertItems(["node-3"])
834
    self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()), {
835
      "iallocator": "hail",
836
      "mode": "all",
837
      "early_release": True,
838
      })
839
    self.assertDryRun()
840

    
841
    self.assertRaises(client.GanetiApiError,
842
                      self.client.EvacuateNode,
843
                      "node-4", iallocator="hail", remote_node="node-5")
844
    self.assertEqual(self.rapi.CountPending(), 0)
845

    
846
  def testEvacuateNodeOldResponse(self):
847
    self.rapi.AddResponse(serializer.DumpJson([]))
848
    self.assertRaises(client.GanetiApiError, self.client.EvacuateNode,
849
                      "node-4", accept_old=False)
850
    self.assertEqual(self.rapi.CountPending(), 0)
851

    
852
    for mode in [client.NODE_EVAC_PRI, client.NODE_EVAC_ALL]:
853
      self.rapi.AddResponse(serializer.DumpJson([]))
854
      self.assertRaises(client.GanetiApiError, self.client.EvacuateNode,
855
                        "node-4", accept_old=True, mode=mode)
856
      self.assertEqual(self.rapi.CountPending(), 0)
857

    
858
    self.rapi.AddResponse(serializer.DumpJson([]))
859
    self.rapi.AddResponse(serializer.DumpJson("21533"))
860
    result = self.client.EvacuateNode("node-3", iallocator="hail",
861
                                      dry_run=True, accept_old=True,
862
                                      mode=client.NODE_EVAC_SEC,
863
                                      early_release=True)
864
    self.assertEqual(result, "21533")
865
    self.assertItems(["node-3"])
866
    self.assertQuery("iallocator", ["hail"])
867
    self.assertQuery("early_release", ["1"])
868
    self.assertFalse(self.rapi.GetLastRequestData())
869
    self.assertDryRun()
870
    self.assertEqual(self.rapi.CountPending(), 0)
871

    
872
  def testMigrateNode(self):
873
    self.rapi.AddResponse(serializer.DumpJson([]))
874
    self.rapi.AddResponse("1111")
875
    self.assertEqual(1111, self.client.MigrateNode("node-a", dry_run=True))
876
    self.assertHandler(rlib2.R_2_nodes_name_migrate)
877
    self.assertItems(["node-a"])
878
    self.assert_("mode" not in self.rapi.GetLastHandler().queryargs)
879
    self.assertDryRun()
880
    self.assertFalse(self.rapi.GetLastRequestData())
881

    
882
    self.rapi.AddResponse(serializer.DumpJson([]))
883
    self.rapi.AddResponse("1112")
884
    self.assertEqual(1112, self.client.MigrateNode("node-a", dry_run=True,
885
                                                   mode="live"))
886
    self.assertHandler(rlib2.R_2_nodes_name_migrate)
887
    self.assertItems(["node-a"])
888
    self.assertQuery("mode", ["live"])
889
    self.assertDryRun()
890
    self.assertFalse(self.rapi.GetLastRequestData())
891

    
892
    self.rapi.AddResponse(serializer.DumpJson([]))
893
    self.assertRaises(client.GanetiApiError, self.client.MigrateNode,
894
                      "node-c", target_node="foonode")
895
    self.assertEqual(self.rapi.CountPending(), 0)
896

    
897
  def testMigrateNodeBodyData(self):
898
    self.rapi.AddResponse(serializer.DumpJson([rlib2._NODE_MIGRATE_REQV1]))
899
    self.rapi.AddResponse("27539")
900
    self.assertEqual(27539, self.client.MigrateNode("node-a", dry_run=False,
901
                                                    mode="live"))
902
    self.assertHandler(rlib2.R_2_nodes_name_migrate)
903
    self.assertItems(["node-a"])
904
    self.assertFalse(self.rapi.GetLastHandler().queryargs)
905
    self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
906
                     { "mode": "live", })
907

    
908
    self.rapi.AddResponse(serializer.DumpJson([rlib2._NODE_MIGRATE_REQV1]))
909
    self.rapi.AddResponse("14219")
910
    self.assertEqual(14219, self.client.MigrateNode("node-x", dry_run=True,
911
                                                    target_node="node9",
912
                                                    iallocator="ial"))
913
    self.assertHandler(rlib2.R_2_nodes_name_migrate)
914
    self.assertItems(["node-x"])
915
    self.assertDryRun()
916
    self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
917
                     { "target_node": "node9", "iallocator": "ial", })
918

    
919
    self.assertEqual(self.rapi.CountPending(), 0)
920

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

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

    
936
  def testPowercycleNode(self):
937
    self.rapi.AddResponse("23051")
938
    self.assertEqual(23051,
939
        self.client.PowercycleNode("node5468", force=True))
940
    self.assertHandler(rlib2.R_2_nodes_name_powercycle)
941
    self.assertItems(["node5468"])
942
    self.assertQuery("force", ["1"])
943
    self.assertFalse(self.rapi.GetLastRequestData())
944
    self.assertEqual(self.rapi.CountPending(), 0)
945

    
946
  def testModifyNode(self):
947
    self.rapi.AddResponse("3783")
948
    job_id = self.client.ModifyNode("node16979.example.com", drained=True)
949
    self.assertEqual(job_id, 3783)
950
    self.assertHandler(rlib2.R_2_nodes_name_modify)
951
    self.assertItems(["node16979.example.com"])
952
    self.assertEqual(self.rapi.CountPending(), 0)
953

    
954
  def testGetNodeStorageUnits(self):
955
    self.rapi.AddResponse("42")
956
    self.assertEqual(42,
957
        self.client.GetNodeStorageUnits("node-x", "lvm-pv", "fields"))
958
    self.assertHandler(rlib2.R_2_nodes_name_storage)
959
    self.assertItems(["node-x"])
960
    self.assertQuery("storage_type", ["lvm-pv"])
961
    self.assertQuery("output_fields", ["fields"])
962

    
963
  def testModifyNodeStorageUnits(self):
964
    self.rapi.AddResponse("14")
965
    self.assertEqual(14,
966
        self.client.ModifyNodeStorageUnits("node-z", "lvm-pv", "hda"))
967
    self.assertHandler(rlib2.R_2_nodes_name_storage_modify)
968
    self.assertItems(["node-z"])
969
    self.assertQuery("storage_type", ["lvm-pv"])
970
    self.assertQuery("name", ["hda"])
971
    self.assertQuery("allocatable", None)
972

    
973
    for allocatable, query_allocatable in [(True, "1"), (False, "0")]:
974
      self.rapi.AddResponse("7205")
975
      job_id = self.client.ModifyNodeStorageUnits("node-z", "lvm-pv", "hda",
976
                                                  allocatable=allocatable)
977
      self.assertEqual(7205, job_id)
978
      self.assertHandler(rlib2.R_2_nodes_name_storage_modify)
979
      self.assertItems(["node-z"])
980
      self.assertQuery("storage_type", ["lvm-pv"])
981
      self.assertQuery("name", ["hda"])
982
      self.assertQuery("allocatable", [query_allocatable])
983

    
984
  def testRepairNodeStorageUnits(self):
985
    self.rapi.AddResponse("99")
986
    self.assertEqual(99, self.client.RepairNodeStorageUnits("node-z", "lvm-pv",
987
                                                            "hda"))
988
    self.assertHandler(rlib2.R_2_nodes_name_storage_repair)
989
    self.assertItems(["node-z"])
990
    self.assertQuery("storage_type", ["lvm-pv"])
991
    self.assertQuery("name", ["hda"])
992

    
993
  def testGetNodeTags(self):
994
    self.rapi.AddResponse("[\"fry\", \"bender\"]")
995
    self.assertEqual(["fry", "bender"], self.client.GetNodeTags("node-k"))
996
    self.assertHandler(rlib2.R_2_nodes_name_tags)
997
    self.assertItems(["node-k"])
998

    
999
  def testAddNodeTags(self):
1000
    self.rapi.AddResponse("1234")
1001
    self.assertEqual(1234,
1002
        self.client.AddNodeTags("node-v", ["awesome"], dry_run=True))
1003
    self.assertHandler(rlib2.R_2_nodes_name_tags)
1004
    self.assertItems(["node-v"])
1005
    self.assertDryRun()
1006
    self.assertQuery("tag", ["awesome"])
1007

    
1008
  def testDeleteNodeTags(self):
1009
    self.rapi.AddResponse("16861")
1010
    self.assertEqual(16861, self.client.DeleteNodeTags("node-w", ["awesome"],
1011
                                                       dry_run=True))
1012
    self.assertHandler(rlib2.R_2_nodes_name_tags)
1013
    self.assertItems(["node-w"])
1014
    self.assertDryRun()
1015
    self.assertQuery("tag", ["awesome"])
1016

    
1017
  def testGetGroups(self):
1018
    groups = [{"name": "group1",
1019
               "uri": "/2/groups/group1",
1020
               },
1021
              {"name": "group2",
1022
               "uri": "/2/groups/group2",
1023
               },
1024
              ]
1025
    self.rapi.AddResponse(serializer.DumpJson(groups))
1026
    self.assertEqual(["group1", "group2"], self.client.GetGroups())
1027
    self.assertHandler(rlib2.R_2_groups)
1028

    
1029
  def testGetGroupsBulk(self):
1030
    groups = [{"name": "group1",
1031
               "uri": "/2/groups/group1",
1032
               "node_cnt": 2,
1033
               "node_list": ["gnt1.test",
1034
                             "gnt2.test",
1035
                             ],
1036
               },
1037
              {"name": "group2",
1038
               "uri": "/2/groups/group2",
1039
               "node_cnt": 1,
1040
               "node_list": ["gnt3.test",
1041
                             ],
1042
               },
1043
              ]
1044
    self.rapi.AddResponse(serializer.DumpJson(groups))
1045

    
1046
    self.assertEqual(groups, self.client.GetGroups(bulk=True))
1047
    self.assertHandler(rlib2.R_2_groups)
1048
    self.assertBulk()
1049

    
1050
  def testGetGroup(self):
1051
    group = {"ctime": None,
1052
             "name": "default",
1053
             }
1054
    self.rapi.AddResponse(serializer.DumpJson(group))
1055
    self.assertEqual({"ctime": None, "name": "default"},
1056
                     self.client.GetGroup("default"))
1057
    self.assertHandler(rlib2.R_2_groups_name)
1058
    self.assertItems(["default"])
1059

    
1060
  def testCreateGroup(self):
1061
    self.rapi.AddResponse("12345")
1062
    job_id = self.client.CreateGroup("newgroup", dry_run=True)
1063
    self.assertEqual(job_id, 12345)
1064
    self.assertHandler(rlib2.R_2_groups)
1065
    self.assertDryRun()
1066

    
1067
  def testDeleteGroup(self):
1068
    self.rapi.AddResponse("12346")
1069
    job_id = self.client.DeleteGroup("newgroup", dry_run=True)
1070
    self.assertEqual(job_id, 12346)
1071
    self.assertHandler(rlib2.R_2_groups_name)
1072
    self.assertDryRun()
1073

    
1074
  def testRenameGroup(self):
1075
    self.rapi.AddResponse("12347")
1076
    job_id = self.client.RenameGroup("oldname", "newname")
1077
    self.assertEqual(job_id, 12347)
1078
    self.assertHandler(rlib2.R_2_groups_name_rename)
1079

    
1080
  def testModifyGroup(self):
1081
    self.rapi.AddResponse("12348")
1082
    job_id = self.client.ModifyGroup("mygroup", alloc_policy="foo")
1083
    self.assertEqual(job_id, 12348)
1084
    self.assertHandler(rlib2.R_2_groups_name_modify)
1085

    
1086
  def testAssignGroupNodes(self):
1087
    self.rapi.AddResponse("12349")
1088
    job_id = self.client.AssignGroupNodes("mygroup", ["node1", "node2"],
1089
                                          force=True, dry_run=True)
1090
    self.assertEqual(job_id, 12349)
1091
    self.assertHandler(rlib2.R_2_groups_name_assign_nodes)
1092
    self.assertDryRun()
1093
    self.assertUseForce()
1094

    
1095
  def testModifyInstance(self):
1096
    self.rapi.AddResponse("23681")
1097
    job_id = self.client.ModifyInstance("inst7210", os_name="linux")
1098
    self.assertEqual(job_id, 23681)
1099
    self.assertItems(["inst7210"])
1100
    self.assertHandler(rlib2.R_2_instances_name_modify)
1101
    self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
1102
                     { "os_name": "linux", })
1103

    
1104
  def testModifyCluster(self):
1105
    for mnh in [None, False, True]:
1106
      self.rapi.AddResponse("14470")
1107
      self.assertEqual(14470,
1108
        self.client.ModifyCluster(maintain_node_health=mnh))
1109
      self.assertHandler(rlib2.R_2_cluster_modify)
1110
      self.assertItems([])
1111
      data = serializer.LoadJson(self.rapi.GetLastRequestData())
1112
      self.assertEqual(len(data), 1)
1113
      self.assertEqual(data["maintain_node_health"], mnh)
1114
      self.assertEqual(self.rapi.CountPending(), 0)
1115

    
1116
  def testRedistributeConfig(self):
1117
    self.rapi.AddResponse("3364")
1118
    job_id = self.client.RedistributeConfig()
1119
    self.assertEqual(job_id, 3364)
1120
    self.assertItems([])
1121
    self.assertHandler(rlib2.R_2_redist_config)
1122

    
1123
  def testActivateInstanceDisks(self):
1124
    self.rapi.AddResponse("23547")
1125
    job_id = self.client.ActivateInstanceDisks("inst28204")
1126
    self.assertEqual(job_id, 23547)
1127
    self.assertItems(["inst28204"])
1128
    self.assertHandler(rlib2.R_2_instances_name_activate_disks)
1129
    self.assertFalse(self.rapi.GetLastHandler().queryargs)
1130

    
1131
  def testActivateInstanceDisksIgnoreSize(self):
1132
    self.rapi.AddResponse("11044")
1133
    job_id = self.client.ActivateInstanceDisks("inst28204", ignore_size=True)
1134
    self.assertEqual(job_id, 11044)
1135
    self.assertItems(["inst28204"])
1136
    self.assertHandler(rlib2.R_2_instances_name_activate_disks)
1137
    self.assertQuery("ignore_size", ["1"])
1138

    
1139
  def testDeactivateInstanceDisks(self):
1140
    self.rapi.AddResponse("14591")
1141
    job_id = self.client.DeactivateInstanceDisks("inst28234")
1142
    self.assertEqual(job_id, 14591)
1143
    self.assertItems(["inst28234"])
1144
    self.assertHandler(rlib2.R_2_instances_name_deactivate_disks)
1145
    self.assertFalse(self.rapi.GetLastHandler().queryargs)
1146

    
1147
  def testRecreateInstanceDisks(self):
1148
    self.rapi.AddResponse("13553")
1149
    job_id = self.client.RecreateInstanceDisks("inst23153")
1150
    self.assertEqual(job_id, 13553)
1151
    self.assertItems(["inst23153"])
1152
    self.assertHandler(rlib2.R_2_instances_name_recreate_disks)
1153
    self.assertFalse(self.rapi.GetLastHandler().queryargs)
1154

    
1155
  def testGetInstanceConsole(self):
1156
    self.rapi.AddResponse("26876")
1157
    job_id = self.client.GetInstanceConsole("inst21491")
1158
    self.assertEqual(job_id, 26876)
1159
    self.assertItems(["inst21491"])
1160
    self.assertHandler(rlib2.R_2_instances_name_console)
1161
    self.assertFalse(self.rapi.GetLastHandler().queryargs)
1162
    self.assertFalse(self.rapi.GetLastRequestData())
1163

    
1164
  def testGrowInstanceDisk(self):
1165
    for idx, wait_for_sync in enumerate([None, False, True]):
1166
      amount = 128 + (512 * idx)
1167
      self.assertEqual(self.rapi.CountPending(), 0)
1168
      self.rapi.AddResponse("30783")
1169
      self.assertEqual(30783,
1170
        self.client.GrowInstanceDisk("eze8ch", idx, amount,
1171
                                     wait_for_sync=wait_for_sync))
1172
      self.assertHandler(rlib2.R_2_instances_name_disk_grow)
1173
      self.assertItems(["eze8ch", str(idx)])
1174
      data = serializer.LoadJson(self.rapi.GetLastRequestData())
1175
      if wait_for_sync is None:
1176
        self.assertEqual(len(data), 1)
1177
        self.assert_("wait_for_sync" not in data)
1178
      else:
1179
        self.assertEqual(len(data), 2)
1180
        self.assertEqual(data["wait_for_sync"], wait_for_sync)
1181
      self.assertEqual(data["amount"], amount)
1182
      self.assertEqual(self.rapi.CountPending(), 0)
1183

    
1184
  def testGetGroupTags(self):
1185
    self.rapi.AddResponse("[]")
1186
    self.assertEqual([], self.client.GetGroupTags("fooGroup"))
1187
    self.assertHandler(rlib2.R_2_groups_name_tags)
1188
    self.assertItems(["fooGroup"])
1189

    
1190
  def testAddGroupTags(self):
1191
    self.rapi.AddResponse("1234")
1192
    self.assertEqual(1234,
1193
        self.client.AddGroupTags("fooGroup", ["awesome"], dry_run=True))
1194
    self.assertHandler(rlib2.R_2_groups_name_tags)
1195
    self.assertItems(["fooGroup"])
1196
    self.assertDryRun()
1197
    self.assertQuery("tag", ["awesome"])
1198

    
1199
  def testDeleteGroupTags(self):
1200
    self.rapi.AddResponse("25826")
1201
    self.assertEqual(25826, self.client.DeleteGroupTags("foo", ["awesome"],
1202
                                                        dry_run=True))
1203
    self.assertHandler(rlib2.R_2_groups_name_tags)
1204
    self.assertItems(["foo"])
1205
    self.assertDryRun()
1206
    self.assertQuery("tag", ["awesome"])
1207

    
1208
  def testQuery(self):
1209
    for idx, what in enumerate(constants.QR_VIA_RAPI):
1210
      for idx2, qfilter in enumerate([None, ["?", "name"]]):
1211
        job_id = 11010 + (idx << 4) + (idx2 << 16)
1212
        fields = sorted(query.ALL_FIELDS[what].keys())[:10]
1213

    
1214
        self.rapi.AddResponse(str(job_id))
1215
        self.assertEqual(self.client.Query(what, fields, qfilter=qfilter),
1216
                         job_id)
1217
        self.assertItems([what])
1218
        self.assertHandler(rlib2.R_2_query)
1219
        self.assertFalse(self.rapi.GetLastHandler().queryargs)
1220
        data = serializer.LoadJson(self.rapi.GetLastRequestData())
1221
        self.assertEqual(data["fields"], fields)
1222
        if qfilter is None:
1223
          self.assertTrue("qfilter" not in data)
1224
        else:
1225
          self.assertEqual(data["qfilter"], qfilter)
1226
        self.assertEqual(self.rapi.CountPending(), 0)
1227

    
1228
  def testQueryFields(self):
1229
    exp_result = objects.QueryFieldsResponse(fields=[
1230
      objects.QueryFieldDefinition(name="pnode", title="PNode",
1231
                                   kind=constants.QFT_NUMBER),
1232
      objects.QueryFieldDefinition(name="other", title="Other",
1233
                                   kind=constants.QFT_BOOL),
1234
      ])
1235

    
1236
    for what in constants.QR_VIA_RAPI:
1237
      for fields in [None, ["name", "_unknown_"], ["&", "?|"]]:
1238
        self.rapi.AddResponse(serializer.DumpJson(exp_result.ToDict()))
1239
        result = self.client.QueryFields(what, fields=fields)
1240
        self.assertItems([what])
1241
        self.assertHandler(rlib2.R_2_query_fields)
1242
        self.assertFalse(self.rapi.GetLastRequestData())
1243

    
1244
        queryargs = self.rapi.GetLastHandler().queryargs
1245
        if fields is None:
1246
          self.assertFalse(queryargs)
1247
        else:
1248
          self.assertEqual(queryargs, {
1249
            "fields": [",".join(fields)],
1250
            })
1251

    
1252
        self.assertEqual(objects.QueryFieldsResponse.FromDict(result).ToDict(),
1253
                         exp_result.ToDict())
1254

    
1255
        self.assertEqual(self.rapi.CountPending(), 0)
1256

    
1257
  def testWaitForJobCompletionNoChange(self):
1258
    resp = serializer.DumpJson({
1259
      "status": constants.JOB_STATUS_WAITING,
1260
      })
1261

    
1262
    for retries in [1, 5, 25]:
1263
      for _ in range(retries):
1264
        self.rapi.AddResponse(resp)
1265

    
1266
      self.assertFalse(self.client.WaitForJobCompletion(22789, period=None,
1267
                                                        retries=retries))
1268
      self.assertHandler(rlib2.R_2_jobs_id)
1269
      self.assertItems(["22789"])
1270

    
1271
      self.assertEqual(self.rapi.CountPending(), 0)
1272

    
1273
  def testWaitForJobCompletionAlreadyFinished(self):
1274
    self.rapi.AddResponse(serializer.DumpJson({
1275
      "status": constants.JOB_STATUS_SUCCESS,
1276
      }))
1277

    
1278
    self.assertTrue(self.client.WaitForJobCompletion(22793, period=None,
1279
                                                     retries=1))
1280
    self.assertHandler(rlib2.R_2_jobs_id)
1281
    self.assertItems(["22793"])
1282

    
1283
    self.assertEqual(self.rapi.CountPending(), 0)
1284

    
1285
  def testWaitForJobCompletionEmptyResponse(self):
1286
    self.rapi.AddResponse("{}")
1287
    self.assertFalse(self.client.WaitForJobCompletion(22793, period=None,
1288
                                                     retries=10))
1289
    self.assertHandler(rlib2.R_2_jobs_id)
1290
    self.assertItems(["22793"])
1291

    
1292
    self.assertEqual(self.rapi.CountPending(), 0)
1293

    
1294
  def testWaitForJobCompletionOutOfRetries(self):
1295
    for retries in [3, 10, 21]:
1296
      for _ in range(retries):
1297
        self.rapi.AddResponse(serializer.DumpJson({
1298
          "status": constants.JOB_STATUS_RUNNING,
1299
          }))
1300

    
1301
      self.assertFalse(self.client.WaitForJobCompletion(30948, period=None,
1302
                                                        retries=retries - 1))
1303
      self.assertHandler(rlib2.R_2_jobs_id)
1304
      self.assertItems(["30948"])
1305

    
1306
      self.assertEqual(self.rapi.CountPending(), 1)
1307
      self.rapi.ResetResponses()
1308

    
1309
  def testWaitForJobCompletionSuccessAndFailure(self):
1310
    for retries in [1, 4, 13]:
1311
      for (success, end_status) in [(False, constants.JOB_STATUS_ERROR),
1312
                                    (True, constants.JOB_STATUS_SUCCESS)]:
1313
        for _ in range(retries):
1314
          self.rapi.AddResponse(serializer.DumpJson({
1315
            "status": constants.JOB_STATUS_RUNNING,
1316
            }))
1317

    
1318
        self.rapi.AddResponse(serializer.DumpJson({
1319
          "status": end_status,
1320
          }))
1321

    
1322
        result = self.client.WaitForJobCompletion(3187, period=None,
1323
                                                  retries=retries + 1)
1324
        self.assertEqual(result, success)
1325
        self.assertHandler(rlib2.R_2_jobs_id)
1326
        self.assertItems(["3187"])
1327

    
1328
        self.assertEqual(self.rapi.CountPending(), 0)
1329

    
1330

    
1331
class RapiTestRunner(unittest.TextTestRunner):
1332
  def run(self, *args):
1333
    global _used_handlers
1334
    assert _used_handlers is None
1335

    
1336
    _used_handlers = set()
1337
    try:
1338
      # Run actual tests
1339
      result = unittest.TextTestRunner.run(self, *args)
1340

    
1341
      diff = (set(connector.CONNECTOR.values()) - _used_handlers -
1342
             _KNOWN_UNUSED)
1343
      if diff:
1344
        raise AssertionError("The following RAPI resources were not used by the"
1345
                             " RAPI client: %r" % utils.CommaJoin(diff))
1346
    finally:
1347
      # Reset global variable
1348
      _used_handlers = None
1349

    
1350
    return result
1351

    
1352

    
1353
if __name__ == '__main__':
1354
  client.UsesRapiClient(testutils.GanetiTestProgram)(testRunner=RapiTestRunner)