Statistics
| Branch: | Tag: | Revision:

root / test / ganeti.rapi.client_unittest.py @ 6e8091f9

History | View | Annotate | Download (55.3 kB)

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

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

    
21

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

    
24

    
25
import unittest
26
import warnings
27
import pycurl
28

    
29
from ganeti import 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, NotImplemented, 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 test404(self):
142
    (code, _, body) = RapiMock().FetchResponse("/foo", "GET", None, None)
143
    self.assertEqual(code, 404)
144
    self.assertTrue(body is None)
145

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

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

    
159

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

    
164

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

    
169

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

    
174

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

    
179

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

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

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

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

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

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

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

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

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

    
235
  def testNoCertVerify(self):
236
    cfgfn = client.GenericCurlConfig()
237

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

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

    
247
  def testCertVerifyCurlBundle(self):
248
    cfgfn = client.GenericCurlConfig(use_curl_cabundle=True)
249

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

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

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

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

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

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

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

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

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

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

    
297
    self.assertRaises(client.Error, cl._CreateCurl)
298

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

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

    
309
    self.assertRaises(client.Error, cl._CreateCurl)
310

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

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

    
321
    self.assertRaises(NotImplementedError, cl._CreateCurl)
322

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

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

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

    
337

    
338
class GanetiRapiClientTests(testutils.GanetiTestCase):
339
  def setUp(self):
340
    testutils.GanetiTestCase.setUp(self)
341

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

    
347
  def assertHandler(self, handler_cls):
348
    self.failUnless(isinstance(self.rapi.GetLastHandler(), handler_cls))
349

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

    
353
  def assertItems(self, items):
354
    self.assertEqual(items, self.rapi.GetLastHandler().items)
355

    
356
  def assertBulk(self):
357
    self.assertTrue(self.rapi.GetLastHandler().useBulk())
358

    
359
  def assertDryRun(self):
360
    self.assertTrue(self.rapi.GetLastHandler().dryRun())
361

    
362
  def assertUseForce(self):
363
    self.assertTrue(self.rapi.GetLastHandler().useForce())
364

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

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

    
382
    self.assertEqualValues(self.client._EncodeQuery(query),
383
                           expected)
384

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
506
  def testCreateInstanceOldVersion(self):
507
    # The old request format, version 0, is no longer supported
508
    self.rapi.AddResponse(None, code=404)
509
    self.assertRaises(client.GanetiApiError, self.client.CreateInstance,
510
                      "create", "inst1.example.com", "plain", [], [])
511
    self.assertEqual(self.rapi.CountPending(), 0)
512

    
513
  def testCreateInstance(self):
514
    self.rapi.AddResponse(serializer.DumpJson([rlib2._INST_CREATE_REQV1]))
515
    self.rapi.AddResponse("23030")
516
    job_id = self.client.CreateInstance("create", "inst1.example.com",
517
                                        "plain", [], [], dry_run=True)
518
    self.assertEqual(job_id, 23030)
519
    self.assertHandler(rlib2.R_2_instances)
520
    self.assertDryRun()
521

    
522
    data = serializer.LoadJson(self.rapi.GetLastRequestData())
523

    
524
    for field in ["dry_run", "beparams", "hvparams", "start"]:
525
      self.assertFalse(field in data)
526

    
527
    self.assertEqual(data["name"], "inst1.example.com")
528
    self.assertEqual(data["disk_template"], "plain")
529

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

    
542
    data = serializer.LoadJson(self.rapi.GetLastRequestData())
543
    self.assertEqual(data[rlib2._REQ_DATA_VERSION], 1)
544
    self.assertEqual(data["name"], "inst2.example.com")
545
    self.assertEqual(data["disk_template"], "drbd8")
546
    self.assertEqual(data["start"], True)
547
    self.assertEqual(data["ip_check"], False)
548
    self.assertEqualValues(data["disks"], [{"size": 100,}])
549
    self.assertEqualValues(data["nics"], [{}, {"bridge": "br1", }])
550

    
551
  def testDeleteInstance(self):
552
    self.rapi.AddResponse("1234")
553
    self.assertEqual(1234, self.client.DeleteInstance("instance", dry_run=True))
554
    self.assertHandler(rlib2.R_2_instances_name)
555
    self.assertItems(["instance"])
556
    self.assertDryRun()
557

    
558
  def testGetInstanceTags(self):
559
    self.rapi.AddResponse("[]")
560
    self.assertEqual([], self.client.GetInstanceTags("fooinstance"))
561
    self.assertHandler(rlib2.R_2_instances_name_tags)
562
    self.assertItems(["fooinstance"])
563

    
564
  def testAddInstanceTags(self):
565
    self.rapi.AddResponse("1234")
566
    self.assertEqual(1234,
567
        self.client.AddInstanceTags("fooinstance", ["awesome"], dry_run=True))
568
    self.assertHandler(rlib2.R_2_instances_name_tags)
569
    self.assertItems(["fooinstance"])
570
    self.assertDryRun()
571
    self.assertQuery("tag", ["awesome"])
572

    
573
  def testDeleteInstanceTags(self):
574
    self.rapi.AddResponse("25826")
575
    self.assertEqual(25826, self.client.DeleteInstanceTags("foo", ["awesome"],
576
                                                           dry_run=True))
577
    self.assertHandler(rlib2.R_2_instances_name_tags)
578
    self.assertItems(["foo"])
579
    self.assertDryRun()
580
    self.assertQuery("tag", ["awesome"])
581

    
582
  def testRebootInstance(self):
583
    self.rapi.AddResponse("6146")
584
    job_id = self.client.RebootInstance("i-bar", reboot_type="hard",
585
                                        ignore_secondaries=True, dry_run=True)
586
    self.assertEqual(6146, job_id)
587
    self.assertHandler(rlib2.R_2_instances_name_reboot)
588
    self.assertItems(["i-bar"])
589
    self.assertDryRun()
590
    self.assertQuery("type", ["hard"])
591
    self.assertQuery("ignore_secondaries", ["1"])
592

    
593
  def testShutdownInstance(self):
594
    self.rapi.AddResponse("1487")
595
    self.assertEqual(1487, self.client.ShutdownInstance("foo-instance",
596
                                                        dry_run=True))
597
    self.assertHandler(rlib2.R_2_instances_name_shutdown)
598
    self.assertItems(["foo-instance"])
599
    self.assertDryRun()
600

    
601
  def testStartupInstance(self):
602
    self.rapi.AddResponse("27149")
603
    self.assertEqual(27149, self.client.StartupInstance("bar-instance",
604
                                                        dry_run=True))
605
    self.assertHandler(rlib2.R_2_instances_name_startup)
606
    self.assertItems(["bar-instance"])
607
    self.assertDryRun()
608

    
609
  def testReinstallInstance(self):
610
    self.rapi.AddResponse(serializer.DumpJson([]))
611
    self.rapi.AddResponse("19119")
612
    self.assertEqual(19119, self.client.ReinstallInstance("baz-instance",
613
                                                          os="DOS",
614
                                                          no_startup=True))
615
    self.assertHandler(rlib2.R_2_instances_name_reinstall)
616
    self.assertItems(["baz-instance"])
617
    self.assertQuery("os", ["DOS"])
618
    self.assertQuery("nostartup", ["1"])
619
    self.assertEqual(self.rapi.CountPending(), 0)
620

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

    
635
  def testReinstallInstanceWithOsparams1(self):
636
    self.rapi.AddResponse(serializer.DumpJson([]))
637
    self.assertRaises(client.GanetiApiError, self.client.ReinstallInstance,
638
                      "doo-instance", osparams={"x": "y"})
639
    self.assertEqual(self.rapi.CountPending(), 0)
640

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

    
658
  def testReplaceInstanceDisks(self):
659
    self.rapi.AddResponse("999")
660
    job_id = self.client.ReplaceInstanceDisks("instance-name",
661
        disks=[0, 1], iallocator="hail")
662
    self.assertEqual(999, job_id)
663
    self.assertHandler(rlib2.R_2_instances_name_replace_disks)
664
    self.assertItems(["instance-name"])
665
    self.assertQuery("disks", ["0,1"])
666
    self.assertQuery("mode", ["replace_auto"])
667
    self.assertQuery("iallocator", ["hail"])
668

    
669
    self.rapi.AddResponse("1000")
670
    job_id = self.client.ReplaceInstanceDisks("instance-bar",
671
        disks=[1], mode="replace_on_secondary", remote_node="foo-node")
672
    self.assertEqual(1000, job_id)
673
    self.assertItems(["instance-bar"])
674
    self.assertQuery("disks", ["1"])
675
    self.assertQuery("remote_node", ["foo-node"])
676

    
677
    self.rapi.AddResponse("5175")
678
    self.assertEqual(5175, self.client.ReplaceInstanceDisks("instance-moo"))
679
    self.assertItems(["instance-moo"])
680
    self.assertQuery("disks", None)
681

    
682
  def testPrepareExport(self):
683
    self.rapi.AddResponse("8326")
684
    self.assertEqual(8326, self.client.PrepareExport("inst1", "local"))
685
    self.assertHandler(rlib2.R_2_instances_name_prepare_export)
686
    self.assertItems(["inst1"])
687
    self.assertQuery("mode", ["local"])
688

    
689
  def testExportInstance(self):
690
    self.rapi.AddResponse("19695")
691
    job_id = self.client.ExportInstance("inst2", "local", "nodeX",
692
                                        shutdown=True)
693
    self.assertEqual(job_id, 19695)
694
    self.assertHandler(rlib2.R_2_instances_name_export)
695
    self.assertItems(["inst2"])
696

    
697
    data = serializer.LoadJson(self.rapi.GetLastRequestData())
698
    self.assertEqual(data["mode"], "local")
699
    self.assertEqual(data["destination"], "nodeX")
700
    self.assertEqual(data["shutdown"], True)
701

    
702
  def testMigrateInstanceDefaults(self):
703
    self.rapi.AddResponse("24873")
704
    job_id = self.client.MigrateInstance("inst91")
705
    self.assertEqual(job_id, 24873)
706
    self.assertHandler(rlib2.R_2_instances_name_migrate)
707
    self.assertItems(["inst91"])
708

    
709
    data = serializer.LoadJson(self.rapi.GetLastRequestData())
710
    self.assertFalse(data)
711

    
712
  def testMigrateInstance(self):
713
    for mode in constants.HT_MIGRATION_MODES:
714
      for cleanup in [False, True]:
715
        self.rapi.AddResponse("31910")
716
        job_id = self.client.MigrateInstance("inst289", mode=mode,
717
                                             cleanup=cleanup)
718
        self.assertEqual(job_id, 31910)
719
        self.assertHandler(rlib2.R_2_instances_name_migrate)
720
        self.assertItems(["inst289"])
721

    
722
        data = serializer.LoadJson(self.rapi.GetLastRequestData())
723
        self.assertEqual(len(data), 2)
724
        self.assertEqual(data["mode"], mode)
725
        self.assertEqual(data["cleanup"], cleanup)
726

    
727
  def testFailoverInstanceDefaults(self):
728
    self.rapi.AddResponse("7639")
729
    job_id = self.client.FailoverInstance("inst13579")
730
    self.assertEqual(job_id, 7639)
731
    self.assertHandler(rlib2.R_2_instances_name_failover)
732
    self.assertItems(["inst13579"])
733

    
734
    data = serializer.LoadJson(self.rapi.GetLastRequestData())
735
    self.assertFalse(data)
736

    
737
  def testFailoverInstance(self):
738
    for iallocator in ["dumb", "hail"]:
739
      for ignore_consistency in [False, True]:
740
        for target_node in ["node-a", "node2"]:
741
          self.rapi.AddResponse("19161")
742
          job_id = \
743
            self.client.FailoverInstance("inst251", iallocator=iallocator,
744
                                         ignore_consistency=ignore_consistency,
745
                                         target_node=target_node)
746
          self.assertEqual(job_id, 19161)
747
          self.assertHandler(rlib2.R_2_instances_name_failover)
748
          self.assertItems(["inst251"])
749

    
750
          data = serializer.LoadJson(self.rapi.GetLastRequestData())
751
          self.assertEqual(len(data), 3)
752
          self.assertEqual(data["iallocator"], iallocator)
753
          self.assertEqual(data["ignore_consistency"], ignore_consistency)
754
          self.assertEqual(data["target_node"], target_node)
755
          self.assertEqual(self.rapi.CountPending(), 0)
756

    
757
  def testRenameInstanceDefaults(self):
758
    new_name = "newnametha7euqu"
759
    self.rapi.AddResponse("8791")
760
    job_id = self.client.RenameInstance("inst18821", new_name)
761
    self.assertEqual(job_id, 8791)
762
    self.assertHandler(rlib2.R_2_instances_name_rename)
763
    self.assertItems(["inst18821"])
764

    
765
    data = serializer.LoadJson(self.rapi.GetLastRequestData())
766
    self.assertEqualValues(data, {"new_name": new_name, })
767

    
768
  def testRenameInstance(self):
769
    new_name = "new-name-yiux1iin"
770
    for ip_check in [False, True]:
771
      for name_check in [False, True]:
772
        self.rapi.AddResponse("24776")
773
        job_id = self.client.RenameInstance("inst20967", new_name,
774
                                             ip_check=ip_check,
775
                                             name_check=name_check)
776
        self.assertEqual(job_id, 24776)
777
        self.assertHandler(rlib2.R_2_instances_name_rename)
778
        self.assertItems(["inst20967"])
779

    
780
        data = serializer.LoadJson(self.rapi.GetLastRequestData())
781
        self.assertEqual(len(data), 3)
782
        self.assertEqual(data["new_name"], new_name)
783
        self.assertEqual(data["ip_check"], ip_check)
784
        self.assertEqual(data["name_check"], name_check)
785

    
786
  def testGetJobs(self):
787
    self.rapi.AddResponse('[ { "id": "123", "uri": "\\/2\\/jobs\\/123" },'
788
                          '  { "id": "124", "uri": "\\/2\\/jobs\\/124" } ]')
789
    self.assertEqual([123, 124], self.client.GetJobs())
790
    self.assertHandler(rlib2.R_2_jobs)
791

    
792
  def testGetJobStatus(self):
793
    self.rapi.AddResponse("{\"foo\": \"bar\"}")
794
    self.assertEqual({"foo": "bar"}, self.client.GetJobStatus(1234))
795
    self.assertHandler(rlib2.R_2_jobs_id)
796
    self.assertItems(["1234"])
797

    
798
  def testWaitForJobChange(self):
799
    fields = ["id", "summary"]
800
    expected = {
801
      "job_info": [123, "something"],
802
      "log_entries": [],
803
      }
804

    
805
    self.rapi.AddResponse(serializer.DumpJson(expected))
806
    result = self.client.WaitForJobChange(123, fields, [], -1)
807
    self.assertEqualValues(expected, result)
808
    self.assertHandler(rlib2.R_2_jobs_id_wait)
809
    self.assertItems(["123"])
810

    
811
  def testCancelJob(self):
812
    self.rapi.AddResponse("[true, \"Job 123 will be canceled\"]")
813
    self.assertEqual([True, "Job 123 will be canceled"],
814
                     self.client.CancelJob(999, dry_run=True))
815
    self.assertHandler(rlib2.R_2_jobs_id)
816
    self.assertItems(["999"])
817
    self.assertDryRun()
818

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

    
825
    self.rapi.AddResponse("[ { \"id\": \"node1\", \"uri\": \"uri1\" },"
826
                          " { \"id\": \"node2\", \"uri\": \"uri2\" } ]")
827
    self.assertEqual([{"id": "node1", "uri": "uri1"},
828
                      {"id": "node2", "uri": "uri2"}],
829
                     self.client.GetNodes(bulk=True))
830
    self.assertHandler(rlib2.R_2_nodes)
831
    self.assertBulk()
832

    
833
  def testGetNode(self):
834
    self.rapi.AddResponse("{}")
835
    self.assertEqual({}, self.client.GetNode("node-foo"))
836
    self.assertHandler(rlib2.R_2_nodes_name)
837
    self.assertItems(["node-foo"])
838

    
839
  def testEvacuateNode(self):
840
    self.rapi.AddResponse(serializer.DumpJson([rlib2._NODE_EVAC_RES1]))
841
    self.rapi.AddResponse("9876")
842
    job_id = self.client.EvacuateNode("node-1", remote_node="node-2")
843
    self.assertEqual(9876, job_id)
844
    self.assertHandler(rlib2.R_2_nodes_name_evacuate)
845
    self.assertItems(["node-1"])
846
    self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
847
                     { "remote_node": "node-2", })
848
    self.assertEqual(self.rapi.CountPending(), 0)
849

    
850
    self.rapi.AddResponse(serializer.DumpJson([rlib2._NODE_EVAC_RES1]))
851
    self.rapi.AddResponse("8888")
852
    job_id = self.client.EvacuateNode("node-3", iallocator="hail", dry_run=True,
853
                                      mode=constants.NODE_EVAC_ALL,
854
                                      early_release=True)
855
    self.assertEqual(8888, job_id)
856
    self.assertItems(["node-3"])
857
    self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()), {
858
      "iallocator": "hail",
859
      "mode": "all",
860
      "early_release": True,
861
      })
862
    self.assertDryRun()
863

    
864
    self.assertRaises(client.GanetiApiError,
865
                      self.client.EvacuateNode,
866
                      "node-4", iallocator="hail", remote_node="node-5")
867
    self.assertEqual(self.rapi.CountPending(), 0)
868

    
869
  def testEvacuateNodeOldResponse(self):
870
    self.rapi.AddResponse(serializer.DumpJson([]))
871
    self.assertRaises(client.GanetiApiError, self.client.EvacuateNode,
872
                      "node-4", accept_old=False)
873
    self.assertEqual(self.rapi.CountPending(), 0)
874

    
875
    for mode in [client.NODE_EVAC_PRI, client.NODE_EVAC_ALL]:
876
      self.rapi.AddResponse(serializer.DumpJson([]))
877
      self.assertRaises(client.GanetiApiError, self.client.EvacuateNode,
878
                        "node-4", accept_old=True, mode=mode)
879
      self.assertEqual(self.rapi.CountPending(), 0)
880

    
881
    self.rapi.AddResponse(serializer.DumpJson([]))
882
    self.rapi.AddResponse(serializer.DumpJson("21533"))
883
    result = self.client.EvacuateNode("node-3", iallocator="hail",
884
                                      dry_run=True, accept_old=True,
885
                                      mode=client.NODE_EVAC_SEC,
886
                                      early_release=True)
887
    self.assertEqual(result, "21533")
888
    self.assertItems(["node-3"])
889
    self.assertQuery("iallocator", ["hail"])
890
    self.assertQuery("early_release", ["1"])
891
    self.assertFalse(self.rapi.GetLastRequestData())
892
    self.assertDryRun()
893
    self.assertEqual(self.rapi.CountPending(), 0)
894

    
895
  def testMigrateNode(self):
896
    self.rapi.AddResponse(serializer.DumpJson([]))
897
    self.rapi.AddResponse("1111")
898
    self.assertEqual(1111, self.client.MigrateNode("node-a", dry_run=True))
899
    self.assertHandler(rlib2.R_2_nodes_name_migrate)
900
    self.assertItems(["node-a"])
901
    self.assert_("mode" not in self.rapi.GetLastHandler().queryargs)
902
    self.assertDryRun()
903
    self.assertFalse(self.rapi.GetLastRequestData())
904

    
905
    self.rapi.AddResponse(serializer.DumpJson([]))
906
    self.rapi.AddResponse("1112")
907
    self.assertEqual(1112, self.client.MigrateNode("node-a", dry_run=True,
908
                                                   mode="live"))
909
    self.assertHandler(rlib2.R_2_nodes_name_migrate)
910
    self.assertItems(["node-a"])
911
    self.assertQuery("mode", ["live"])
912
    self.assertDryRun()
913
    self.assertFalse(self.rapi.GetLastRequestData())
914

    
915
    self.rapi.AddResponse(serializer.DumpJson([]))
916
    self.assertRaises(client.GanetiApiError, self.client.MigrateNode,
917
                      "node-c", target_node="foonode")
918
    self.assertEqual(self.rapi.CountPending(), 0)
919

    
920
  def testMigrateNodeBodyData(self):
921
    self.rapi.AddResponse(serializer.DumpJson([rlib2._NODE_MIGRATE_REQV1]))
922
    self.rapi.AddResponse("27539")
923
    self.assertEqual(27539, self.client.MigrateNode("node-a", dry_run=False,
924
                                                    mode="live"))
925
    self.assertHandler(rlib2.R_2_nodes_name_migrate)
926
    self.assertItems(["node-a"])
927
    self.assertFalse(self.rapi.GetLastHandler().queryargs)
928
    self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
929
                     { "mode": "live", })
930

    
931
    self.rapi.AddResponse(serializer.DumpJson([rlib2._NODE_MIGRATE_REQV1]))
932
    self.rapi.AddResponse("14219")
933
    self.assertEqual(14219, self.client.MigrateNode("node-x", dry_run=True,
934
                                                    target_node="node9",
935
                                                    iallocator="ial"))
936
    self.assertHandler(rlib2.R_2_nodes_name_migrate)
937
    self.assertItems(["node-x"])
938
    self.assertDryRun()
939
    self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
940
                     { "target_node": "node9", "iallocator": "ial", })
941

    
942
    self.assertEqual(self.rapi.CountPending(), 0)
943

    
944
  def testGetNodeRole(self):
945
    self.rapi.AddResponse("\"master\"")
946
    self.assertEqual("master", self.client.GetNodeRole("node-a"))
947
    self.assertHandler(rlib2.R_2_nodes_name_role)
948
    self.assertItems(["node-a"])
949

    
950
  def testSetNodeRole(self):
951
    self.rapi.AddResponse("789")
952
    self.assertEqual(789,
953
        self.client.SetNodeRole("node-foo", "master-candidate", force=True))
954
    self.assertHandler(rlib2.R_2_nodes_name_role)
955
    self.assertItems(["node-foo"])
956
    self.assertQuery("force", ["1"])
957
    self.assertEqual("\"master-candidate\"", self.rapi.GetLastRequestData())
958

    
959
  def testPowercycleNode(self):
960
    self.rapi.AddResponse("23051")
961
    self.assertEqual(23051,
962
        self.client.PowercycleNode("node5468", force=True))
963
    self.assertHandler(rlib2.R_2_nodes_name_powercycle)
964
    self.assertItems(["node5468"])
965
    self.assertQuery("force", ["1"])
966
    self.assertFalse(self.rapi.GetLastRequestData())
967
    self.assertEqual(self.rapi.CountPending(), 0)
968

    
969
  def testModifyNode(self):
970
    self.rapi.AddResponse("3783")
971
    job_id = self.client.ModifyNode("node16979.example.com", drained=True)
972
    self.assertEqual(job_id, 3783)
973
    self.assertHandler(rlib2.R_2_nodes_name_modify)
974
    self.assertItems(["node16979.example.com"])
975
    self.assertEqual(self.rapi.CountPending(), 0)
976

    
977
  def testGetNodeStorageUnits(self):
978
    self.rapi.AddResponse("42")
979
    self.assertEqual(42,
980
        self.client.GetNodeStorageUnits("node-x", "lvm-pv", "fields"))
981
    self.assertHandler(rlib2.R_2_nodes_name_storage)
982
    self.assertItems(["node-x"])
983
    self.assertQuery("storage_type", ["lvm-pv"])
984
    self.assertQuery("output_fields", ["fields"])
985

    
986
  def testModifyNodeStorageUnits(self):
987
    self.rapi.AddResponse("14")
988
    self.assertEqual(14,
989
        self.client.ModifyNodeStorageUnits("node-z", "lvm-pv", "hda"))
990
    self.assertHandler(rlib2.R_2_nodes_name_storage_modify)
991
    self.assertItems(["node-z"])
992
    self.assertQuery("storage_type", ["lvm-pv"])
993
    self.assertQuery("name", ["hda"])
994
    self.assertQuery("allocatable", None)
995

    
996
    for allocatable, query_allocatable in [(True, "1"), (False, "0")]:
997
      self.rapi.AddResponse("7205")
998
      job_id = self.client.ModifyNodeStorageUnits("node-z", "lvm-pv", "hda",
999
                                                  allocatable=allocatable)
1000
      self.assertEqual(7205, job_id)
1001
      self.assertHandler(rlib2.R_2_nodes_name_storage_modify)
1002
      self.assertItems(["node-z"])
1003
      self.assertQuery("storage_type", ["lvm-pv"])
1004
      self.assertQuery("name", ["hda"])
1005
      self.assertQuery("allocatable", [query_allocatable])
1006

    
1007
  def testRepairNodeStorageUnits(self):
1008
    self.rapi.AddResponse("99")
1009
    self.assertEqual(99, self.client.RepairNodeStorageUnits("node-z", "lvm-pv",
1010
                                                            "hda"))
1011
    self.assertHandler(rlib2.R_2_nodes_name_storage_repair)
1012
    self.assertItems(["node-z"])
1013
    self.assertQuery("storage_type", ["lvm-pv"])
1014
    self.assertQuery("name", ["hda"])
1015

    
1016
  def testGetNodeTags(self):
1017
    self.rapi.AddResponse("[\"fry\", \"bender\"]")
1018
    self.assertEqual(["fry", "bender"], self.client.GetNodeTags("node-k"))
1019
    self.assertHandler(rlib2.R_2_nodes_name_tags)
1020
    self.assertItems(["node-k"])
1021

    
1022
  def testAddNodeTags(self):
1023
    self.rapi.AddResponse("1234")
1024
    self.assertEqual(1234,
1025
        self.client.AddNodeTags("node-v", ["awesome"], dry_run=True))
1026
    self.assertHandler(rlib2.R_2_nodes_name_tags)
1027
    self.assertItems(["node-v"])
1028
    self.assertDryRun()
1029
    self.assertQuery("tag", ["awesome"])
1030

    
1031
  def testDeleteNodeTags(self):
1032
    self.rapi.AddResponse("16861")
1033
    self.assertEqual(16861, self.client.DeleteNodeTags("node-w", ["awesome"],
1034
                                                       dry_run=True))
1035
    self.assertHandler(rlib2.R_2_nodes_name_tags)
1036
    self.assertItems(["node-w"])
1037
    self.assertDryRun()
1038
    self.assertQuery("tag", ["awesome"])
1039

    
1040
  def testGetGroups(self):
1041
    groups = [{"name": "group1",
1042
               "uri": "/2/groups/group1",
1043
               },
1044
              {"name": "group2",
1045
               "uri": "/2/groups/group2",
1046
               },
1047
              ]
1048
    self.rapi.AddResponse(serializer.DumpJson(groups))
1049
    self.assertEqual(["group1", "group2"], self.client.GetGroups())
1050
    self.assertHandler(rlib2.R_2_groups)
1051

    
1052
  def testGetGroupsBulk(self):
1053
    groups = [{"name": "group1",
1054
               "uri": "/2/groups/group1",
1055
               "node_cnt": 2,
1056
               "node_list": ["gnt1.test",
1057
                             "gnt2.test",
1058
                             ],
1059
               },
1060
              {"name": "group2",
1061
               "uri": "/2/groups/group2",
1062
               "node_cnt": 1,
1063
               "node_list": ["gnt3.test",
1064
                             ],
1065
               },
1066
              ]
1067
    self.rapi.AddResponse(serializer.DumpJson(groups))
1068

    
1069
    self.assertEqual(groups, self.client.GetGroups(bulk=True))
1070
    self.assertHandler(rlib2.R_2_groups)
1071
    self.assertBulk()
1072

    
1073
  def testGetGroup(self):
1074
    group = {"ctime": None,
1075
             "name": "default",
1076
             }
1077
    self.rapi.AddResponse(serializer.DumpJson(group))
1078
    self.assertEqual({"ctime": None, "name": "default"},
1079
                     self.client.GetGroup("default"))
1080
    self.assertHandler(rlib2.R_2_groups_name)
1081
    self.assertItems(["default"])
1082

    
1083
  def testCreateGroup(self):
1084
    self.rapi.AddResponse("12345")
1085
    job_id = self.client.CreateGroup("newgroup", dry_run=True)
1086
    self.assertEqual(job_id, 12345)
1087
    self.assertHandler(rlib2.R_2_groups)
1088
    self.assertDryRun()
1089

    
1090
  def testDeleteGroup(self):
1091
    self.rapi.AddResponse("12346")
1092
    job_id = self.client.DeleteGroup("newgroup", dry_run=True)
1093
    self.assertEqual(job_id, 12346)
1094
    self.assertHandler(rlib2.R_2_groups_name)
1095
    self.assertDryRun()
1096

    
1097
  def testRenameGroup(self):
1098
    self.rapi.AddResponse("12347")
1099
    job_id = self.client.RenameGroup("oldname", "newname")
1100
    self.assertEqual(job_id, 12347)
1101
    self.assertHandler(rlib2.R_2_groups_name_rename)
1102

    
1103
  def testModifyGroup(self):
1104
    self.rapi.AddResponse("12348")
1105
    job_id = self.client.ModifyGroup("mygroup", alloc_policy="foo")
1106
    self.assertEqual(job_id, 12348)
1107
    self.assertHandler(rlib2.R_2_groups_name_modify)
1108

    
1109
  def testAssignGroupNodes(self):
1110
    self.rapi.AddResponse("12349")
1111
    job_id = self.client.AssignGroupNodes("mygroup", ["node1", "node2"],
1112
                                          force=True, dry_run=True)
1113
    self.assertEqual(job_id, 12349)
1114
    self.assertHandler(rlib2.R_2_groups_name_assign_nodes)
1115
    self.assertDryRun()
1116
    self.assertUseForce()
1117

    
1118
  def testGetNetworksBulk(self):
1119
    networks = [{"name": "network1",
1120
               "uri": "/2/networks/network1",
1121
               "network": "192.168.0.0/24",
1122
               },
1123
              {"name": "network2",
1124
               "uri": "/2/networks/network2",
1125
               "network": "192.168.0.0/24",
1126
               },
1127
              ]
1128
    self.rapi.AddResponse(serializer.DumpJson(networks))
1129

    
1130
    self.assertEqual(networks, self.client.GetNetworks(bulk=True))
1131
    self.assertHandler(rlib2.R_2_networks)
1132
    self.assertBulk()
1133

    
1134
  def testGetNetwork(self):
1135
    network = {"ctime": None,
1136
               "name": "network1",
1137
               }
1138
    self.rapi.AddResponse(serializer.DumpJson(network))
1139
    self.assertEqual({"ctime": None, "name": "network1"},
1140
                     self.client.GetNetwork("network1"))
1141
    self.assertHandler(rlib2.R_2_networks_name)
1142
    self.assertItems(["network1"])
1143

    
1144
  def testCreateNetwork(self):
1145
    self.rapi.AddResponse("12345")
1146
    job_id = self.client.CreateNetwork("newnetwork", network="192.168.0.0/24",
1147
                                       dry_run=True)
1148
    self.assertEqual(job_id, 12345)
1149
    self.assertHandler(rlib2.R_2_networks)
1150
    self.assertDryRun()
1151

    
1152
  def testModifyNetwork(self):
1153
    self.rapi.AddResponse("12346")
1154
    job_id = self.client.ModifyNetwork("mynetwork", gateway="192.168.0.10",
1155
                                     dry_run=True)
1156
    self.assertEqual(job_id, 12346)
1157
    self.assertHandler(rlib2.R_2_networks_name_modify)
1158

    
1159
  def testDeleteNetwork(self):
1160
    self.rapi.AddResponse("12347")
1161
    job_id = self.client.DeleteNetwork("newnetwork", dry_run=True)
1162
    self.assertEqual(job_id, 12347)
1163
    self.assertHandler(rlib2.R_2_networks_name)
1164
    self.assertDryRun()
1165

    
1166
  def testConnectNetwork(self):
1167
    self.rapi.AddResponse("12348")
1168
    job_id = self.client.ConnectNetwork("mynetwork", "default",
1169
                                        "bridged", "br0", dry_run=True)
1170
    self.assertEqual(job_id, 12348)
1171
    self.assertHandler(rlib2.R_2_networks_name_connect)
1172
    self.assertDryRun()
1173

    
1174
  def testDisconnectNetwork(self):
1175
    self.rapi.AddResponse("12349")
1176
    job_id = self.client.DisconnectNetwork("mynetwork", "default", dry_run=True)
1177
    self.assertEqual(job_id, 12349)
1178
    self.assertHandler(rlib2.R_2_networks_name_disconnect)
1179
    self.assertDryRun()
1180

    
1181
  def testGetNetworkTags(self):
1182
    self.rapi.AddResponse("[]")
1183
    self.assertEqual([], self.client.GetNetworkTags("fooNetwork"))
1184
    self.assertHandler(rlib2.R_2_networks_name_tags)
1185
    self.assertItems(["fooNetwork"])
1186

    
1187
  def testAddNetworkTags(self):
1188
    self.rapi.AddResponse("1234")
1189
    self.assertEqual(1234,
1190
        self.client.AddNetworkTags("fooNetwork", ["awesome"], dry_run=True))
1191
    self.assertHandler(rlib2.R_2_networks_name_tags)
1192
    self.assertItems(["fooNetwork"])
1193
    self.assertDryRun()
1194
    self.assertQuery("tag", ["awesome"])
1195

    
1196
  def testDeleteNetworkTags(self):
1197
    self.rapi.AddResponse("25826")
1198
    self.assertEqual(25826, self.client.DeleteNetworkTags("foo", ["awesome"],
1199
                                                          dry_run=True))
1200
    self.assertHandler(rlib2.R_2_networks_name_tags)
1201
    self.assertItems(["foo"])
1202
    self.assertDryRun()
1203
    self.assertQuery("tag", ["awesome"])
1204

    
1205
  def testModifyInstance(self):
1206
    self.rapi.AddResponse("23681")
1207
    job_id = self.client.ModifyInstance("inst7210", os_name="linux")
1208
    self.assertEqual(job_id, 23681)
1209
    self.assertItems(["inst7210"])
1210
    self.assertHandler(rlib2.R_2_instances_name_modify)
1211
    self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
1212
                     { "os_name": "linux", })
1213

    
1214
  def testModifyCluster(self):
1215
    for mnh in [None, False, True]:
1216
      self.rapi.AddResponse("14470")
1217
      self.assertEqual(14470,
1218
        self.client.ModifyCluster(maintain_node_health=mnh))
1219
      self.assertHandler(rlib2.R_2_cluster_modify)
1220
      self.assertItems([])
1221
      data = serializer.LoadJson(self.rapi.GetLastRequestData())
1222
      self.assertEqual(len(data), 1)
1223
      self.assertEqual(data["maintain_node_health"], mnh)
1224
      self.assertEqual(self.rapi.CountPending(), 0)
1225

    
1226
  def testRedistributeConfig(self):
1227
    self.rapi.AddResponse("3364")
1228
    job_id = self.client.RedistributeConfig()
1229
    self.assertEqual(job_id, 3364)
1230
    self.assertItems([])
1231
    self.assertHandler(rlib2.R_2_redist_config)
1232

    
1233
  def testActivateInstanceDisks(self):
1234
    self.rapi.AddResponse("23547")
1235
    job_id = self.client.ActivateInstanceDisks("inst28204")
1236
    self.assertEqual(job_id, 23547)
1237
    self.assertItems(["inst28204"])
1238
    self.assertHandler(rlib2.R_2_instances_name_activate_disks)
1239
    self.assertFalse(self.rapi.GetLastHandler().queryargs)
1240

    
1241
  def testActivateInstanceDisksIgnoreSize(self):
1242
    self.rapi.AddResponse("11044")
1243
    job_id = self.client.ActivateInstanceDisks("inst28204", ignore_size=True)
1244
    self.assertEqual(job_id, 11044)
1245
    self.assertItems(["inst28204"])
1246
    self.assertHandler(rlib2.R_2_instances_name_activate_disks)
1247
    self.assertQuery("ignore_size", ["1"])
1248

    
1249
  def testDeactivateInstanceDisks(self):
1250
    self.rapi.AddResponse("14591")
1251
    job_id = self.client.DeactivateInstanceDisks("inst28234")
1252
    self.assertEqual(job_id, 14591)
1253
    self.assertItems(["inst28234"])
1254
    self.assertHandler(rlib2.R_2_instances_name_deactivate_disks)
1255
    self.assertFalse(self.rapi.GetLastHandler().queryargs)
1256

    
1257
  def testRecreateInstanceDisks(self):
1258
    self.rapi.AddResponse("13553")
1259
    job_id = self.client.RecreateInstanceDisks("inst23153")
1260
    self.assertEqual(job_id, 13553)
1261
    self.assertItems(["inst23153"])
1262
    self.assertHandler(rlib2.R_2_instances_name_recreate_disks)
1263
    self.assertFalse(self.rapi.GetLastHandler().queryargs)
1264

    
1265
  def testGetInstanceConsole(self):
1266
    self.rapi.AddResponse("26876")
1267
    job_id = self.client.GetInstanceConsole("inst21491")
1268
    self.assertEqual(job_id, 26876)
1269
    self.assertItems(["inst21491"])
1270
    self.assertHandler(rlib2.R_2_instances_name_console)
1271
    self.assertFalse(self.rapi.GetLastHandler().queryargs)
1272
    self.assertFalse(self.rapi.GetLastRequestData())
1273

    
1274
  def testGrowInstanceDisk(self):
1275
    for idx, wait_for_sync in enumerate([None, False, True]):
1276
      amount = 128 + (512 * idx)
1277
      self.assertEqual(self.rapi.CountPending(), 0)
1278
      self.rapi.AddResponse("30783")
1279
      self.assertEqual(30783,
1280
        self.client.GrowInstanceDisk("eze8ch", idx, amount,
1281
                                     wait_for_sync=wait_for_sync))
1282
      self.assertHandler(rlib2.R_2_instances_name_disk_grow)
1283
      self.assertItems(["eze8ch", str(idx)])
1284
      data = serializer.LoadJson(self.rapi.GetLastRequestData())
1285
      if wait_for_sync is None:
1286
        self.assertEqual(len(data), 1)
1287
        self.assert_("wait_for_sync" not in data)
1288
      else:
1289
        self.assertEqual(len(data), 2)
1290
        self.assertEqual(data["wait_for_sync"], wait_for_sync)
1291
      self.assertEqual(data["amount"], amount)
1292
      self.assertEqual(self.rapi.CountPending(), 0)
1293

    
1294
  def testGetGroupTags(self):
1295
    self.rapi.AddResponse("[]")
1296
    self.assertEqual([], self.client.GetGroupTags("fooGroup"))
1297
    self.assertHandler(rlib2.R_2_groups_name_tags)
1298
    self.assertItems(["fooGroup"])
1299

    
1300
  def testAddGroupTags(self):
1301
    self.rapi.AddResponse("1234")
1302
    self.assertEqual(1234,
1303
        self.client.AddGroupTags("fooGroup", ["awesome"], dry_run=True))
1304
    self.assertHandler(rlib2.R_2_groups_name_tags)
1305
    self.assertItems(["fooGroup"])
1306
    self.assertDryRun()
1307
    self.assertQuery("tag", ["awesome"])
1308

    
1309
  def testDeleteGroupTags(self):
1310
    self.rapi.AddResponse("25826")
1311
    self.assertEqual(25826, self.client.DeleteGroupTags("foo", ["awesome"],
1312
                                                        dry_run=True))
1313
    self.assertHandler(rlib2.R_2_groups_name_tags)
1314
    self.assertItems(["foo"])
1315
    self.assertDryRun()
1316
    self.assertQuery("tag", ["awesome"])
1317

    
1318
  def testQuery(self):
1319
    for idx, what in enumerate(constants.QR_VIA_RAPI):
1320
      for idx2, qfilter in enumerate([None, ["?", "name"]]):
1321
        job_id = 11010 + (idx << 4) + (idx2 << 16)
1322
        fields = sorted(query.ALL_FIELDS[what].keys())[:10]
1323

    
1324
        self.rapi.AddResponse(str(job_id))
1325
        self.assertEqual(self.client.Query(what, fields, qfilter=qfilter),
1326
                         job_id)
1327
        self.assertItems([what])
1328
        self.assertHandler(rlib2.R_2_query)
1329
        self.assertFalse(self.rapi.GetLastHandler().queryargs)
1330
        data = serializer.LoadJson(self.rapi.GetLastRequestData())
1331
        self.assertEqual(data["fields"], fields)
1332
        if qfilter is None:
1333
          self.assertTrue("qfilter" not in data)
1334
        else:
1335
          self.assertEqual(data["qfilter"], qfilter)
1336
        self.assertEqual(self.rapi.CountPending(), 0)
1337

    
1338
  def testQueryFields(self):
1339
    exp_result = objects.QueryFieldsResponse(fields=[
1340
      objects.QueryFieldDefinition(name="pnode", title="PNode",
1341
                                   kind=constants.QFT_NUMBER),
1342
      objects.QueryFieldDefinition(name="other", title="Other",
1343
                                   kind=constants.QFT_BOOL),
1344
      ])
1345

    
1346
    for what in constants.QR_VIA_RAPI:
1347
      for fields in [None, ["name", "_unknown_"], ["&", "?|"]]:
1348
        self.rapi.AddResponse(serializer.DumpJson(exp_result.ToDict()))
1349
        result = self.client.QueryFields(what, fields=fields)
1350
        self.assertItems([what])
1351
        self.assertHandler(rlib2.R_2_query_fields)
1352
        self.assertFalse(self.rapi.GetLastRequestData())
1353

    
1354
        queryargs = self.rapi.GetLastHandler().queryargs
1355
        if fields is None:
1356
          self.assertFalse(queryargs)
1357
        else:
1358
          self.assertEqual(queryargs, {
1359
            "fields": [",".join(fields)],
1360
            })
1361

    
1362
        self.assertEqual(objects.QueryFieldsResponse.FromDict(result).ToDict(),
1363
                         exp_result.ToDict())
1364

    
1365
        self.assertEqual(self.rapi.CountPending(), 0)
1366

    
1367
  def testWaitForJobCompletionNoChange(self):
1368
    resp = serializer.DumpJson({
1369
      "status": constants.JOB_STATUS_WAITING,
1370
      })
1371

    
1372
    for retries in [1, 5, 25]:
1373
      for _ in range(retries):
1374
        self.rapi.AddResponse(resp)
1375

    
1376
      self.assertFalse(self.client.WaitForJobCompletion(22789, period=None,
1377
                                                        retries=retries))
1378
      self.assertHandler(rlib2.R_2_jobs_id)
1379
      self.assertItems(["22789"])
1380

    
1381
      self.assertEqual(self.rapi.CountPending(), 0)
1382

    
1383
  def testWaitForJobCompletionAlreadyFinished(self):
1384
    self.rapi.AddResponse(serializer.DumpJson({
1385
      "status": constants.JOB_STATUS_SUCCESS,
1386
      }))
1387

    
1388
    self.assertTrue(self.client.WaitForJobCompletion(22793, period=None,
1389
                                                     retries=1))
1390
    self.assertHandler(rlib2.R_2_jobs_id)
1391
    self.assertItems(["22793"])
1392

    
1393
    self.assertEqual(self.rapi.CountPending(), 0)
1394

    
1395
  def testWaitForJobCompletionEmptyResponse(self):
1396
    self.rapi.AddResponse("{}")
1397
    self.assertFalse(self.client.WaitForJobCompletion(22793, period=None,
1398
                                                     retries=10))
1399
    self.assertHandler(rlib2.R_2_jobs_id)
1400
    self.assertItems(["22793"])
1401

    
1402
    self.assertEqual(self.rapi.CountPending(), 0)
1403

    
1404
  def testWaitForJobCompletionOutOfRetries(self):
1405
    for retries in [3, 10, 21]:
1406
      for _ in range(retries):
1407
        self.rapi.AddResponse(serializer.DumpJson({
1408
          "status": constants.JOB_STATUS_RUNNING,
1409
          }))
1410

    
1411
      self.assertFalse(self.client.WaitForJobCompletion(30948, period=None,
1412
                                                        retries=retries - 1))
1413
      self.assertHandler(rlib2.R_2_jobs_id)
1414
      self.assertItems(["30948"])
1415

    
1416
      self.assertEqual(self.rapi.CountPending(), 1)
1417
      self.rapi.ResetResponses()
1418

    
1419
  def testWaitForJobCompletionSuccessAndFailure(self):
1420
    for retries in [1, 4, 13]:
1421
      for (success, end_status) in [(False, constants.JOB_STATUS_ERROR),
1422
                                    (True, constants.JOB_STATUS_SUCCESS)]:
1423
        for _ in range(retries):
1424
          self.rapi.AddResponse(serializer.DumpJson({
1425
            "status": constants.JOB_STATUS_RUNNING,
1426
            }))
1427

    
1428
        self.rapi.AddResponse(serializer.DumpJson({
1429
          "status": end_status,
1430
          }))
1431

    
1432
        result = self.client.WaitForJobCompletion(3187, period=None,
1433
                                                  retries=retries + 1)
1434
        self.assertEqual(result, success)
1435
        self.assertHandler(rlib2.R_2_jobs_id)
1436
        self.assertItems(["3187"])
1437

    
1438
        self.assertEqual(self.rapi.CountPending(), 0)
1439

    
1440

    
1441
class RapiTestRunner(unittest.TextTestRunner):
1442
  def run(self, *args):
1443
    global _used_handlers
1444
    assert _used_handlers is None
1445

    
1446
    _used_handlers = set()
1447
    try:
1448
      # Run actual tests
1449
      result = unittest.TextTestRunner.run(self, *args)
1450

    
1451
      diff = (set(connector.CONNECTOR.values()) - _used_handlers -
1452
             _KNOWN_UNUSED)
1453
      if diff:
1454
        raise AssertionError("The following RAPI resources were not used by the"
1455
                             " RAPI client: %r" % utils.CommaJoin(diff))
1456
    finally:
1457
      # Reset global variable
1458
      _used_handlers = None
1459

    
1460
    return result
1461

    
1462

    
1463
if __name__ == "__main__":
1464
  client.UsesRapiClient(testutils.GanetiTestProgram)(testRunner=RapiTestRunner)