Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (49.4 kB)

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

    
4
# Copyright (C) 2010 Google Inc.
5
#
6
# This program is free software; you can redistribute it and/or modify
7
# it under the terms of the GNU General Public License as published by
8
# the Free Software Foundation; either version 2 of the License, or
9
# (at your option) any later version.
10
#
11
# This program is distributed in the hope that it will be useful, but
12
# WITHOUT ANY WARRANTY; without even the implied warranty of
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
# General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License
17
# along with this program; if not, write to the Free Software
18
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19
# 02110-1301, USA.
20

    
21

    
22
"""Script for unittesting the RAPI client module"""
23

    
24

    
25
import re
26
import unittest
27
import warnings
28
import pycurl
29

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

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

    
41
import testutils
42

    
43

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

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

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

    
55

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

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

    
66

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

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

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

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

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

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

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

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

    
98

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

    
106
  def ResetResponses(self):
107
    del self._responses[:]
108

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

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

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

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

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

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

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

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

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

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

    
143
    return code, response
144

    
145

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

    
168

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

    
182

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

    
187

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

    
192

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

    
197

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

    
202

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

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

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

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

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

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

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

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

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

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

    
261
    curl_factory = lambda: 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.assertFalse(curl.getopt(pycurl.SSL_VERIFYPEER))
267
    self.assertFalse(curl.getopt(pycurl.CAINFO))
268
    self.assertFalse(curl.getopt(pycurl.CAPATH))
269

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
360

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
851
    self.rapi.AddResponse(serializer.DumpJson([]))
852
    self.assertRaises(client.GanetiApiError, self.client.EvacuateNode,
853
                      "node-4", accept_old=True)
854
    self.assertEqual(self.rapi.CountPending(), 0)
855

    
856
    self.rapi.AddResponse(serializer.DumpJson([]))
857
    self.assertRaises(client.GanetiApiError, self.client.EvacuateNode,
858
                      "node-4", accept_old=True, primary=True)
859
    self.assertEqual(self.rapi.CountPending(), 0)
860

    
861
    self.rapi.AddResponse(serializer.DumpJson([]))
862
    self.assertRaises(client.GanetiApiError, self.client.EvacuateNode,
863
                      "node-4", accept_old=True, secondary=False)
864
    self.assertEqual(self.rapi.CountPending(), 0)
865

    
866
    for sec in [True, None]:
867
      self.rapi.AddResponse(serializer.DumpJson([]))
868
      self.rapi.AddResponse(serializer.DumpJson([["res", "foo"]]))
869
      result = self.client.EvacuateNode("node-3", iallocator="hail",
870
                                        dry_run=True, accept_old=True,
871
                                        primary=False, secondary=sec)
872
      self.assertEqual(result, [["res", "foo"]])
873
      self.assertItems(["node-3"])
874
      self.assertQuery("iallocator", ["hail"])
875
      self.assertFalse(self.rapi.GetLastRequestData())
876
      self.assertDryRun()
877
      self.assertEqual(self.rapi.CountPending(), 0)
878

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

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

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

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

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

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

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

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

    
943
  def testGetNodeStorageUnits(self):
944
    self.rapi.AddResponse("42")
945
    self.assertEqual(42,
946
        self.client.GetNodeStorageUnits("node-x", "lvm-pv", "fields"))
947
    self.assertHandler(rlib2.R_2_nodes_name_storage)
948
    self.assertItems(["node-x"])
949
    self.assertQuery("storage_type", ["lvm-pv"])
950
    self.assertQuery("output_fields", ["fields"])
951

    
952
  def testModifyNodeStorageUnits(self):
953
    self.rapi.AddResponse("14")
954
    self.assertEqual(14,
955
        self.client.ModifyNodeStorageUnits("node-z", "lvm-pv", "hda"))
956
    self.assertHandler(rlib2.R_2_nodes_name_storage_modify)
957
    self.assertItems(["node-z"])
958
    self.assertQuery("storage_type", ["lvm-pv"])
959
    self.assertQuery("name", ["hda"])
960
    self.assertQuery("allocatable", None)
961

    
962
    for allocatable, query_allocatable in [(True, "1"), (False, "0")]:
963
      self.rapi.AddResponse("7205")
964
      job_id = self.client.ModifyNodeStorageUnits("node-z", "lvm-pv", "hda",
965
                                                  allocatable=allocatable)
966
      self.assertEqual(7205, job_id)
967
      self.assertHandler(rlib2.R_2_nodes_name_storage_modify)
968
      self.assertItems(["node-z"])
969
      self.assertQuery("storage_type", ["lvm-pv"])
970
      self.assertQuery("name", ["hda"])
971
      self.assertQuery("allocatable", [query_allocatable])
972

    
973
  def testRepairNodeStorageUnits(self):
974
    self.rapi.AddResponse("99")
975
    self.assertEqual(99, self.client.RepairNodeStorageUnits("node-z", "lvm-pv",
976
                                                            "hda"))
977
    self.assertHandler(rlib2.R_2_nodes_name_storage_repair)
978
    self.assertItems(["node-z"])
979
    self.assertQuery("storage_type", ["lvm-pv"])
980
    self.assertQuery("name", ["hda"])
981

    
982
  def testGetNodeTags(self):
983
    self.rapi.AddResponse("[\"fry\", \"bender\"]")
984
    self.assertEqual(["fry", "bender"], self.client.GetNodeTags("node-k"))
985
    self.assertHandler(rlib2.R_2_nodes_name_tags)
986
    self.assertItems(["node-k"])
987

    
988
  def testAddNodeTags(self):
989
    self.rapi.AddResponse("1234")
990
    self.assertEqual(1234,
991
        self.client.AddNodeTags("node-v", ["awesome"], dry_run=True))
992
    self.assertHandler(rlib2.R_2_nodes_name_tags)
993
    self.assertItems(["node-v"])
994
    self.assertDryRun()
995
    self.assertQuery("tag", ["awesome"])
996

    
997
  def testDeleteNodeTags(self):
998
    self.rapi.AddResponse("16861")
999
    self.assertEqual(16861, self.client.DeleteNodeTags("node-w", ["awesome"],
1000
                                                       dry_run=True))
1001
    self.assertHandler(rlib2.R_2_nodes_name_tags)
1002
    self.assertItems(["node-w"])
1003
    self.assertDryRun()
1004
    self.assertQuery("tag", ["awesome"])
1005

    
1006
  def testGetGroups(self):
1007
    groups = [{"name": "group1",
1008
               "uri": "/2/groups/group1",
1009
               },
1010
              {"name": "group2",
1011
               "uri": "/2/groups/group2",
1012
               },
1013
              ]
1014
    self.rapi.AddResponse(serializer.DumpJson(groups))
1015
    self.assertEqual(["group1", "group2"], self.client.GetGroups())
1016
    self.assertHandler(rlib2.R_2_groups)
1017

    
1018
  def testGetGroupsBulk(self):
1019
    groups = [{"name": "group1",
1020
               "uri": "/2/groups/group1",
1021
               "node_cnt": 2,
1022
               "node_list": ["gnt1.test",
1023
                             "gnt2.test",
1024
                             ],
1025
               },
1026
              {"name": "group2",
1027
               "uri": "/2/groups/group2",
1028
               "node_cnt": 1,
1029
               "node_list": ["gnt3.test",
1030
                             ],
1031
               },
1032
              ]
1033
    self.rapi.AddResponse(serializer.DumpJson(groups))
1034

    
1035
    self.assertEqual(groups, self.client.GetGroups(bulk=True))
1036
    self.assertHandler(rlib2.R_2_groups)
1037
    self.assertBulk()
1038

    
1039
  def testGetGroup(self):
1040
    group = {"ctime": None,
1041
             "name": "default",
1042
             }
1043
    self.rapi.AddResponse(serializer.DumpJson(group))
1044
    self.assertEqual({"ctime": None, "name": "default"},
1045
                     self.client.GetGroup("default"))
1046
    self.assertHandler(rlib2.R_2_groups_name)
1047
    self.assertItems(["default"])
1048

    
1049
  def testCreateGroup(self):
1050
    self.rapi.AddResponse("12345")
1051
    job_id = self.client.CreateGroup("newgroup", dry_run=True)
1052
    self.assertEqual(job_id, 12345)
1053
    self.assertHandler(rlib2.R_2_groups)
1054
    self.assertDryRun()
1055

    
1056
  def testDeleteGroup(self):
1057
    self.rapi.AddResponse("12346")
1058
    job_id = self.client.DeleteGroup("newgroup", dry_run=True)
1059
    self.assertEqual(job_id, 12346)
1060
    self.assertHandler(rlib2.R_2_groups_name)
1061
    self.assertDryRun()
1062

    
1063
  def testRenameGroup(self):
1064
    self.rapi.AddResponse("12347")
1065
    job_id = self.client.RenameGroup("oldname", "newname")
1066
    self.assertEqual(job_id, 12347)
1067
    self.assertHandler(rlib2.R_2_groups_name_rename)
1068

    
1069
  def testModifyGroup(self):
1070
    self.rapi.AddResponse("12348")
1071
    job_id = self.client.ModifyGroup("mygroup", alloc_policy="foo")
1072
    self.assertEqual(job_id, 12348)
1073
    self.assertHandler(rlib2.R_2_groups_name_modify)
1074

    
1075
  def testAssignGroupNodes(self):
1076
    self.rapi.AddResponse("12349")
1077
    job_id = self.client.AssignGroupNodes("mygroup", ["node1", "node2"],
1078
                                          force=True, dry_run=True)
1079
    self.assertEqual(job_id, 12349)
1080
    self.assertHandler(rlib2.R_2_groups_name_assign_nodes)
1081
    self.assertDryRun()
1082
    self.assertUseForce()
1083

    
1084
  def testModifyInstance(self):
1085
    self.rapi.AddResponse("23681")
1086
    job_id = self.client.ModifyInstance("inst7210", os_name="linux")
1087
    self.assertEqual(job_id, 23681)
1088
    self.assertItems(["inst7210"])
1089
    self.assertHandler(rlib2.R_2_instances_name_modify)
1090
    self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
1091
                     { "os_name": "linux", })
1092

    
1093
  def testModifyCluster(self):
1094
    for mnh in [None, False, True]:
1095
      self.rapi.AddResponse("14470")
1096
      self.assertEqual(14470,
1097
        self.client.ModifyCluster(maintain_node_health=mnh))
1098
      self.assertHandler(rlib2.R_2_cluster_modify)
1099
      self.assertItems([])
1100
      data = serializer.LoadJson(self.rapi.GetLastRequestData())
1101
      self.assertEqual(len(data), 1)
1102
      self.assertEqual(data["maintain_node_health"], mnh)
1103
      self.assertEqual(self.rapi.CountPending(), 0)
1104

    
1105
  def testRedistributeConfig(self):
1106
    self.rapi.AddResponse("3364")
1107
    job_id = self.client.RedistributeConfig()
1108
    self.assertEqual(job_id, 3364)
1109
    self.assertItems([])
1110
    self.assertHandler(rlib2.R_2_redist_config)
1111

    
1112
  def testActivateInstanceDisks(self):
1113
    self.rapi.AddResponse("23547")
1114
    job_id = self.client.ActivateInstanceDisks("inst28204")
1115
    self.assertEqual(job_id, 23547)
1116
    self.assertItems(["inst28204"])
1117
    self.assertHandler(rlib2.R_2_instances_name_activate_disks)
1118
    self.assertFalse(self.rapi.GetLastHandler().queryargs)
1119

    
1120
  def testActivateInstanceDisksIgnoreSize(self):
1121
    self.rapi.AddResponse("11044")
1122
    job_id = self.client.ActivateInstanceDisks("inst28204", ignore_size=True)
1123
    self.assertEqual(job_id, 11044)
1124
    self.assertItems(["inst28204"])
1125
    self.assertHandler(rlib2.R_2_instances_name_activate_disks)
1126
    self.assertQuery("ignore_size", ["1"])
1127

    
1128
  def testDeactivateInstanceDisks(self):
1129
    self.rapi.AddResponse("14591")
1130
    job_id = self.client.DeactivateInstanceDisks("inst28234")
1131
    self.assertEqual(job_id, 14591)
1132
    self.assertItems(["inst28234"])
1133
    self.assertHandler(rlib2.R_2_instances_name_deactivate_disks)
1134
    self.assertFalse(self.rapi.GetLastHandler().queryargs)
1135

    
1136
  def testGetInstanceConsole(self):
1137
    self.rapi.AddResponse("26876")
1138
    job_id = self.client.GetInstanceConsole("inst21491")
1139
    self.assertEqual(job_id, 26876)
1140
    self.assertItems(["inst21491"])
1141
    self.assertHandler(rlib2.R_2_instances_name_console)
1142
    self.assertFalse(self.rapi.GetLastHandler().queryargs)
1143
    self.assertFalse(self.rapi.GetLastRequestData())
1144

    
1145
  def testGrowInstanceDisk(self):
1146
    for idx, wait_for_sync in enumerate([None, False, True]):
1147
      amount = 128 + (512 * idx)
1148
      self.assertEqual(self.rapi.CountPending(), 0)
1149
      self.rapi.AddResponse("30783")
1150
      self.assertEqual(30783,
1151
        self.client.GrowInstanceDisk("eze8ch", idx, amount,
1152
                                     wait_for_sync=wait_for_sync))
1153
      self.assertHandler(rlib2.R_2_instances_name_disk_grow)
1154
      self.assertItems(["eze8ch", str(idx)])
1155
      data = serializer.LoadJson(self.rapi.GetLastRequestData())
1156
      if wait_for_sync is None:
1157
        self.assertEqual(len(data), 1)
1158
        self.assert_("wait_for_sync" not in data)
1159
      else:
1160
        self.assertEqual(len(data), 2)
1161
        self.assertEqual(data["wait_for_sync"], wait_for_sync)
1162
      self.assertEqual(data["amount"], amount)
1163
      self.assertEqual(self.rapi.CountPending(), 0)
1164

    
1165
  def testGetGroupTags(self):
1166
    self.rapi.AddResponse("[]")
1167
    self.assertEqual([], self.client.GetGroupTags("fooGroup"))
1168
    self.assertHandler(rlib2.R_2_groups_name_tags)
1169
    self.assertItems(["fooGroup"])
1170

    
1171
  def testAddGroupTags(self):
1172
    self.rapi.AddResponse("1234")
1173
    self.assertEqual(1234,
1174
        self.client.AddGroupTags("fooGroup", ["awesome"], dry_run=True))
1175
    self.assertHandler(rlib2.R_2_groups_name_tags)
1176
    self.assertItems(["fooGroup"])
1177
    self.assertDryRun()
1178
    self.assertQuery("tag", ["awesome"])
1179

    
1180
  def testDeleteGroupTags(self):
1181
    self.rapi.AddResponse("25826")
1182
    self.assertEqual(25826, self.client.DeleteGroupTags("foo", ["awesome"],
1183
                                                        dry_run=True))
1184
    self.assertHandler(rlib2.R_2_groups_name_tags)
1185
    self.assertItems(["foo"])
1186
    self.assertDryRun()
1187
    self.assertQuery("tag", ["awesome"])
1188

    
1189
  def testQuery(self):
1190
    for idx, what in enumerate(constants.QR_VIA_RAPI):
1191
      for idx2, filter_ in enumerate([None, ["?", "name"]]):
1192
        job_id = 11010 + (idx << 4) + (idx2 << 16)
1193
        fields = sorted(query.ALL_FIELDS[what].keys())[:10]
1194

    
1195
        self.rapi.AddResponse(str(job_id))
1196
        self.assertEqual(self.client.Query(what, fields, filter_=filter_),
1197
                         job_id)
1198
        self.assertItems([what])
1199
        self.assertHandler(rlib2.R_2_query)
1200
        self.assertFalse(self.rapi.GetLastHandler().queryargs)
1201
        data = serializer.LoadJson(self.rapi.GetLastRequestData())
1202
        self.assertEqual(data["fields"], fields)
1203
        if filter_ is None:
1204
          self.assertTrue("filter" not in data)
1205
        else:
1206
          self.assertEqual(data["filter"], filter_)
1207
        self.assertEqual(self.rapi.CountPending(), 0)
1208

    
1209
  def testQueryFields(self):
1210
    exp_result = objects.QueryFieldsResponse(fields=[
1211
      objects.QueryFieldDefinition(name="pnode", title="PNode",
1212
                                   kind=constants.QFT_NUMBER),
1213
      objects.QueryFieldDefinition(name="other", title="Other",
1214
                                   kind=constants.QFT_BOOL),
1215
      ])
1216

    
1217
    for what in constants.QR_VIA_RAPI:
1218
      for fields in [None, ["name", "_unknown_"], ["&", "?|"]]:
1219
        self.rapi.AddResponse(serializer.DumpJson(exp_result.ToDict()))
1220
        result = self.client.QueryFields(what, fields=fields)
1221
        self.assertItems([what])
1222
        self.assertHandler(rlib2.R_2_query_fields)
1223
        self.assertFalse(self.rapi.GetLastRequestData())
1224

    
1225
        queryargs = self.rapi.GetLastHandler().queryargs
1226
        if fields is None:
1227
          self.assertFalse(queryargs)
1228
        else:
1229
          self.assertEqual(queryargs, {
1230
            "fields": [",".join(fields)],
1231
            })
1232

    
1233
        self.assertEqual(objects.QueryFieldsResponse.FromDict(result).ToDict(),
1234
                         exp_result.ToDict())
1235

    
1236
        self.assertEqual(self.rapi.CountPending(), 0)
1237

    
1238
  def testWaitForJobCompletionNoChange(self):
1239
    resp = serializer.DumpJson({
1240
      "status": constants.JOB_STATUS_WAITLOCK,
1241
      })
1242

    
1243
    for retries in [1, 5, 25]:
1244
      for _ in range(retries):
1245
        self.rapi.AddResponse(resp)
1246

    
1247
      self.assertFalse(self.client.WaitForJobCompletion(22789, period=None,
1248
                                                        retries=retries))
1249
      self.assertHandler(rlib2.R_2_jobs_id)
1250
      self.assertItems(["22789"])
1251

    
1252
      self.assertEqual(self.rapi.CountPending(), 0)
1253

    
1254
  def testWaitForJobCompletionAlreadyFinished(self):
1255
    self.rapi.AddResponse(serializer.DumpJson({
1256
      "status": constants.JOB_STATUS_SUCCESS,
1257
      }))
1258

    
1259
    self.assertTrue(self.client.WaitForJobCompletion(22793, period=None,
1260
                                                     retries=1))
1261
    self.assertHandler(rlib2.R_2_jobs_id)
1262
    self.assertItems(["22793"])
1263

    
1264
    self.assertEqual(self.rapi.CountPending(), 0)
1265

    
1266
  def testWaitForJobCompletionEmptyResponse(self):
1267
    self.rapi.AddResponse("{}")
1268
    self.assertFalse(self.client.WaitForJobCompletion(22793, period=None,
1269
                                                     retries=10))
1270
    self.assertHandler(rlib2.R_2_jobs_id)
1271
    self.assertItems(["22793"])
1272

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

    
1275
  def testWaitForJobCompletionOutOfRetries(self):
1276
    for retries in [3, 10, 21]:
1277
      for _ in range(retries):
1278
        self.rapi.AddResponse(serializer.DumpJson({
1279
          "status": constants.JOB_STATUS_RUNNING,
1280
          }))
1281

    
1282
      self.assertFalse(self.client.WaitForJobCompletion(30948, period=None,
1283
                                                        retries=retries - 1))
1284
      self.assertHandler(rlib2.R_2_jobs_id)
1285
      self.assertItems(["30948"])
1286

    
1287
      self.assertEqual(self.rapi.CountPending(), 1)
1288
      self.rapi.ResetResponses()
1289

    
1290
  def testWaitForJobCompletionSuccessAndFailure(self):
1291
    for retries in [1, 4, 13]:
1292
      for (success, end_status) in [(False, constants.JOB_STATUS_ERROR),
1293
                                    (True, constants.JOB_STATUS_SUCCESS)]:
1294
        for _ in range(retries):
1295
          self.rapi.AddResponse(serializer.DumpJson({
1296
            "status": constants.JOB_STATUS_RUNNING,
1297
            }))
1298

    
1299
        self.rapi.AddResponse(serializer.DumpJson({
1300
          "status": end_status,
1301
          }))
1302

    
1303
        result = self.client.WaitForJobCompletion(3187, period=None,
1304
                                                  retries=retries + 1)
1305
        self.assertEqual(result, success)
1306
        self.assertHandler(rlib2.R_2_jobs_id)
1307
        self.assertItems(["3187"])
1308

    
1309
        self.assertEqual(self.rapi.CountPending(), 0)
1310

    
1311

    
1312
class RapiTestRunner(unittest.TextTestRunner):
1313
  def run(self, *args):
1314
    global _used_handlers
1315
    assert _used_handlers is None
1316

    
1317
    _used_handlers = set()
1318
    try:
1319
      # Run actual tests
1320
      result = unittest.TextTestRunner.run(self, *args)
1321

    
1322
      diff = (set(connector.CONNECTOR.values()) - _used_handlers -
1323
             _KNOWN_UNUSED)
1324
      if diff:
1325
        raise AssertionError("The following RAPI resources were not used by the"
1326
                             " RAPI client: %r" % utils.CommaJoin(diff))
1327
    finally:
1328
      # Reset global variable
1329
      _used_handlers = None
1330

    
1331
    return result
1332

    
1333

    
1334
if __name__ == '__main__':
1335
  client.UsesRapiClient(testutils.GanetiTestProgram)(testRunner=RapiTestRunner)