Statistics
| Branch: | Tag: | Revision:

root / test / ganeti.rapi.client_unittest.py @ 4ee72287

History | View | Annotate | Download (51.3 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
  rlib2.R_2_instances_multi_alloc,
50
  ])
51

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

    
55

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

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

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

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

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

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

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

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

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

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

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

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

    
100
    return code, response
101

    
102

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

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

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

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

    
138

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

    
152

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

    
157

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

    
162

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

    
167

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

    
172

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
330

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1331

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

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

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

    
1351
    return result
1352

    
1353

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