Statistics
| Branch: | Tag: | Revision:

root / test / ganeti.rapi.client_unittest.py @ 1eaddbc6

History | View | Annotate | Download (52 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 opcodes
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
from ganeti import rapi
37

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

    
43
import testutils
44

    
45

    
46
# List of resource handlers which aren't used by the RAPI client
47
_KNOWN_UNUSED = set([
48
  rlib2.R_root,
49
  rlib2.R_2,
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_PENDING, constants.JOBS_PENDING)
118
    self.assertEqual(client.JOB_STATUS_FINALIZED, constants.JOBS_FINALIZED)
119
    self.assertEqual(client.JOB_STATUS_ALL, constants.JOB_STATUS_ALL)
120

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

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

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

    
139

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

    
153

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

    
158

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

    
163

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

    
168

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

    
173

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
331

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
485
  def testInstancesMultiAlloc(self):
486
    response = {
487
      constants.JOB_IDS_KEY: ["23423"],
488
      opcodes.OpInstanceMultiAlloc.ALLOCATABLE_KEY: ["foobar"],
489
      opcodes.OpInstanceMultiAlloc.FAILED_KEY: ["foobar2"],
490
      }
491
    self.rapi.AddResponse(serializer.DumpJson(response))
492
    insts = [self.client.InstanceAllocation("create", "foobar",
493
                                            "plain", [], []),
494
             self.client.InstanceAllocation("create", "foobar2",
495
                                            "drbd8", [{"size": 100}], [])]
496
    resp = self.client.InstancesMultiAlloc(insts)
497
    self.assertEqual(resp, response)
498
    self.assertHandler(rlib2.R_2_instances_multi_alloc)
499

    
500
  def testCreateInstanceOldVersion(self):
501
    # The old request format, version 0, is no longer supported
502
    self.rapi.AddResponse(None, code=404)
503
    self.assertRaises(client.GanetiApiError, self.client.CreateInstance,
504
                      "create", "inst1.example.com", "plain", [], [])
505
    self.assertEqual(self.rapi.CountPending(), 0)
506

    
507
  def testCreateInstance(self):
508
    self.rapi.AddResponse(serializer.DumpJson([rlib2._INST_CREATE_REQV1]))
509
    self.rapi.AddResponse("23030")
510
    job_id = self.client.CreateInstance("create", "inst1.example.com",
511
                                        "plain", [], [], dry_run=True)
512
    self.assertEqual(job_id, 23030)
513
    self.assertHandler(rlib2.R_2_instances)
514
    self.assertDryRun()
515

    
516
    data = serializer.LoadJson(self.rapi.GetLastRequestData())
517

    
518
    for field in ["dry_run", "beparams", "hvparams", "start"]:
519
      self.assertFalse(field in data)
520

    
521
    self.assertEqual(data["name"], "inst1.example.com")
522
    self.assertEqual(data["disk_template"], "plain")
523

    
524
  def testCreateInstance2(self):
525
    self.rapi.AddResponse(serializer.DumpJson([rlib2._INST_CREATE_REQV1]))
526
    self.rapi.AddResponse("24740")
527
    job_id = self.client.CreateInstance("import", "inst2.example.com",
528
                                        "drbd8", [{"size": 100,}],
529
                                        [{}, {"bridge": "br1", }],
530
                                        dry_run=False, start=True,
531
                                        pnode="node1", snode="node9",
532
                                        ip_check=False)
533
    self.assertEqual(job_id, 24740)
534
    self.assertHandler(rlib2.R_2_instances)
535

    
536
    data = serializer.LoadJson(self.rapi.GetLastRequestData())
537
    self.assertEqual(data[rlib2._REQ_DATA_VERSION], 1)
538
    self.assertEqual(data["name"], "inst2.example.com")
539
    self.assertEqual(data["disk_template"], "drbd8")
540
    self.assertEqual(data["start"], True)
541
    self.assertEqual(data["ip_check"], False)
542
    self.assertEqualValues(data["disks"], [{"size": 100,}])
543
    self.assertEqualValues(data["nics"], [{}, {"bridge": "br1", }])
544

    
545
  def testDeleteInstance(self):
546
    self.rapi.AddResponse("1234")
547
    self.assertEqual(1234, self.client.DeleteInstance("instance", dry_run=True))
548
    self.assertHandler(rlib2.R_2_instances_name)
549
    self.assertItems(["instance"])
550
    self.assertDryRun()
551

    
552
  def testGetInstanceTags(self):
553
    self.rapi.AddResponse("[]")
554
    self.assertEqual([], self.client.GetInstanceTags("fooinstance"))
555
    self.assertHandler(rlib2.R_2_instances_name_tags)
556
    self.assertItems(["fooinstance"])
557

    
558
  def testAddInstanceTags(self):
559
    self.rapi.AddResponse("1234")
560
    self.assertEqual(1234,
561
        self.client.AddInstanceTags("fooinstance", ["awesome"], dry_run=True))
562
    self.assertHandler(rlib2.R_2_instances_name_tags)
563
    self.assertItems(["fooinstance"])
564
    self.assertDryRun()
565
    self.assertQuery("tag", ["awesome"])
566

    
567
  def testDeleteInstanceTags(self):
568
    self.rapi.AddResponse("25826")
569
    self.assertEqual(25826, self.client.DeleteInstanceTags("foo", ["awesome"],
570
                                                           dry_run=True))
571
    self.assertHandler(rlib2.R_2_instances_name_tags)
572
    self.assertItems(["foo"])
573
    self.assertDryRun()
574
    self.assertQuery("tag", ["awesome"])
575

    
576
  def testRebootInstance(self):
577
    self.rapi.AddResponse("6146")
578
    job_id = self.client.RebootInstance("i-bar", reboot_type="hard",
579
                                        ignore_secondaries=True, dry_run=True)
580
    self.assertEqual(6146, job_id)
581
    self.assertHandler(rlib2.R_2_instances_name_reboot)
582
    self.assertItems(["i-bar"])
583
    self.assertDryRun()
584
    self.assertQuery("type", ["hard"])
585
    self.assertQuery("ignore_secondaries", ["1"])
586

    
587
  def testShutdownInstance(self):
588
    self.rapi.AddResponse("1487")
589
    self.assertEqual(1487, self.client.ShutdownInstance("foo-instance",
590
                                                        dry_run=True))
591
    self.assertHandler(rlib2.R_2_instances_name_shutdown)
592
    self.assertItems(["foo-instance"])
593
    self.assertDryRun()
594

    
595
  def testStartupInstance(self):
596
    self.rapi.AddResponse("27149")
597
    self.assertEqual(27149, self.client.StartupInstance("bar-instance",
598
                                                        dry_run=True))
599
    self.assertHandler(rlib2.R_2_instances_name_startup)
600
    self.assertItems(["bar-instance"])
601
    self.assertDryRun()
602

    
603
  def testReinstallInstance(self):
604
    self.rapi.AddResponse(serializer.DumpJson([]))
605
    self.rapi.AddResponse("19119")
606
    self.assertEqual(19119, self.client.ReinstallInstance("baz-instance",
607
                                                          os="DOS",
608
                                                          no_startup=True))
609
    self.assertHandler(rlib2.R_2_instances_name_reinstall)
610
    self.assertItems(["baz-instance"])
611
    self.assertQuery("os", ["DOS"])
612
    self.assertQuery("nostartup", ["1"])
613
    self.assertEqual(self.rapi.CountPending(), 0)
614

    
615
  def testReinstallInstanceNew(self):
616
    self.rapi.AddResponse(serializer.DumpJson([rlib2._INST_REINSTALL_REQV1]))
617
    self.rapi.AddResponse("25689")
618
    self.assertEqual(25689, self.client.ReinstallInstance("moo-instance",
619
                                                          os="Debian",
620
                                                          no_startup=True))
621
    self.assertHandler(rlib2.R_2_instances_name_reinstall)
622
    self.assertItems(["moo-instance"])
623
    data = serializer.LoadJson(self.rapi.GetLastRequestData())
624
    self.assertEqual(len(data), 2)
625
    self.assertEqual(data["os"], "Debian")
626
    self.assertEqual(data["start"], False)
627
    self.assertEqual(self.rapi.CountPending(), 0)
628

    
629
  def testReinstallInstanceWithOsparams1(self):
630
    self.rapi.AddResponse(serializer.DumpJson([]))
631
    self.assertRaises(client.GanetiApiError, self.client.ReinstallInstance,
632
                      "doo-instance", osparams={"x": "y"})
633
    self.assertEqual(self.rapi.CountPending(), 0)
634

    
635
  def testReinstallInstanceWithOsparams2(self):
636
    osparams = {
637
      "Hello": "World",
638
      "foo": "bar",
639
      }
640
    self.rapi.AddResponse(serializer.DumpJson([rlib2._INST_REINSTALL_REQV1]))
641
    self.rapi.AddResponse("1717")
642
    self.assertEqual(1717, self.client.ReinstallInstance("zoo-instance",
643
                                                         osparams=osparams))
644
    self.assertHandler(rlib2.R_2_instances_name_reinstall)
645
    self.assertItems(["zoo-instance"])
646
    data = serializer.LoadJson(self.rapi.GetLastRequestData())
647
    self.assertEqual(len(data), 2)
648
    self.assertEqual(data["osparams"], osparams)
649
    self.assertEqual(data["start"], True)
650
    self.assertEqual(self.rapi.CountPending(), 0)
651

    
652
  def testReplaceInstanceDisks(self):
653
    self.rapi.AddResponse("999")
654
    job_id = self.client.ReplaceInstanceDisks("instance-name",
655
        disks=[0, 1], iallocator="hail")
656
    self.assertEqual(999, job_id)
657
    self.assertHandler(rlib2.R_2_instances_name_replace_disks)
658
    self.assertItems(["instance-name"])
659
    self.assertQuery("disks", ["0,1"])
660
    self.assertQuery("mode", ["replace_auto"])
661
    self.assertQuery("iallocator", ["hail"])
662

    
663
    self.rapi.AddResponse("1000")
664
    job_id = self.client.ReplaceInstanceDisks("instance-bar",
665
        disks=[1], mode="replace_on_secondary", remote_node="foo-node")
666
    self.assertEqual(1000, job_id)
667
    self.assertItems(["instance-bar"])
668
    self.assertQuery("disks", ["1"])
669
    self.assertQuery("remote_node", ["foo-node"])
670

    
671
    self.rapi.AddResponse("5175")
672
    self.assertEqual(5175, self.client.ReplaceInstanceDisks("instance-moo"))
673
    self.assertItems(["instance-moo"])
674
    self.assertQuery("disks", None)
675

    
676
  def testPrepareExport(self):
677
    self.rapi.AddResponse("8326")
678
    self.assertEqual(8326, self.client.PrepareExport("inst1", "local"))
679
    self.assertHandler(rlib2.R_2_instances_name_prepare_export)
680
    self.assertItems(["inst1"])
681
    self.assertQuery("mode", ["local"])
682

    
683
  def testExportInstance(self):
684
    self.rapi.AddResponse("19695")
685
    job_id = self.client.ExportInstance("inst2", "local", "nodeX",
686
                                        shutdown=True)
687
    self.assertEqual(job_id, 19695)
688
    self.assertHandler(rlib2.R_2_instances_name_export)
689
    self.assertItems(["inst2"])
690

    
691
    data = serializer.LoadJson(self.rapi.GetLastRequestData())
692
    self.assertEqual(data["mode"], "local")
693
    self.assertEqual(data["destination"], "nodeX")
694
    self.assertEqual(data["shutdown"], True)
695

    
696
  def testMigrateInstanceDefaults(self):
697
    self.rapi.AddResponse("24873")
698
    job_id = self.client.MigrateInstance("inst91")
699
    self.assertEqual(job_id, 24873)
700
    self.assertHandler(rlib2.R_2_instances_name_migrate)
701
    self.assertItems(["inst91"])
702

    
703
    data = serializer.LoadJson(self.rapi.GetLastRequestData())
704
    self.assertFalse(data)
705

    
706
  def testMigrateInstance(self):
707
    for mode in constants.HT_MIGRATION_MODES:
708
      for cleanup in [False, True]:
709
        self.rapi.AddResponse("31910")
710
        job_id = self.client.MigrateInstance("inst289", mode=mode,
711
                                             cleanup=cleanup)
712
        self.assertEqual(job_id, 31910)
713
        self.assertHandler(rlib2.R_2_instances_name_migrate)
714
        self.assertItems(["inst289"])
715

    
716
        data = serializer.LoadJson(self.rapi.GetLastRequestData())
717
        self.assertEqual(len(data), 2)
718
        self.assertEqual(data["mode"], mode)
719
        self.assertEqual(data["cleanup"], cleanup)
720

    
721
  def testFailoverInstanceDefaults(self):
722
    self.rapi.AddResponse("7639")
723
    job_id = self.client.FailoverInstance("inst13579")
724
    self.assertEqual(job_id, 7639)
725
    self.assertHandler(rlib2.R_2_instances_name_failover)
726
    self.assertItems(["inst13579"])
727

    
728
    data = serializer.LoadJson(self.rapi.GetLastRequestData())
729
    self.assertFalse(data)
730

    
731
  def testFailoverInstance(self):
732
    for iallocator in ["dumb", "hail"]:
733
      for ignore_consistency in [False, True]:
734
        for target_node in ["node-a", "node2"]:
735
          self.rapi.AddResponse("19161")
736
          job_id = \
737
            self.client.FailoverInstance("inst251", iallocator=iallocator,
738
                                         ignore_consistency=ignore_consistency,
739
                                         target_node=target_node)
740
          self.assertEqual(job_id, 19161)
741
          self.assertHandler(rlib2.R_2_instances_name_failover)
742
          self.assertItems(["inst251"])
743

    
744
          data = serializer.LoadJson(self.rapi.GetLastRequestData())
745
          self.assertEqual(len(data), 3)
746
          self.assertEqual(data["iallocator"], iallocator)
747
          self.assertEqual(data["ignore_consistency"], ignore_consistency)
748
          self.assertEqual(data["target_node"], target_node)
749
          self.assertEqual(self.rapi.CountPending(), 0)
750

    
751
  def testRenameInstanceDefaults(self):
752
    new_name = "newnametha7euqu"
753
    self.rapi.AddResponse("8791")
754
    job_id = self.client.RenameInstance("inst18821", new_name)
755
    self.assertEqual(job_id, 8791)
756
    self.assertHandler(rlib2.R_2_instances_name_rename)
757
    self.assertItems(["inst18821"])
758

    
759
    data = serializer.LoadJson(self.rapi.GetLastRequestData())
760
    self.assertEqualValues(data, {"new_name": new_name, })
761

    
762
  def testRenameInstance(self):
763
    new_name = "new-name-yiux1iin"
764
    for ip_check in [False, True]:
765
      for name_check in [False, True]:
766
        self.rapi.AddResponse("24776")
767
        job_id = self.client.RenameInstance("inst20967", new_name,
768
                                             ip_check=ip_check,
769
                                             name_check=name_check)
770
        self.assertEqual(job_id, 24776)
771
        self.assertHandler(rlib2.R_2_instances_name_rename)
772
        self.assertItems(["inst20967"])
773

    
774
        data = serializer.LoadJson(self.rapi.GetLastRequestData())
775
        self.assertEqual(len(data), 3)
776
        self.assertEqual(data["new_name"], new_name)
777
        self.assertEqual(data["ip_check"], ip_check)
778
        self.assertEqual(data["name_check"], name_check)
779

    
780
  def testGetJobs(self):
781
    self.rapi.AddResponse('[ { "id": "123", "uri": "\\/2\\/jobs\\/123" },'
782
                          '  { "id": "124", "uri": "\\/2\\/jobs\\/124" } ]')
783
    self.assertEqual([123, 124], self.client.GetJobs())
784
    self.assertHandler(rlib2.R_2_jobs)
785

    
786
  def testGetJobStatus(self):
787
    self.rapi.AddResponse("{\"foo\": \"bar\"}")
788
    self.assertEqual({"foo": "bar"}, self.client.GetJobStatus(1234))
789
    self.assertHandler(rlib2.R_2_jobs_id)
790
    self.assertItems(["1234"])
791

    
792
  def testWaitForJobChange(self):
793
    fields = ["id", "summary"]
794
    expected = {
795
      "job_info": [123, "something"],
796
      "log_entries": [],
797
      }
798

    
799
    self.rapi.AddResponse(serializer.DumpJson(expected))
800
    result = self.client.WaitForJobChange(123, fields, [], -1)
801
    self.assertEqualValues(expected, result)
802
    self.assertHandler(rlib2.R_2_jobs_id_wait)
803
    self.assertItems(["123"])
804

    
805
  def testCancelJob(self):
806
    self.rapi.AddResponse("[true, \"Job 123 will be canceled\"]")
807
    self.assertEqual([True, "Job 123 will be canceled"],
808
                     self.client.CancelJob(999, dry_run=True))
809
    self.assertHandler(rlib2.R_2_jobs_id)
810
    self.assertItems(["999"])
811
    self.assertDryRun()
812

    
813
  def testGetNodes(self):
814
    self.rapi.AddResponse("[ { \"id\": \"node1\", \"uri\": \"uri1\" },"
815
                          " { \"id\": \"node2\", \"uri\": \"uri2\" } ]")
816
    self.assertEqual(["node1", "node2"], self.client.GetNodes())
817
    self.assertHandler(rlib2.R_2_nodes)
818

    
819
    self.rapi.AddResponse("[ { \"id\": \"node1\", \"uri\": \"uri1\" },"
820
                          " { \"id\": \"node2\", \"uri\": \"uri2\" } ]")
821
    self.assertEqual([{"id": "node1", "uri": "uri1"},
822
                      {"id": "node2", "uri": "uri2"}],
823
                     self.client.GetNodes(bulk=True))
824
    self.assertHandler(rlib2.R_2_nodes)
825
    self.assertBulk()
826

    
827
  def testGetNode(self):
828
    self.rapi.AddResponse("{}")
829
    self.assertEqual({}, self.client.GetNode("node-foo"))
830
    self.assertHandler(rlib2.R_2_nodes_name)
831
    self.assertItems(["node-foo"])
832

    
833
  def testEvacuateNode(self):
834
    self.rapi.AddResponse(serializer.DumpJson([rlib2._NODE_EVAC_RES1]))
835
    self.rapi.AddResponse("9876")
836
    job_id = self.client.EvacuateNode("node-1", remote_node="node-2")
837
    self.assertEqual(9876, job_id)
838
    self.assertHandler(rlib2.R_2_nodes_name_evacuate)
839
    self.assertItems(["node-1"])
840
    self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
841
                     { "remote_node": "node-2", })
842
    self.assertEqual(self.rapi.CountPending(), 0)
843

    
844
    self.rapi.AddResponse(serializer.DumpJson([rlib2._NODE_EVAC_RES1]))
845
    self.rapi.AddResponse("8888")
846
    job_id = self.client.EvacuateNode("node-3", iallocator="hail", dry_run=True,
847
                                      mode=constants.NODE_EVAC_ALL,
848
                                      early_release=True)
849
    self.assertEqual(8888, job_id)
850
    self.assertItems(["node-3"])
851
    self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()), {
852
      "iallocator": "hail",
853
      "mode": "all",
854
      "early_release": True,
855
      })
856
    self.assertDryRun()
857

    
858
    self.assertRaises(client.GanetiApiError,
859
                      self.client.EvacuateNode,
860
                      "node-4", iallocator="hail", remote_node="node-5")
861
    self.assertEqual(self.rapi.CountPending(), 0)
862

    
863
  def testEvacuateNodeOldResponse(self):
864
    self.rapi.AddResponse(serializer.DumpJson([]))
865
    self.assertRaises(client.GanetiApiError, self.client.EvacuateNode,
866
                      "node-4", accept_old=False)
867
    self.assertEqual(self.rapi.CountPending(), 0)
868

    
869
    for mode in [client.NODE_EVAC_PRI, client.NODE_EVAC_ALL]:
870
      self.rapi.AddResponse(serializer.DumpJson([]))
871
      self.assertRaises(client.GanetiApiError, self.client.EvacuateNode,
872
                        "node-4", accept_old=True, mode=mode)
873
      self.assertEqual(self.rapi.CountPending(), 0)
874

    
875
    self.rapi.AddResponse(serializer.DumpJson([]))
876
    self.rapi.AddResponse(serializer.DumpJson("21533"))
877
    result = self.client.EvacuateNode("node-3", iallocator="hail",
878
                                      dry_run=True, accept_old=True,
879
                                      mode=client.NODE_EVAC_SEC,
880
                                      early_release=True)
881
    self.assertEqual(result, "21533")
882
    self.assertItems(["node-3"])
883
    self.assertQuery("iallocator", ["hail"])
884
    self.assertQuery("early_release", ["1"])
885
    self.assertFalse(self.rapi.GetLastRequestData())
886
    self.assertDryRun()
887
    self.assertEqual(self.rapi.CountPending(), 0)
888

    
889
  def testMigrateNode(self):
890
    self.rapi.AddResponse(serializer.DumpJson([]))
891
    self.rapi.AddResponse("1111")
892
    self.assertEqual(1111, self.client.MigrateNode("node-a", dry_run=True))
893
    self.assertHandler(rlib2.R_2_nodes_name_migrate)
894
    self.assertItems(["node-a"])
895
    self.assert_("mode" not in self.rapi.GetLastHandler().queryargs)
896
    self.assertDryRun()
897
    self.assertFalse(self.rapi.GetLastRequestData())
898

    
899
    self.rapi.AddResponse(serializer.DumpJson([]))
900
    self.rapi.AddResponse("1112")
901
    self.assertEqual(1112, self.client.MigrateNode("node-a", dry_run=True,
902
                                                   mode="live"))
903
    self.assertHandler(rlib2.R_2_nodes_name_migrate)
904
    self.assertItems(["node-a"])
905
    self.assertQuery("mode", ["live"])
906
    self.assertDryRun()
907
    self.assertFalse(self.rapi.GetLastRequestData())
908

    
909
    self.rapi.AddResponse(serializer.DumpJson([]))
910
    self.assertRaises(client.GanetiApiError, self.client.MigrateNode,
911
                      "node-c", target_node="foonode")
912
    self.assertEqual(self.rapi.CountPending(), 0)
913

    
914
  def testMigrateNodeBodyData(self):
915
    self.rapi.AddResponse(serializer.DumpJson([rlib2._NODE_MIGRATE_REQV1]))
916
    self.rapi.AddResponse("27539")
917
    self.assertEqual(27539, self.client.MigrateNode("node-a", dry_run=False,
918
                                                    mode="live"))
919
    self.assertHandler(rlib2.R_2_nodes_name_migrate)
920
    self.assertItems(["node-a"])
921
    self.assertFalse(self.rapi.GetLastHandler().queryargs)
922
    self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
923
                     { "mode": "live", })
924

    
925
    self.rapi.AddResponse(serializer.DumpJson([rlib2._NODE_MIGRATE_REQV1]))
926
    self.rapi.AddResponse("14219")
927
    self.assertEqual(14219, self.client.MigrateNode("node-x", dry_run=True,
928
                                                    target_node="node9",
929
                                                    iallocator="ial"))
930
    self.assertHandler(rlib2.R_2_nodes_name_migrate)
931
    self.assertItems(["node-x"])
932
    self.assertDryRun()
933
    self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
934
                     { "target_node": "node9", "iallocator": "ial", })
935

    
936
    self.assertEqual(self.rapi.CountPending(), 0)
937

    
938
  def testGetNodeRole(self):
939
    self.rapi.AddResponse("\"master\"")
940
    self.assertEqual("master", self.client.GetNodeRole("node-a"))
941
    self.assertHandler(rlib2.R_2_nodes_name_role)
942
    self.assertItems(["node-a"])
943

    
944
  def testSetNodeRole(self):
945
    self.rapi.AddResponse("789")
946
    self.assertEqual(789,
947
        self.client.SetNodeRole("node-foo", "master-candidate", force=True))
948
    self.assertHandler(rlib2.R_2_nodes_name_role)
949
    self.assertItems(["node-foo"])
950
    self.assertQuery("force", ["1"])
951
    self.assertEqual("\"master-candidate\"", self.rapi.GetLastRequestData())
952

    
953
  def testPowercycleNode(self):
954
    self.rapi.AddResponse("23051")
955
    self.assertEqual(23051,
956
        self.client.PowercycleNode("node5468", force=True))
957
    self.assertHandler(rlib2.R_2_nodes_name_powercycle)
958
    self.assertItems(["node5468"])
959
    self.assertQuery("force", ["1"])
960
    self.assertFalse(self.rapi.GetLastRequestData())
961
    self.assertEqual(self.rapi.CountPending(), 0)
962

    
963
  def testModifyNode(self):
964
    self.rapi.AddResponse("3783")
965
    job_id = self.client.ModifyNode("node16979.example.com", drained=True)
966
    self.assertEqual(job_id, 3783)
967
    self.assertHandler(rlib2.R_2_nodes_name_modify)
968
    self.assertItems(["node16979.example.com"])
969
    self.assertEqual(self.rapi.CountPending(), 0)
970

    
971
  def testGetNodeStorageUnits(self):
972
    self.rapi.AddResponse("42")
973
    self.assertEqual(42,
974
        self.client.GetNodeStorageUnits("node-x", "lvm-pv", "fields"))
975
    self.assertHandler(rlib2.R_2_nodes_name_storage)
976
    self.assertItems(["node-x"])
977
    self.assertQuery("storage_type", ["lvm-pv"])
978
    self.assertQuery("output_fields", ["fields"])
979

    
980
  def testModifyNodeStorageUnits(self):
981
    self.rapi.AddResponse("14")
982
    self.assertEqual(14,
983
        self.client.ModifyNodeStorageUnits("node-z", "lvm-pv", "hda"))
984
    self.assertHandler(rlib2.R_2_nodes_name_storage_modify)
985
    self.assertItems(["node-z"])
986
    self.assertQuery("storage_type", ["lvm-pv"])
987
    self.assertQuery("name", ["hda"])
988
    self.assertQuery("allocatable", None)
989

    
990
    for allocatable, query_allocatable in [(True, "1"), (False, "0")]:
991
      self.rapi.AddResponse("7205")
992
      job_id = self.client.ModifyNodeStorageUnits("node-z", "lvm-pv", "hda",
993
                                                  allocatable=allocatable)
994
      self.assertEqual(7205, job_id)
995
      self.assertHandler(rlib2.R_2_nodes_name_storage_modify)
996
      self.assertItems(["node-z"])
997
      self.assertQuery("storage_type", ["lvm-pv"])
998
      self.assertQuery("name", ["hda"])
999
      self.assertQuery("allocatable", [query_allocatable])
1000

    
1001
  def testRepairNodeStorageUnits(self):
1002
    self.rapi.AddResponse("99")
1003
    self.assertEqual(99, self.client.RepairNodeStorageUnits("node-z", "lvm-pv",
1004
                                                            "hda"))
1005
    self.assertHandler(rlib2.R_2_nodes_name_storage_repair)
1006
    self.assertItems(["node-z"])
1007
    self.assertQuery("storage_type", ["lvm-pv"])
1008
    self.assertQuery("name", ["hda"])
1009

    
1010
  def testGetNodeTags(self):
1011
    self.rapi.AddResponse("[\"fry\", \"bender\"]")
1012
    self.assertEqual(["fry", "bender"], self.client.GetNodeTags("node-k"))
1013
    self.assertHandler(rlib2.R_2_nodes_name_tags)
1014
    self.assertItems(["node-k"])
1015

    
1016
  def testAddNodeTags(self):
1017
    self.rapi.AddResponse("1234")
1018
    self.assertEqual(1234,
1019
        self.client.AddNodeTags("node-v", ["awesome"], dry_run=True))
1020
    self.assertHandler(rlib2.R_2_nodes_name_tags)
1021
    self.assertItems(["node-v"])
1022
    self.assertDryRun()
1023
    self.assertQuery("tag", ["awesome"])
1024

    
1025
  def testDeleteNodeTags(self):
1026
    self.rapi.AddResponse("16861")
1027
    self.assertEqual(16861, self.client.DeleteNodeTags("node-w", ["awesome"],
1028
                                                       dry_run=True))
1029
    self.assertHandler(rlib2.R_2_nodes_name_tags)
1030
    self.assertItems(["node-w"])
1031
    self.assertDryRun()
1032
    self.assertQuery("tag", ["awesome"])
1033

    
1034
  def testGetGroups(self):
1035
    groups = [{"name": "group1",
1036
               "uri": "/2/groups/group1",
1037
               },
1038
              {"name": "group2",
1039
               "uri": "/2/groups/group2",
1040
               },
1041
              ]
1042
    self.rapi.AddResponse(serializer.DumpJson(groups))
1043
    self.assertEqual(["group1", "group2"], self.client.GetGroups())
1044
    self.assertHandler(rlib2.R_2_groups)
1045

    
1046
  def testGetGroupsBulk(self):
1047
    groups = [{"name": "group1",
1048
               "uri": "/2/groups/group1",
1049
               "node_cnt": 2,
1050
               "node_list": ["gnt1.test",
1051
                             "gnt2.test",
1052
                             ],
1053
               },
1054
              {"name": "group2",
1055
               "uri": "/2/groups/group2",
1056
               "node_cnt": 1,
1057
               "node_list": ["gnt3.test",
1058
                             ],
1059
               },
1060
              ]
1061
    self.rapi.AddResponse(serializer.DumpJson(groups))
1062

    
1063
    self.assertEqual(groups, self.client.GetGroups(bulk=True))
1064
    self.assertHandler(rlib2.R_2_groups)
1065
    self.assertBulk()
1066

    
1067
  def testGetGroup(self):
1068
    group = {"ctime": None,
1069
             "name": "default",
1070
             }
1071
    self.rapi.AddResponse(serializer.DumpJson(group))
1072
    self.assertEqual({"ctime": None, "name": "default"},
1073
                     self.client.GetGroup("default"))
1074
    self.assertHandler(rlib2.R_2_groups_name)
1075
    self.assertItems(["default"])
1076

    
1077
  def testCreateGroup(self):
1078
    self.rapi.AddResponse("12345")
1079
    job_id = self.client.CreateGroup("newgroup", dry_run=True)
1080
    self.assertEqual(job_id, 12345)
1081
    self.assertHandler(rlib2.R_2_groups)
1082
    self.assertDryRun()
1083

    
1084
  def testDeleteGroup(self):
1085
    self.rapi.AddResponse("12346")
1086
    job_id = self.client.DeleteGroup("newgroup", dry_run=True)
1087
    self.assertEqual(job_id, 12346)
1088
    self.assertHandler(rlib2.R_2_groups_name)
1089
    self.assertDryRun()
1090

    
1091
  def testRenameGroup(self):
1092
    self.rapi.AddResponse("12347")
1093
    job_id = self.client.RenameGroup("oldname", "newname")
1094
    self.assertEqual(job_id, 12347)
1095
    self.assertHandler(rlib2.R_2_groups_name_rename)
1096

    
1097
  def testModifyGroup(self):
1098
    self.rapi.AddResponse("12348")
1099
    job_id = self.client.ModifyGroup("mygroup", alloc_policy="foo")
1100
    self.assertEqual(job_id, 12348)
1101
    self.assertHandler(rlib2.R_2_groups_name_modify)
1102

    
1103
  def testAssignGroupNodes(self):
1104
    self.rapi.AddResponse("12349")
1105
    job_id = self.client.AssignGroupNodes("mygroup", ["node1", "node2"],
1106
                                          force=True, dry_run=True)
1107
    self.assertEqual(job_id, 12349)
1108
    self.assertHandler(rlib2.R_2_groups_name_assign_nodes)
1109
    self.assertDryRun()
1110
    self.assertUseForce()
1111

    
1112
  def testModifyInstance(self):
1113
    self.rapi.AddResponse("23681")
1114
    job_id = self.client.ModifyInstance("inst7210", os_name="linux")
1115
    self.assertEqual(job_id, 23681)
1116
    self.assertItems(["inst7210"])
1117
    self.assertHandler(rlib2.R_2_instances_name_modify)
1118
    self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
1119
                     { "os_name": "linux", })
1120

    
1121
  def testModifyCluster(self):
1122
    for mnh in [None, False, True]:
1123
      self.rapi.AddResponse("14470")
1124
      self.assertEqual(14470,
1125
        self.client.ModifyCluster(maintain_node_health=mnh))
1126
      self.assertHandler(rlib2.R_2_cluster_modify)
1127
      self.assertItems([])
1128
      data = serializer.LoadJson(self.rapi.GetLastRequestData())
1129
      self.assertEqual(len(data), 1)
1130
      self.assertEqual(data["maintain_node_health"], mnh)
1131
      self.assertEqual(self.rapi.CountPending(), 0)
1132

    
1133
  def testRedistributeConfig(self):
1134
    self.rapi.AddResponse("3364")
1135
    job_id = self.client.RedistributeConfig()
1136
    self.assertEqual(job_id, 3364)
1137
    self.assertItems([])
1138
    self.assertHandler(rlib2.R_2_redist_config)
1139

    
1140
  def testActivateInstanceDisks(self):
1141
    self.rapi.AddResponse("23547")
1142
    job_id = self.client.ActivateInstanceDisks("inst28204")
1143
    self.assertEqual(job_id, 23547)
1144
    self.assertItems(["inst28204"])
1145
    self.assertHandler(rlib2.R_2_instances_name_activate_disks)
1146
    self.assertFalse(self.rapi.GetLastHandler().queryargs)
1147

    
1148
  def testActivateInstanceDisksIgnoreSize(self):
1149
    self.rapi.AddResponse("11044")
1150
    job_id = self.client.ActivateInstanceDisks("inst28204", ignore_size=True)
1151
    self.assertEqual(job_id, 11044)
1152
    self.assertItems(["inst28204"])
1153
    self.assertHandler(rlib2.R_2_instances_name_activate_disks)
1154
    self.assertQuery("ignore_size", ["1"])
1155

    
1156
  def testDeactivateInstanceDisks(self):
1157
    self.rapi.AddResponse("14591")
1158
    job_id = self.client.DeactivateInstanceDisks("inst28234")
1159
    self.assertEqual(job_id, 14591)
1160
    self.assertItems(["inst28234"])
1161
    self.assertHandler(rlib2.R_2_instances_name_deactivate_disks)
1162
    self.assertFalse(self.rapi.GetLastHandler().queryargs)
1163

    
1164
  def testRecreateInstanceDisks(self):
1165
    self.rapi.AddResponse("13553")
1166
    job_id = self.client.RecreateInstanceDisks("inst23153")
1167
    self.assertEqual(job_id, 13553)
1168
    self.assertItems(["inst23153"])
1169
    self.assertHandler(rlib2.R_2_instances_name_recreate_disks)
1170
    self.assertFalse(self.rapi.GetLastHandler().queryargs)
1171

    
1172
  def testGetInstanceConsole(self):
1173
    self.rapi.AddResponse("26876")
1174
    job_id = self.client.GetInstanceConsole("inst21491")
1175
    self.assertEqual(job_id, 26876)
1176
    self.assertItems(["inst21491"])
1177
    self.assertHandler(rlib2.R_2_instances_name_console)
1178
    self.assertFalse(self.rapi.GetLastHandler().queryargs)
1179
    self.assertFalse(self.rapi.GetLastRequestData())
1180

    
1181
  def testGrowInstanceDisk(self):
1182
    for idx, wait_for_sync in enumerate([None, False, True]):
1183
      amount = 128 + (512 * idx)
1184
      self.assertEqual(self.rapi.CountPending(), 0)
1185
      self.rapi.AddResponse("30783")
1186
      self.assertEqual(30783,
1187
        self.client.GrowInstanceDisk("eze8ch", idx, amount,
1188
                                     wait_for_sync=wait_for_sync))
1189
      self.assertHandler(rlib2.R_2_instances_name_disk_grow)
1190
      self.assertItems(["eze8ch", str(idx)])
1191
      data = serializer.LoadJson(self.rapi.GetLastRequestData())
1192
      if wait_for_sync is None:
1193
        self.assertEqual(len(data), 1)
1194
        self.assert_("wait_for_sync" not in data)
1195
      else:
1196
        self.assertEqual(len(data), 2)
1197
        self.assertEqual(data["wait_for_sync"], wait_for_sync)
1198
      self.assertEqual(data["amount"], amount)
1199
      self.assertEqual(self.rapi.CountPending(), 0)
1200

    
1201
  def testGetGroupTags(self):
1202
    self.rapi.AddResponse("[]")
1203
    self.assertEqual([], self.client.GetGroupTags("fooGroup"))
1204
    self.assertHandler(rlib2.R_2_groups_name_tags)
1205
    self.assertItems(["fooGroup"])
1206

    
1207
  def testAddGroupTags(self):
1208
    self.rapi.AddResponse("1234")
1209
    self.assertEqual(1234,
1210
        self.client.AddGroupTags("fooGroup", ["awesome"], dry_run=True))
1211
    self.assertHandler(rlib2.R_2_groups_name_tags)
1212
    self.assertItems(["fooGroup"])
1213
    self.assertDryRun()
1214
    self.assertQuery("tag", ["awesome"])
1215

    
1216
  def testDeleteGroupTags(self):
1217
    self.rapi.AddResponse("25826")
1218
    self.assertEqual(25826, self.client.DeleteGroupTags("foo", ["awesome"],
1219
                                                        dry_run=True))
1220
    self.assertHandler(rlib2.R_2_groups_name_tags)
1221
    self.assertItems(["foo"])
1222
    self.assertDryRun()
1223
    self.assertQuery("tag", ["awesome"])
1224

    
1225
  def testQuery(self):
1226
    for idx, what in enumerate(constants.QR_VIA_RAPI):
1227
      for idx2, qfilter in enumerate([None, ["?", "name"]]):
1228
        job_id = 11010 + (idx << 4) + (idx2 << 16)
1229
        fields = sorted(query.ALL_FIELDS[what].keys())[:10]
1230

    
1231
        self.rapi.AddResponse(str(job_id))
1232
        self.assertEqual(self.client.Query(what, fields, qfilter=qfilter),
1233
                         job_id)
1234
        self.assertItems([what])
1235
        self.assertHandler(rlib2.R_2_query)
1236
        self.assertFalse(self.rapi.GetLastHandler().queryargs)
1237
        data = serializer.LoadJson(self.rapi.GetLastRequestData())
1238
        self.assertEqual(data["fields"], fields)
1239
        if qfilter is None:
1240
          self.assertTrue("qfilter" not in data)
1241
        else:
1242
          self.assertEqual(data["qfilter"], qfilter)
1243
        self.assertEqual(self.rapi.CountPending(), 0)
1244

    
1245
  def testQueryFields(self):
1246
    exp_result = objects.QueryFieldsResponse(fields=[
1247
      objects.QueryFieldDefinition(name="pnode", title="PNode",
1248
                                   kind=constants.QFT_NUMBER),
1249
      objects.QueryFieldDefinition(name="other", title="Other",
1250
                                   kind=constants.QFT_BOOL),
1251
      ])
1252

    
1253
    for what in constants.QR_VIA_RAPI:
1254
      for fields in [None, ["name", "_unknown_"], ["&", "?|"]]:
1255
        self.rapi.AddResponse(serializer.DumpJson(exp_result.ToDict()))
1256
        result = self.client.QueryFields(what, fields=fields)
1257
        self.assertItems([what])
1258
        self.assertHandler(rlib2.R_2_query_fields)
1259
        self.assertFalse(self.rapi.GetLastRequestData())
1260

    
1261
        queryargs = self.rapi.GetLastHandler().queryargs
1262
        if fields is None:
1263
          self.assertFalse(queryargs)
1264
        else:
1265
          self.assertEqual(queryargs, {
1266
            "fields": [",".join(fields)],
1267
            })
1268

    
1269
        self.assertEqual(objects.QueryFieldsResponse.FromDict(result).ToDict(),
1270
                         exp_result.ToDict())
1271

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

    
1274
  def testWaitForJobCompletionNoChange(self):
1275
    resp = serializer.DumpJson({
1276
      "status": constants.JOB_STATUS_WAITING,
1277
      })
1278

    
1279
    for retries in [1, 5, 25]:
1280
      for _ in range(retries):
1281
        self.rapi.AddResponse(resp)
1282

    
1283
      self.assertFalse(self.client.WaitForJobCompletion(22789, period=None,
1284
                                                        retries=retries))
1285
      self.assertHandler(rlib2.R_2_jobs_id)
1286
      self.assertItems(["22789"])
1287

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

    
1290
  def testWaitForJobCompletionAlreadyFinished(self):
1291
    self.rapi.AddResponse(serializer.DumpJson({
1292
      "status": constants.JOB_STATUS_SUCCESS,
1293
      }))
1294

    
1295
    self.assertTrue(self.client.WaitForJobCompletion(22793, period=None,
1296
                                                     retries=1))
1297
    self.assertHandler(rlib2.R_2_jobs_id)
1298
    self.assertItems(["22793"])
1299

    
1300
    self.assertEqual(self.rapi.CountPending(), 0)
1301

    
1302
  def testWaitForJobCompletionEmptyResponse(self):
1303
    self.rapi.AddResponse("{}")
1304
    self.assertFalse(self.client.WaitForJobCompletion(22793, period=None,
1305
                                                     retries=10))
1306
    self.assertHandler(rlib2.R_2_jobs_id)
1307
    self.assertItems(["22793"])
1308

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

    
1311
  def testWaitForJobCompletionOutOfRetries(self):
1312
    for retries in [3, 10, 21]:
1313
      for _ in range(retries):
1314
        self.rapi.AddResponse(serializer.DumpJson({
1315
          "status": constants.JOB_STATUS_RUNNING,
1316
          }))
1317

    
1318
      self.assertFalse(self.client.WaitForJobCompletion(30948, period=None,
1319
                                                        retries=retries - 1))
1320
      self.assertHandler(rlib2.R_2_jobs_id)
1321
      self.assertItems(["30948"])
1322

    
1323
      self.assertEqual(self.rapi.CountPending(), 1)
1324
      self.rapi.ResetResponses()
1325

    
1326
  def testWaitForJobCompletionSuccessAndFailure(self):
1327
    for retries in [1, 4, 13]:
1328
      for (success, end_status) in [(False, constants.JOB_STATUS_ERROR),
1329
                                    (True, constants.JOB_STATUS_SUCCESS)]:
1330
        for _ in range(retries):
1331
          self.rapi.AddResponse(serializer.DumpJson({
1332
            "status": constants.JOB_STATUS_RUNNING,
1333
            }))
1334

    
1335
        self.rapi.AddResponse(serializer.DumpJson({
1336
          "status": end_status,
1337
          }))
1338

    
1339
        result = self.client.WaitForJobCompletion(3187, period=None,
1340
                                                  retries=retries + 1)
1341
        self.assertEqual(result, success)
1342
        self.assertHandler(rlib2.R_2_jobs_id)
1343
        self.assertItems(["3187"])
1344

    
1345
        self.assertEqual(self.rapi.CountPending(), 0)
1346

    
1347

    
1348
class RapiTestRunner(unittest.TextTestRunner):
1349
  def run(self, *args):
1350
    global _used_handlers
1351
    assert _used_handlers is None
1352

    
1353
    _used_handlers = set()
1354
    try:
1355
      # Run actual tests
1356
      result = unittest.TextTestRunner.run(self, *args)
1357

    
1358
      diff = (set(connector.CONNECTOR.values()) - _used_handlers -
1359
             _KNOWN_UNUSED)
1360
      if diff:
1361
        raise AssertionError("The following RAPI resources were not used by the"
1362
                             " RAPI client: %r" % utils.CommaJoin(diff))
1363
    finally:
1364
      # Reset global variable
1365
      _used_handlers = None
1366

    
1367
    return result
1368

    
1369

    
1370
if __name__ == '__main__':
1371
  client.UsesRapiClient(testutils.GanetiTestProgram)(testRunner=RapiTestRunner)