Statistics
| Branch: | Tag: | Revision:

root / test / ganeti.rapi.client_unittest.py @ 0351944b

History | View | Annotate | Download (51.4 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, NotImplemented, 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 test404(self):
140
    (code, _, body) = RapiMock().FetchResponse("/foo", "GET", None, None)
141
    self.assertEqual(code, 404)
142
    self.assertTrue(body is None)
143

    
144
  def test501(self):
145
    (code, _, body) = RapiMock().FetchResponse("/version", "POST", None, None)
146
    self.assertEqual(code, 501)
147
    self.assertEqual(body, "Method not implemented")
148

    
149
  def test200(self):
150
    rapi = RapiMock()
151
    rapi.AddResponse("2")
152
    (code, _, response) = rapi.FetchResponse("/version", "GET", None, None)
153
    self.assertEqual(200, code)
154
    self.assertEqual("2", response)
155
    self.failUnless(isinstance(rapi.GetLastHandler(), rlib2.R_version))
156

    
157

    
158
def _FakeNoSslPycurlVersion():
159
  # Note: incomplete version tuple
160
  return (3, "7.16.0", 462848, "mysystem", 1581, None, 0)
161

    
162

    
163
def _FakeFancySslPycurlVersion():
164
  # Note: incomplete version tuple
165
  return (3, "7.16.0", 462848, "mysystem", 1581, "FancySSL/1.2.3", 0)
166

    
167

    
168
def _FakeOpenSslPycurlVersion():
169
  # Note: incomplete version tuple
170
  return (2, "7.15.5", 462597, "othersystem", 668, "OpenSSL/0.9.8c", 0)
171

    
172

    
173
def _FakeGnuTlsPycurlVersion():
174
  # Note: incomplete version tuple
175
  return (3, "7.18.0", 463360, "somesystem", 1581, "GnuTLS/2.0.4", 0)
176

    
177

    
178
class TestExtendedConfig(unittest.TestCase):
179
  def testAuth(self):
180
    cl = client.GanetiRapiClient("master.example.com",
181
      username="user", password="pw",
182
      curl_factory=lambda: rapi.testutils.FakeCurl(RapiMock()))
183

    
184
    curl = cl._CreateCurl()
185
    self.assertEqual(curl.getopt(pycurl.HTTPAUTH), pycurl.HTTPAUTH_BASIC)
186
    self.assertEqual(curl.getopt(pycurl.USERPWD), "user:pw")
187

    
188
  def testInvalidAuth(self):
189
    # No username
190
    self.assertRaises(client.Error, client.GanetiRapiClient,
191
                      "master-a.example.com", password="pw")
192
    # No password
193
    self.assertRaises(client.Error, client.GanetiRapiClient,
194
                      "master-b.example.com", username="user")
195

    
196
  def testCertVerifyInvalidCombinations(self):
197
    self.assertRaises(client.Error, client.GenericCurlConfig,
198
                      use_curl_cabundle=True, cafile="cert1.pem")
199
    self.assertRaises(client.Error, client.GenericCurlConfig,
200
                      use_curl_cabundle=True, capath="certs/")
201
    self.assertRaises(client.Error, client.GenericCurlConfig,
202
                      use_curl_cabundle=True,
203
                      cafile="cert1.pem", capath="certs/")
204

    
205
  def testProxySignalVerifyHostname(self):
206
    for use_gnutls in [False, True]:
207
      if use_gnutls:
208
        pcverfn = _FakeGnuTlsPycurlVersion
209
      else:
210
        pcverfn = _FakeOpenSslPycurlVersion
211

    
212
      for proxy in ["", "http://127.0.0.1:1234"]:
213
        for use_signal in [False, True]:
214
          for verify_hostname in [False, True]:
215
            cfgfn = client.GenericCurlConfig(proxy=proxy, use_signal=use_signal,
216
                                             verify_hostname=verify_hostname,
217
                                             _pycurl_version_fn=pcverfn)
218

    
219
            curl_factory = lambda: rapi.testutils.FakeCurl(RapiMock())
220
            cl = client.GanetiRapiClient("master.example.com",
221
                                         curl_config_fn=cfgfn,
222
                                         curl_factory=curl_factory)
223

    
224
            curl = cl._CreateCurl()
225
            self.assertEqual(curl.getopt(pycurl.PROXY), proxy)
226
            self.assertEqual(curl.getopt(pycurl.NOSIGNAL), not use_signal)
227

    
228
            if verify_hostname:
229
              self.assertEqual(curl.getopt(pycurl.SSL_VERIFYHOST), 2)
230
            else:
231
              self.assertEqual(curl.getopt(pycurl.SSL_VERIFYHOST), 0)
232

    
233
  def testNoCertVerify(self):
234
    cfgfn = client.GenericCurlConfig()
235

    
236
    curl_factory = lambda: rapi.testutils.FakeCurl(RapiMock())
237
    cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
238
                                 curl_factory=curl_factory)
239

    
240
    curl = cl._CreateCurl()
241
    self.assertFalse(curl.getopt(pycurl.SSL_VERIFYPEER))
242
    self.assertFalse(curl.getopt(pycurl.CAINFO))
243
    self.assertFalse(curl.getopt(pycurl.CAPATH))
244

    
245
  def testCertVerifyCurlBundle(self):
246
    cfgfn = client.GenericCurlConfig(use_curl_cabundle=True)
247

    
248
    curl_factory = lambda: rapi.testutils.FakeCurl(RapiMock())
249
    cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
250
                                 curl_factory=curl_factory)
251

    
252
    curl = cl._CreateCurl()
253
    self.assert_(curl.getopt(pycurl.SSL_VERIFYPEER))
254
    self.assertFalse(curl.getopt(pycurl.CAINFO))
255
    self.assertFalse(curl.getopt(pycurl.CAPATH))
256

    
257
  def testCertVerifyCafile(self):
258
    mycert = "/tmp/some/UNUSED/cert/file.pem"
259
    cfgfn = client.GenericCurlConfig(cafile=mycert)
260

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

    
265
    curl = cl._CreateCurl()
266
    self.assert_(curl.getopt(pycurl.SSL_VERIFYPEER))
267
    self.assertEqual(curl.getopt(pycurl.CAINFO), mycert)
268
    self.assertFalse(curl.getopt(pycurl.CAPATH))
269

    
270
  def testCertVerifyCapath(self):
271
    certdir = "/tmp/some/UNUSED/cert/directory"
272
    pcverfn = _FakeOpenSslPycurlVersion
273
    cfgfn = client.GenericCurlConfig(capath=certdir,
274
                                     _pycurl_version_fn=pcverfn)
275

    
276
    curl_factory = lambda: rapi.testutils.FakeCurl(RapiMock())
277
    cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
278
                                 curl_factory=curl_factory)
279

    
280
    curl = cl._CreateCurl()
281
    self.assert_(curl.getopt(pycurl.SSL_VERIFYPEER))
282
    self.assertEqual(curl.getopt(pycurl.CAPATH), certdir)
283
    self.assertFalse(curl.getopt(pycurl.CAINFO))
284

    
285
  def testCertVerifyCapathGnuTls(self):
286
    certdir = "/tmp/some/UNUSED/cert/directory"
287
    pcverfn = _FakeGnuTlsPycurlVersion
288
    cfgfn = client.GenericCurlConfig(capath=certdir,
289
                                     _pycurl_version_fn=pcverfn)
290

    
291
    curl_factory = lambda: rapi.testutils.FakeCurl(RapiMock())
292
    cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
293
                                 curl_factory=curl_factory)
294

    
295
    self.assertRaises(client.Error, cl._CreateCurl)
296

    
297
  def testCertVerifyNoSsl(self):
298
    certdir = "/tmp/some/UNUSED/cert/directory"
299
    pcverfn = _FakeNoSslPycurlVersion
300
    cfgfn = client.GenericCurlConfig(capath=certdir,
301
                                     _pycurl_version_fn=pcverfn)
302

    
303
    curl_factory = lambda: rapi.testutils.FakeCurl(RapiMock())
304
    cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
305
                                 curl_factory=curl_factory)
306

    
307
    self.assertRaises(client.Error, cl._CreateCurl)
308

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

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

    
319
    self.assertRaises(NotImplementedError, cl._CreateCurl)
320

    
321
  def testCertVerifyCapath(self):
322
    for connect_timeout in [None, 1, 5, 10, 30, 60, 300]:
323
      for timeout in [None, 1, 30, 60, 3600, 24 * 3600]:
324
        cfgfn = client.GenericCurlConfig(connect_timeout=connect_timeout,
325
                                         timeout=timeout)
326

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

    
331
        curl = cl._CreateCurl()
332
        self.assertEqual(curl.getopt(pycurl.CONNECTTIMEOUT), connect_timeout)
333
        self.assertEqual(curl.getopt(pycurl.TIMEOUT), timeout)
334

    
335

    
336
class GanetiRapiClientTests(testutils.GanetiTestCase):
337
  def setUp(self):
338
    testutils.GanetiTestCase.setUp(self)
339

    
340
    self.rapi = RapiMock()
341
    self.curl = rapi.testutils.FakeCurl(self.rapi)
342
    self.client = client.GanetiRapiClient("master.example.com",
343
                                          curl_factory=lambda: self.curl)
344

    
345
  def assertHandler(self, handler_cls):
346
    self.failUnless(isinstance(self.rapi.GetLastHandler(), handler_cls))
347

    
348
  def assertQuery(self, key, value):
349
    self.assertEqual(value, self.rapi.GetLastHandler().queryargs.get(key, None))
350

    
351
  def assertItems(self, items):
352
    self.assertEqual(items, self.rapi.GetLastHandler().items)
353

    
354
  def assertBulk(self):
355
    self.assertTrue(self.rapi.GetLastHandler().useBulk())
356

    
357
  def assertDryRun(self):
358
    self.assertTrue(self.rapi.GetLastHandler().dryRun())
359

    
360
  def assertUseForce(self):
361
    self.assertTrue(self.rapi.GetLastHandler().useForce())
362

    
363
  def testEncodeQuery(self):
364
    query = [
365
      ("a", None),
366
      ("b", 1),
367
      ("c", 2),
368
      ("d", "Foo"),
369
      ("e", True),
370
      ]
371

    
372
    expected = [
373
      ("a", ""),
374
      ("b", 1),
375
      ("c", 2),
376
      ("d", "Foo"),
377
      ("e", 1),
378
      ]
379

    
380
    self.assertEqualValues(self.client._EncodeQuery(query),
381
                           expected)
382

    
383
    # invalid types
384
    for i in [[1, 2, 3], {"moo": "boo"}, (1, 2, 3)]:
385
      self.assertRaises(ValueError, self.client._EncodeQuery, [("x", i)])
386

    
387
  def testCurlSettings(self):
388
    self.rapi.AddResponse("2")
389
    self.assertEqual(2, self.client.GetVersion())
390
    self.assertHandler(rlib2.R_version)
391

    
392
    # Signals should be disabled by default
393
    self.assert_(self.curl.getopt(pycurl.NOSIGNAL))
394

    
395
    # No auth and no proxy
396
    self.assertFalse(self.curl.getopt(pycurl.USERPWD))
397
    self.assert_(self.curl.getopt(pycurl.PROXY) is None)
398

    
399
    # Content-type is required for requests
400
    headers = self.curl.getopt(pycurl.HTTPHEADER)
401
    self.assert_("Content-type: application/json" in headers)
402

    
403
  def testHttpError(self):
404
    self.rapi.AddResponse(None, code=404)
405
    try:
406
      self.client.GetJobStatus(15140)
407
    except client.GanetiApiError, err:
408
      self.assertEqual(err.code, 404)
409
    else:
410
      self.fail("Didn't raise exception")
411

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

    
417
  def testGetFeatures(self):
418
    for features in [[], ["foo", "bar", "baz"]]:
419
      self.rapi.AddResponse(serializer.DumpJson(features))
420
      self.assertEqual(features, self.client.GetFeatures())
421
      self.assertHandler(rlib2.R_2_features)
422

    
423
  def testGetFeaturesNotFound(self):
424
    self.rapi.AddResponse(None, code=404)
425
    self.assertEqual([], self.client.GetFeatures())
426

    
427
  def testGetOperatingSystems(self):
428
    self.rapi.AddResponse("[\"beos\"]")
429
    self.assertEqual(["beos"], self.client.GetOperatingSystems())
430
    self.assertHandler(rlib2.R_2_os)
431

    
432
  def testGetClusterTags(self):
433
    self.rapi.AddResponse("[\"tag\"]")
434
    self.assertEqual(["tag"], self.client.GetClusterTags())
435
    self.assertHandler(rlib2.R_2_tags)
436

    
437
  def testAddClusterTags(self):
438
    self.rapi.AddResponse("1234")
439
    self.assertEqual(1234,
440
        self.client.AddClusterTags(["awesome"], dry_run=True))
441
    self.assertHandler(rlib2.R_2_tags)
442
    self.assertDryRun()
443
    self.assertQuery("tag", ["awesome"])
444

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

    
453
  def testGetInfo(self):
454
    self.rapi.AddResponse("{}")
455
    self.assertEqual({}, self.client.GetInfo())
456
    self.assertHandler(rlib2.R_2_info)
457

    
458
  def testGetInstances(self):
459
    self.rapi.AddResponse("[]")
460
    self.assertEqual([], self.client.GetInstances(bulk=True))
461
    self.assertHandler(rlib2.R_2_instances)
462
    self.assertBulk()
463

    
464
  def testGetInstance(self):
465
    self.rapi.AddResponse("[]")
466
    self.assertEqual([], self.client.GetInstance("instance"))
467
    self.assertHandler(rlib2.R_2_instances_name)
468
    self.assertItems(["instance"])
469

    
470
  def testGetInstanceInfo(self):
471
    self.rapi.AddResponse("21291")
472
    self.assertEqual(21291, self.client.GetInstanceInfo("inst3"))
473
    self.assertHandler(rlib2.R_2_instances_name_info)
474
    self.assertItems(["inst3"])
475
    self.assertQuery("static", None)
476

    
477
    self.rapi.AddResponse("3428")
478
    self.assertEqual(3428, self.client.GetInstanceInfo("inst31", static=False))
479
    self.assertHandler(rlib2.R_2_instances_name_info)
480
    self.assertItems(["inst31"])
481
    self.assertQuery("static", ["0"])
482

    
483
    self.rapi.AddResponse("15665")
484
    self.assertEqual(15665, self.client.GetInstanceInfo("inst32", static=True))
485
    self.assertHandler(rlib2.R_2_instances_name_info)
486
    self.assertItems(["inst32"])
487
    self.assertQuery("static", ["1"])
488

    
489
  def testCreateInstanceOldVersion(self):
490
    # The old request format, version 0, is no longer supported
491
    self.rapi.AddResponse(None, code=404)
492
    self.assertRaises(client.GanetiApiError, self.client.CreateInstance,
493
                      "create", "inst1.example.com", "plain", [], [])
494
    self.assertEqual(self.rapi.CountPending(), 0)
495

    
496
  def testCreateInstance(self):
497
    self.rapi.AddResponse(serializer.DumpJson([rlib2._INST_CREATE_REQV1]))
498
    self.rapi.AddResponse("23030")
499
    job_id = self.client.CreateInstance("create", "inst1.example.com",
500
                                        "plain", [], [], dry_run=True)
501
    self.assertEqual(job_id, 23030)
502
    self.assertHandler(rlib2.R_2_instances)
503
    self.assertDryRun()
504

    
505
    data = serializer.LoadJson(self.rapi.GetLastRequestData())
506

    
507
    for field in ["dry_run", "beparams", "hvparams", "start"]:
508
      self.assertFalse(field in data)
509

    
510
    self.assertEqual(data["name"], "inst1.example.com")
511
    self.assertEqual(data["disk_template"], "plain")
512

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

    
525
    data = serializer.LoadJson(self.rapi.GetLastRequestData())
526
    self.assertEqual(data[rlib2._REQ_DATA_VERSION], 1)
527
    self.assertEqual(data["name"], "inst2.example.com")
528
    self.assertEqual(data["disk_template"], "drbd8")
529
    self.assertEqual(data["start"], True)
530
    self.assertEqual(data["ip_check"], False)
531
    self.assertEqualValues(data["disks"], [{"size": 100,}])
532
    self.assertEqualValues(data["nics"], [{}, {"bridge": "br1", }])
533

    
534
  def testDeleteInstance(self):
535
    self.rapi.AddResponse("1234")
536
    self.assertEqual(1234, self.client.DeleteInstance("instance", dry_run=True))
537
    self.assertHandler(rlib2.R_2_instances_name)
538
    self.assertItems(["instance"])
539
    self.assertDryRun()
540

    
541
  def testGetInstanceTags(self):
542
    self.rapi.AddResponse("[]")
543
    self.assertEqual([], self.client.GetInstanceTags("fooinstance"))
544
    self.assertHandler(rlib2.R_2_instances_name_tags)
545
    self.assertItems(["fooinstance"])
546

    
547
  def testAddInstanceTags(self):
548
    self.rapi.AddResponse("1234")
549
    self.assertEqual(1234,
550
        self.client.AddInstanceTags("fooinstance", ["awesome"], dry_run=True))
551
    self.assertHandler(rlib2.R_2_instances_name_tags)
552
    self.assertItems(["fooinstance"])
553
    self.assertDryRun()
554
    self.assertQuery("tag", ["awesome"])
555

    
556
  def testDeleteInstanceTags(self):
557
    self.rapi.AddResponse("25826")
558
    self.assertEqual(25826, self.client.DeleteInstanceTags("foo", ["awesome"],
559
                                                           dry_run=True))
560
    self.assertHandler(rlib2.R_2_instances_name_tags)
561
    self.assertItems(["foo"])
562
    self.assertDryRun()
563
    self.assertQuery("tag", ["awesome"])
564

    
565
  def testRebootInstance(self):
566
    self.rapi.AddResponse("6146")
567
    job_id = self.client.RebootInstance("i-bar", reboot_type="hard",
568
                                        ignore_secondaries=True, dry_run=True)
569
    self.assertEqual(6146, job_id)
570
    self.assertHandler(rlib2.R_2_instances_name_reboot)
571
    self.assertItems(["i-bar"])
572
    self.assertDryRun()
573
    self.assertQuery("type", ["hard"])
574
    self.assertQuery("ignore_secondaries", ["1"])
575

    
576
  def testShutdownInstance(self):
577
    self.rapi.AddResponse("1487")
578
    self.assertEqual(1487, self.client.ShutdownInstance("foo-instance",
579
                                                        dry_run=True))
580
    self.assertHandler(rlib2.R_2_instances_name_shutdown)
581
    self.assertItems(["foo-instance"])
582
    self.assertDryRun()
583

    
584
  def testStartupInstance(self):
585
    self.rapi.AddResponse("27149")
586
    self.assertEqual(27149, self.client.StartupInstance("bar-instance",
587
                                                        dry_run=True))
588
    self.assertHandler(rlib2.R_2_instances_name_startup)
589
    self.assertItems(["bar-instance"])
590
    self.assertDryRun()
591

    
592
  def testReinstallInstance(self):
593
    self.rapi.AddResponse(serializer.DumpJson([]))
594
    self.rapi.AddResponse("19119")
595
    self.assertEqual(19119, self.client.ReinstallInstance("baz-instance",
596
                                                          os="DOS",
597
                                                          no_startup=True))
598
    self.assertHandler(rlib2.R_2_instances_name_reinstall)
599
    self.assertItems(["baz-instance"])
600
    self.assertQuery("os", ["DOS"])
601
    self.assertQuery("nostartup", ["1"])
602
    self.assertEqual(self.rapi.CountPending(), 0)
603

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

    
618
  def testReinstallInstanceWithOsparams1(self):
619
    self.rapi.AddResponse(serializer.DumpJson([]))
620
    self.assertRaises(client.GanetiApiError, self.client.ReinstallInstance,
621
                      "doo-instance", osparams={"x": "y"})
622
    self.assertEqual(self.rapi.CountPending(), 0)
623

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

    
641
  def testReplaceInstanceDisks(self):
642
    self.rapi.AddResponse("999")
643
    job_id = self.client.ReplaceInstanceDisks("instance-name",
644
        disks=[0, 1], iallocator="hail")
645
    self.assertEqual(999, job_id)
646
    self.assertHandler(rlib2.R_2_instances_name_replace_disks)
647
    self.assertItems(["instance-name"])
648
    self.assertQuery("disks", ["0,1"])
649
    self.assertQuery("mode", ["replace_auto"])
650
    self.assertQuery("iallocator", ["hail"])
651

    
652
    self.rapi.AddResponse("1000")
653
    job_id = self.client.ReplaceInstanceDisks("instance-bar",
654
        disks=[1], mode="replace_on_secondary", remote_node="foo-node")
655
    self.assertEqual(1000, job_id)
656
    self.assertItems(["instance-bar"])
657
    self.assertQuery("disks", ["1"])
658
    self.assertQuery("remote_node", ["foo-node"])
659

    
660
    self.rapi.AddResponse("5175")
661
    self.assertEqual(5175, self.client.ReplaceInstanceDisks("instance-moo"))
662
    self.assertItems(["instance-moo"])
663
    self.assertQuery("disks", None)
664

    
665
  def testPrepareExport(self):
666
    self.rapi.AddResponse("8326")
667
    self.assertEqual(8326, self.client.PrepareExport("inst1", "local"))
668
    self.assertHandler(rlib2.R_2_instances_name_prepare_export)
669
    self.assertItems(["inst1"])
670
    self.assertQuery("mode", ["local"])
671

    
672
  def testExportInstance(self):
673
    self.rapi.AddResponse("19695")
674
    job_id = self.client.ExportInstance("inst2", "local", "nodeX",
675
                                        shutdown=True)
676
    self.assertEqual(job_id, 19695)
677
    self.assertHandler(rlib2.R_2_instances_name_export)
678
    self.assertItems(["inst2"])
679

    
680
    data = serializer.LoadJson(self.rapi.GetLastRequestData())
681
    self.assertEqual(data["mode"], "local")
682
    self.assertEqual(data["destination"], "nodeX")
683
    self.assertEqual(data["shutdown"], True)
684

    
685
  def testMigrateInstanceDefaults(self):
686
    self.rapi.AddResponse("24873")
687
    job_id = self.client.MigrateInstance("inst91")
688
    self.assertEqual(job_id, 24873)
689
    self.assertHandler(rlib2.R_2_instances_name_migrate)
690
    self.assertItems(["inst91"])
691

    
692
    data = serializer.LoadJson(self.rapi.GetLastRequestData())
693
    self.assertFalse(data)
694

    
695
  def testMigrateInstance(self):
696
    for mode in constants.HT_MIGRATION_MODES:
697
      for cleanup in [False, True]:
698
        self.rapi.AddResponse("31910")
699
        job_id = self.client.MigrateInstance("inst289", mode=mode,
700
                                             cleanup=cleanup)
701
        self.assertEqual(job_id, 31910)
702
        self.assertHandler(rlib2.R_2_instances_name_migrate)
703
        self.assertItems(["inst289"])
704

    
705
        data = serializer.LoadJson(self.rapi.GetLastRequestData())
706
        self.assertEqual(len(data), 2)
707
        self.assertEqual(data["mode"], mode)
708
        self.assertEqual(data["cleanup"], cleanup)
709

    
710
  def testFailoverInstanceDefaults(self):
711
    self.rapi.AddResponse("7639")
712
    job_id = self.client.FailoverInstance("inst13579")
713
    self.assertEqual(job_id, 7639)
714
    self.assertHandler(rlib2.R_2_instances_name_failover)
715
    self.assertItems(["inst13579"])
716

    
717
    data = serializer.LoadJson(self.rapi.GetLastRequestData())
718
    self.assertFalse(data)
719

    
720
  def testFailoverInstance(self):
721
    for iallocator in ["dumb", "hail"]:
722
      for ignore_consistency in [False, True]:
723
        for target_node in ["node-a", "node2"]:
724
          self.rapi.AddResponse("19161")
725
          job_id = \
726
            self.client.FailoverInstance("inst251", iallocator=iallocator,
727
                                         ignore_consistency=ignore_consistency,
728
                                         target_node=target_node)
729
          self.assertEqual(job_id, 19161)
730
          self.assertHandler(rlib2.R_2_instances_name_failover)
731
          self.assertItems(["inst251"])
732

    
733
          data = serializer.LoadJson(self.rapi.GetLastRequestData())
734
          self.assertEqual(len(data), 3)
735
          self.assertEqual(data["iallocator"], iallocator)
736
          self.assertEqual(data["ignore_consistency"], ignore_consistency)
737
          self.assertEqual(data["target_node"], target_node)
738
          self.assertEqual(self.rapi.CountPending(), 0)
739

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

    
748
    data = serializer.LoadJson(self.rapi.GetLastRequestData())
749
    self.assertEqualValues(data, {"new_name": new_name, })
750

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

    
763
        data = serializer.LoadJson(self.rapi.GetLastRequestData())
764
        self.assertEqual(len(data), 3)
765
        self.assertEqual(data["new_name"], new_name)
766
        self.assertEqual(data["ip_check"], ip_check)
767
        self.assertEqual(data["name_check"], name_check)
768

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

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

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

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

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

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

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

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

    
822
  def testEvacuateNode(self):
823
    self.rapi.AddResponse(serializer.DumpJson([rlib2._NODE_EVAC_RES1]))
824
    self.rapi.AddResponse("9876")
825
    job_id = self.client.EvacuateNode("node-1", remote_node="node-2")
826
    self.assertEqual(9876, job_id)
827
    self.assertHandler(rlib2.R_2_nodes_name_evacuate)
828
    self.assertItems(["node-1"])
829
    self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
830
                     { "remote_node": "node-2", })
831
    self.assertEqual(self.rapi.CountPending(), 0)
832

    
833
    self.rapi.AddResponse(serializer.DumpJson([rlib2._NODE_EVAC_RES1]))
834
    self.rapi.AddResponse("8888")
835
    job_id = self.client.EvacuateNode("node-3", iallocator="hail", dry_run=True,
836
                                      mode=constants.NODE_EVAC_ALL,
837
                                      early_release=True)
838
    self.assertEqual(8888, job_id)
839
    self.assertItems(["node-3"])
840
    self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()), {
841
      "iallocator": "hail",
842
      "mode": "all",
843
      "early_release": True,
844
      })
845
    self.assertDryRun()
846

    
847
    self.assertRaises(client.GanetiApiError,
848
                      self.client.EvacuateNode,
849
                      "node-4", iallocator="hail", remote_node="node-5")
850
    self.assertEqual(self.rapi.CountPending(), 0)
851

    
852
  def testEvacuateNodeOldResponse(self):
853
    self.rapi.AddResponse(serializer.DumpJson([]))
854
    self.assertRaises(client.GanetiApiError, self.client.EvacuateNode,
855
                      "node-4", accept_old=False)
856
    self.assertEqual(self.rapi.CountPending(), 0)
857

    
858
    for mode in [client.NODE_EVAC_PRI, client.NODE_EVAC_ALL]:
859
      self.rapi.AddResponse(serializer.DumpJson([]))
860
      self.assertRaises(client.GanetiApiError, self.client.EvacuateNode,
861
                        "node-4", accept_old=True, mode=mode)
862
      self.assertEqual(self.rapi.CountPending(), 0)
863

    
864
    self.rapi.AddResponse(serializer.DumpJson([]))
865
    self.rapi.AddResponse(serializer.DumpJson("21533"))
866
    result = self.client.EvacuateNode("node-3", iallocator="hail",
867
                                      dry_run=True, accept_old=True,
868
                                      mode=client.NODE_EVAC_SEC,
869
                                      early_release=True)
870
    self.assertEqual(result, "21533")
871
    self.assertItems(["node-3"])
872
    self.assertQuery("iallocator", ["hail"])
873
    self.assertQuery("early_release", ["1"])
874
    self.assertFalse(self.rapi.GetLastRequestData())
875
    self.assertDryRun()
876
    self.assertEqual(self.rapi.CountPending(), 0)
877

    
878
  def testMigrateNode(self):
879
    self.rapi.AddResponse(serializer.DumpJson([]))
880
    self.rapi.AddResponse("1111")
881
    self.assertEqual(1111, self.client.MigrateNode("node-a", dry_run=True))
882
    self.assertHandler(rlib2.R_2_nodes_name_migrate)
883
    self.assertItems(["node-a"])
884
    self.assert_("mode" not in self.rapi.GetLastHandler().queryargs)
885
    self.assertDryRun()
886
    self.assertFalse(self.rapi.GetLastRequestData())
887

    
888
    self.rapi.AddResponse(serializer.DumpJson([]))
889
    self.rapi.AddResponse("1112")
890
    self.assertEqual(1112, self.client.MigrateNode("node-a", dry_run=True,
891
                                                   mode="live"))
892
    self.assertHandler(rlib2.R_2_nodes_name_migrate)
893
    self.assertItems(["node-a"])
894
    self.assertQuery("mode", ["live"])
895
    self.assertDryRun()
896
    self.assertFalse(self.rapi.GetLastRequestData())
897

    
898
    self.rapi.AddResponse(serializer.DumpJson([]))
899
    self.assertRaises(client.GanetiApiError, self.client.MigrateNode,
900
                      "node-c", target_node="foonode")
901
    self.assertEqual(self.rapi.CountPending(), 0)
902

    
903
  def testMigrateNodeBodyData(self):
904
    self.rapi.AddResponse(serializer.DumpJson([rlib2._NODE_MIGRATE_REQV1]))
905
    self.rapi.AddResponse("27539")
906
    self.assertEqual(27539, self.client.MigrateNode("node-a", dry_run=False,
907
                                                    mode="live"))
908
    self.assertHandler(rlib2.R_2_nodes_name_migrate)
909
    self.assertItems(["node-a"])
910
    self.assertFalse(self.rapi.GetLastHandler().queryargs)
911
    self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
912
                     { "mode": "live", })
913

    
914
    self.rapi.AddResponse(serializer.DumpJson([rlib2._NODE_MIGRATE_REQV1]))
915
    self.rapi.AddResponse("14219")
916
    self.assertEqual(14219, self.client.MigrateNode("node-x", dry_run=True,
917
                                                    target_node="node9",
918
                                                    iallocator="ial"))
919
    self.assertHandler(rlib2.R_2_nodes_name_migrate)
920
    self.assertItems(["node-x"])
921
    self.assertDryRun()
922
    self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
923
                     { "target_node": "node9", "iallocator": "ial", })
924

    
925
    self.assertEqual(self.rapi.CountPending(), 0)
926

    
927
  def testGetNodeRole(self):
928
    self.rapi.AddResponse("\"master\"")
929
    self.assertEqual("master", self.client.GetNodeRole("node-a"))
930
    self.assertHandler(rlib2.R_2_nodes_name_role)
931
    self.assertItems(["node-a"])
932

    
933
  def testSetNodeRole(self):
934
    self.rapi.AddResponse("789")
935
    self.assertEqual(789,
936
        self.client.SetNodeRole("node-foo", "master-candidate", force=True))
937
    self.assertHandler(rlib2.R_2_nodes_name_role)
938
    self.assertItems(["node-foo"])
939
    self.assertQuery("force", ["1"])
940
    self.assertEqual("\"master-candidate\"", self.rapi.GetLastRequestData())
941

    
942
  def testPowercycleNode(self):
943
    self.rapi.AddResponse("23051")
944
    self.assertEqual(23051,
945
        self.client.PowercycleNode("node5468", force=True))
946
    self.assertHandler(rlib2.R_2_nodes_name_powercycle)
947
    self.assertItems(["node5468"])
948
    self.assertQuery("force", ["1"])
949
    self.assertFalse(self.rapi.GetLastRequestData())
950
    self.assertEqual(self.rapi.CountPending(), 0)
951

    
952
  def testModifyNode(self):
953
    self.rapi.AddResponse("3783")
954
    job_id = self.client.ModifyNode("node16979.example.com", drained=True)
955
    self.assertEqual(job_id, 3783)
956
    self.assertHandler(rlib2.R_2_nodes_name_modify)
957
    self.assertItems(["node16979.example.com"])
958
    self.assertEqual(self.rapi.CountPending(), 0)
959

    
960
  def testGetNodeStorageUnits(self):
961
    self.rapi.AddResponse("42")
962
    self.assertEqual(42,
963
        self.client.GetNodeStorageUnits("node-x", "lvm-pv", "fields"))
964
    self.assertHandler(rlib2.R_2_nodes_name_storage)
965
    self.assertItems(["node-x"])
966
    self.assertQuery("storage_type", ["lvm-pv"])
967
    self.assertQuery("output_fields", ["fields"])
968

    
969
  def testModifyNodeStorageUnits(self):
970
    self.rapi.AddResponse("14")
971
    self.assertEqual(14,
972
        self.client.ModifyNodeStorageUnits("node-z", "lvm-pv", "hda"))
973
    self.assertHandler(rlib2.R_2_nodes_name_storage_modify)
974
    self.assertItems(["node-z"])
975
    self.assertQuery("storage_type", ["lvm-pv"])
976
    self.assertQuery("name", ["hda"])
977
    self.assertQuery("allocatable", None)
978

    
979
    for allocatable, query_allocatable in [(True, "1"), (False, "0")]:
980
      self.rapi.AddResponse("7205")
981
      job_id = self.client.ModifyNodeStorageUnits("node-z", "lvm-pv", "hda",
982
                                                  allocatable=allocatable)
983
      self.assertEqual(7205, job_id)
984
      self.assertHandler(rlib2.R_2_nodes_name_storage_modify)
985
      self.assertItems(["node-z"])
986
      self.assertQuery("storage_type", ["lvm-pv"])
987
      self.assertQuery("name", ["hda"])
988
      self.assertQuery("allocatable", [query_allocatable])
989

    
990
  def testRepairNodeStorageUnits(self):
991
    self.rapi.AddResponse("99")
992
    self.assertEqual(99, self.client.RepairNodeStorageUnits("node-z", "lvm-pv",
993
                                                            "hda"))
994
    self.assertHandler(rlib2.R_2_nodes_name_storage_repair)
995
    self.assertItems(["node-z"])
996
    self.assertQuery("storage_type", ["lvm-pv"])
997
    self.assertQuery("name", ["hda"])
998

    
999
  def testGetNodeTags(self):
1000
    self.rapi.AddResponse("[\"fry\", \"bender\"]")
1001
    self.assertEqual(["fry", "bender"], self.client.GetNodeTags("node-k"))
1002
    self.assertHandler(rlib2.R_2_nodes_name_tags)
1003
    self.assertItems(["node-k"])
1004

    
1005
  def testAddNodeTags(self):
1006
    self.rapi.AddResponse("1234")
1007
    self.assertEqual(1234,
1008
        self.client.AddNodeTags("node-v", ["awesome"], dry_run=True))
1009
    self.assertHandler(rlib2.R_2_nodes_name_tags)
1010
    self.assertItems(["node-v"])
1011
    self.assertDryRun()
1012
    self.assertQuery("tag", ["awesome"])
1013

    
1014
  def testDeleteNodeTags(self):
1015
    self.rapi.AddResponse("16861")
1016
    self.assertEqual(16861, self.client.DeleteNodeTags("node-w", ["awesome"],
1017
                                                       dry_run=True))
1018
    self.assertHandler(rlib2.R_2_nodes_name_tags)
1019
    self.assertItems(["node-w"])
1020
    self.assertDryRun()
1021
    self.assertQuery("tag", ["awesome"])
1022

    
1023
  def testGetGroups(self):
1024
    groups = [{"name": "group1",
1025
               "uri": "/2/groups/group1",
1026
               },
1027
              {"name": "group2",
1028
               "uri": "/2/groups/group2",
1029
               },
1030
              ]
1031
    self.rapi.AddResponse(serializer.DumpJson(groups))
1032
    self.assertEqual(["group1", "group2"], self.client.GetGroups())
1033
    self.assertHandler(rlib2.R_2_groups)
1034

    
1035
  def testGetGroupsBulk(self):
1036
    groups = [{"name": "group1",
1037
               "uri": "/2/groups/group1",
1038
               "node_cnt": 2,
1039
               "node_list": ["gnt1.test",
1040
                             "gnt2.test",
1041
                             ],
1042
               },
1043
              {"name": "group2",
1044
               "uri": "/2/groups/group2",
1045
               "node_cnt": 1,
1046
               "node_list": ["gnt3.test",
1047
                             ],
1048
               },
1049
              ]
1050
    self.rapi.AddResponse(serializer.DumpJson(groups))
1051

    
1052
    self.assertEqual(groups, self.client.GetGroups(bulk=True))
1053
    self.assertHandler(rlib2.R_2_groups)
1054
    self.assertBulk()
1055

    
1056
  def testGetGroup(self):
1057
    group = {"ctime": None,
1058
             "name": "default",
1059
             }
1060
    self.rapi.AddResponse(serializer.DumpJson(group))
1061
    self.assertEqual({"ctime": None, "name": "default"},
1062
                     self.client.GetGroup("default"))
1063
    self.assertHandler(rlib2.R_2_groups_name)
1064
    self.assertItems(["default"])
1065

    
1066
  def testCreateGroup(self):
1067
    self.rapi.AddResponse("12345")
1068
    job_id = self.client.CreateGroup("newgroup", dry_run=True)
1069
    self.assertEqual(job_id, 12345)
1070
    self.assertHandler(rlib2.R_2_groups)
1071
    self.assertDryRun()
1072

    
1073
  def testDeleteGroup(self):
1074
    self.rapi.AddResponse("12346")
1075
    job_id = self.client.DeleteGroup("newgroup", dry_run=True)
1076
    self.assertEqual(job_id, 12346)
1077
    self.assertHandler(rlib2.R_2_groups_name)
1078
    self.assertDryRun()
1079

    
1080
  def testRenameGroup(self):
1081
    self.rapi.AddResponse("12347")
1082
    job_id = self.client.RenameGroup("oldname", "newname")
1083
    self.assertEqual(job_id, 12347)
1084
    self.assertHandler(rlib2.R_2_groups_name_rename)
1085

    
1086
  def testModifyGroup(self):
1087
    self.rapi.AddResponse("12348")
1088
    job_id = self.client.ModifyGroup("mygroup", alloc_policy="foo")
1089
    self.assertEqual(job_id, 12348)
1090
    self.assertHandler(rlib2.R_2_groups_name_modify)
1091

    
1092
  def testAssignGroupNodes(self):
1093
    self.rapi.AddResponse("12349")
1094
    job_id = self.client.AssignGroupNodes("mygroup", ["node1", "node2"],
1095
                                          force=True, dry_run=True)
1096
    self.assertEqual(job_id, 12349)
1097
    self.assertHandler(rlib2.R_2_groups_name_assign_nodes)
1098
    self.assertDryRun()
1099
    self.assertUseForce()
1100

    
1101
  def testModifyInstance(self):
1102
    self.rapi.AddResponse("23681")
1103
    job_id = self.client.ModifyInstance("inst7210", os_name="linux")
1104
    self.assertEqual(job_id, 23681)
1105
    self.assertItems(["inst7210"])
1106
    self.assertHandler(rlib2.R_2_instances_name_modify)
1107
    self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
1108
                     { "os_name": "linux", })
1109

    
1110
  def testModifyCluster(self):
1111
    for mnh in [None, False, True]:
1112
      self.rapi.AddResponse("14470")
1113
      self.assertEqual(14470,
1114
        self.client.ModifyCluster(maintain_node_health=mnh))
1115
      self.assertHandler(rlib2.R_2_cluster_modify)
1116
      self.assertItems([])
1117
      data = serializer.LoadJson(self.rapi.GetLastRequestData())
1118
      self.assertEqual(len(data), 1)
1119
      self.assertEqual(data["maintain_node_health"], mnh)
1120
      self.assertEqual(self.rapi.CountPending(), 0)
1121

    
1122
  def testRedistributeConfig(self):
1123
    self.rapi.AddResponse("3364")
1124
    job_id = self.client.RedistributeConfig()
1125
    self.assertEqual(job_id, 3364)
1126
    self.assertItems([])
1127
    self.assertHandler(rlib2.R_2_redist_config)
1128

    
1129
  def testActivateInstanceDisks(self):
1130
    self.rapi.AddResponse("23547")
1131
    job_id = self.client.ActivateInstanceDisks("inst28204")
1132
    self.assertEqual(job_id, 23547)
1133
    self.assertItems(["inst28204"])
1134
    self.assertHandler(rlib2.R_2_instances_name_activate_disks)
1135
    self.assertFalse(self.rapi.GetLastHandler().queryargs)
1136

    
1137
  def testActivateInstanceDisksIgnoreSize(self):
1138
    self.rapi.AddResponse("11044")
1139
    job_id = self.client.ActivateInstanceDisks("inst28204", ignore_size=True)
1140
    self.assertEqual(job_id, 11044)
1141
    self.assertItems(["inst28204"])
1142
    self.assertHandler(rlib2.R_2_instances_name_activate_disks)
1143
    self.assertQuery("ignore_size", ["1"])
1144

    
1145
  def testDeactivateInstanceDisks(self):
1146
    self.rapi.AddResponse("14591")
1147
    job_id = self.client.DeactivateInstanceDisks("inst28234")
1148
    self.assertEqual(job_id, 14591)
1149
    self.assertItems(["inst28234"])
1150
    self.assertHandler(rlib2.R_2_instances_name_deactivate_disks)
1151
    self.assertFalse(self.rapi.GetLastHandler().queryargs)
1152

    
1153
  def testRecreateInstanceDisks(self):
1154
    self.rapi.AddResponse("13553")
1155
    job_id = self.client.RecreateInstanceDisks("inst23153")
1156
    self.assertEqual(job_id, 13553)
1157
    self.assertItems(["inst23153"])
1158
    self.assertHandler(rlib2.R_2_instances_name_recreate_disks)
1159
    self.assertFalse(self.rapi.GetLastHandler().queryargs)
1160

    
1161
  def testGetInstanceConsole(self):
1162
    self.rapi.AddResponse("26876")
1163
    job_id = self.client.GetInstanceConsole("inst21491")
1164
    self.assertEqual(job_id, 26876)
1165
    self.assertItems(["inst21491"])
1166
    self.assertHandler(rlib2.R_2_instances_name_console)
1167
    self.assertFalse(self.rapi.GetLastHandler().queryargs)
1168
    self.assertFalse(self.rapi.GetLastRequestData())
1169

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

    
1190
  def testGetGroupTags(self):
1191
    self.rapi.AddResponse("[]")
1192
    self.assertEqual([], self.client.GetGroupTags("fooGroup"))
1193
    self.assertHandler(rlib2.R_2_groups_name_tags)
1194
    self.assertItems(["fooGroup"])
1195

    
1196
  def testAddGroupTags(self):
1197
    self.rapi.AddResponse("1234")
1198
    self.assertEqual(1234,
1199
        self.client.AddGroupTags("fooGroup", ["awesome"], dry_run=True))
1200
    self.assertHandler(rlib2.R_2_groups_name_tags)
1201
    self.assertItems(["fooGroup"])
1202
    self.assertDryRun()
1203
    self.assertQuery("tag", ["awesome"])
1204

    
1205
  def testDeleteGroupTags(self):
1206
    self.rapi.AddResponse("25826")
1207
    self.assertEqual(25826, self.client.DeleteGroupTags("foo", ["awesome"],
1208
                                                        dry_run=True))
1209
    self.assertHandler(rlib2.R_2_groups_name_tags)
1210
    self.assertItems(["foo"])
1211
    self.assertDryRun()
1212
    self.assertQuery("tag", ["awesome"])
1213

    
1214
  def testQuery(self):
1215
    for idx, what in enumerate(constants.QR_VIA_RAPI):
1216
      for idx2, qfilter in enumerate([None, ["?", "name"]]):
1217
        job_id = 11010 + (idx << 4) + (idx2 << 16)
1218
        fields = sorted(query.ALL_FIELDS[what].keys())[:10]
1219

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

    
1234
  def testQueryFields(self):
1235
    exp_result = objects.QueryFieldsResponse(fields=[
1236
      objects.QueryFieldDefinition(name="pnode", title="PNode",
1237
                                   kind=constants.QFT_NUMBER),
1238
      objects.QueryFieldDefinition(name="other", title="Other",
1239
                                   kind=constants.QFT_BOOL),
1240
      ])
1241

    
1242
    for what in constants.QR_VIA_RAPI:
1243
      for fields in [None, ["name", "_unknown_"], ["&", "?|"]]:
1244
        self.rapi.AddResponse(serializer.DumpJson(exp_result.ToDict()))
1245
        result = self.client.QueryFields(what, fields=fields)
1246
        self.assertItems([what])
1247
        self.assertHandler(rlib2.R_2_query_fields)
1248
        self.assertFalse(self.rapi.GetLastRequestData())
1249

    
1250
        queryargs = self.rapi.GetLastHandler().queryargs
1251
        if fields is None:
1252
          self.assertFalse(queryargs)
1253
        else:
1254
          self.assertEqual(queryargs, {
1255
            "fields": [",".join(fields)],
1256
            })
1257

    
1258
        self.assertEqual(objects.QueryFieldsResponse.FromDict(result).ToDict(),
1259
                         exp_result.ToDict())
1260

    
1261
        self.assertEqual(self.rapi.CountPending(), 0)
1262

    
1263
  def testWaitForJobCompletionNoChange(self):
1264
    resp = serializer.DumpJson({
1265
      "status": constants.JOB_STATUS_WAITING,
1266
      })
1267

    
1268
    for retries in [1, 5, 25]:
1269
      for _ in range(retries):
1270
        self.rapi.AddResponse(resp)
1271

    
1272
      self.assertFalse(self.client.WaitForJobCompletion(22789, period=None,
1273
                                                        retries=retries))
1274
      self.assertHandler(rlib2.R_2_jobs_id)
1275
      self.assertItems(["22789"])
1276

    
1277
      self.assertEqual(self.rapi.CountPending(), 0)
1278

    
1279
  def testWaitForJobCompletionAlreadyFinished(self):
1280
    self.rapi.AddResponse(serializer.DumpJson({
1281
      "status": constants.JOB_STATUS_SUCCESS,
1282
      }))
1283

    
1284
    self.assertTrue(self.client.WaitForJobCompletion(22793, period=None,
1285
                                                     retries=1))
1286
    self.assertHandler(rlib2.R_2_jobs_id)
1287
    self.assertItems(["22793"])
1288

    
1289
    self.assertEqual(self.rapi.CountPending(), 0)
1290

    
1291
  def testWaitForJobCompletionEmptyResponse(self):
1292
    self.rapi.AddResponse("{}")
1293
    self.assertFalse(self.client.WaitForJobCompletion(22793, period=None,
1294
                                                     retries=10))
1295
    self.assertHandler(rlib2.R_2_jobs_id)
1296
    self.assertItems(["22793"])
1297

    
1298
    self.assertEqual(self.rapi.CountPending(), 0)
1299

    
1300
  def testWaitForJobCompletionOutOfRetries(self):
1301
    for retries in [3, 10, 21]:
1302
      for _ in range(retries):
1303
        self.rapi.AddResponse(serializer.DumpJson({
1304
          "status": constants.JOB_STATUS_RUNNING,
1305
          }))
1306

    
1307
      self.assertFalse(self.client.WaitForJobCompletion(30948, period=None,
1308
                                                        retries=retries - 1))
1309
      self.assertHandler(rlib2.R_2_jobs_id)
1310
      self.assertItems(["30948"])
1311

    
1312
      self.assertEqual(self.rapi.CountPending(), 1)
1313
      self.rapi.ResetResponses()
1314

    
1315
  def testWaitForJobCompletionSuccessAndFailure(self):
1316
    for retries in [1, 4, 13]:
1317
      for (success, end_status) in [(False, constants.JOB_STATUS_ERROR),
1318
                                    (True, constants.JOB_STATUS_SUCCESS)]:
1319
        for _ in range(retries):
1320
          self.rapi.AddResponse(serializer.DumpJson({
1321
            "status": constants.JOB_STATUS_RUNNING,
1322
            }))
1323

    
1324
        self.rapi.AddResponse(serializer.DumpJson({
1325
          "status": end_status,
1326
          }))
1327

    
1328
        result = self.client.WaitForJobCompletion(3187, period=None,
1329
                                                  retries=retries + 1)
1330
        self.assertEqual(result, success)
1331
        self.assertHandler(rlib2.R_2_jobs_id)
1332
        self.assertItems(["3187"])
1333

    
1334
        self.assertEqual(self.rapi.CountPending(), 0)
1335

    
1336

    
1337
class RapiTestRunner(unittest.TextTestRunner):
1338
  def run(self, *args):
1339
    global _used_handlers
1340
    assert _used_handlers is None
1341

    
1342
    _used_handlers = set()
1343
    try:
1344
      # Run actual tests
1345
      result = unittest.TextTestRunner.run(self, *args)
1346

    
1347
      diff = (set(connector.CONNECTOR.values()) - _used_handlers -
1348
             _KNOWN_UNUSED)
1349
      if diff:
1350
        raise AssertionError("The following RAPI resources were not used by the"
1351
                             " RAPI client: %r" % utils.CommaJoin(diff))
1352
    finally:
1353
      # Reset global variable
1354
      _used_handlers = None
1355

    
1356
    return result
1357

    
1358

    
1359
if __name__ == '__main__':
1360
  client.UsesRapiClient(testutils.GanetiTestProgram)(testRunner=RapiTestRunner)