Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (56.2 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
from ganeti import errors
38

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

    
44
import testutils
45

    
46

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

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

    
56

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

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

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

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

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

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

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

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

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

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

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

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

    
101
    return (code, NotImplemented, response)
102

    
103

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

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

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

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

    
140
  def testErrors(self):
141
    self.assertEqual(client.ECODE_ALL, errors.ECODE_ALL)
142

    
143
    # Make sure all error codes are in both RAPI client and errors module
144
    for name in filter(lambda s: (s.startswith("ECODE_") and s != "ECODE_ALL"),
145
                       dir(client)):
146
      value = getattr(client, name)
147
      self.assertEqual(value, getattr(errors, name))
148
      self.assertTrue(value in client.ECODE_ALL)
149
      self.assertTrue(value in errors.ECODE_ALL)
150

    
151

    
152
class RapiMockTest(unittest.TestCase):
153
  def test404(self):
154
    (code, _, body) = RapiMock().FetchResponse("/foo", "GET", None, None)
155
    self.assertEqual(code, 404)
156
    self.assertTrue(body is None)
157

    
158
  def test501(self):
159
    (code, _, body) = RapiMock().FetchResponse("/version", "POST", None, None)
160
    self.assertEqual(code, 501)
161
    self.assertEqual(body, "Method not implemented")
162

    
163
  def test200(self):
164
    rapi = RapiMock()
165
    rapi.AddResponse("2")
166
    (code, _, response) = rapi.FetchResponse("/version", "GET", None, None)
167
    self.assertEqual(200, code)
168
    self.assertEqual("2", response)
169
    self.failUnless(isinstance(rapi.GetLastHandler(), rlib2.R_version))
170

    
171

    
172
def _FakeNoSslPycurlVersion():
173
  # Note: incomplete version tuple
174
  return (3, "7.16.0", 462848, "mysystem", 1581, None, 0)
175

    
176

    
177
def _FakeFancySslPycurlVersion():
178
  # Note: incomplete version tuple
179
  return (3, "7.16.0", 462848, "mysystem", 1581, "FancySSL/1.2.3", 0)
180

    
181

    
182
def _FakeOpenSslPycurlVersion():
183
  # Note: incomplete version tuple
184
  return (2, "7.15.5", 462597, "othersystem", 668, "OpenSSL/0.9.8c", 0)
185

    
186

    
187
def _FakeGnuTlsPycurlVersion():
188
  # Note: incomplete version tuple
189
  return (3, "7.18.0", 463360, "somesystem", 1581, "GnuTLS/2.0.4", 0)
190

    
191

    
192
class TestExtendedConfig(unittest.TestCase):
193
  def testAuth(self):
194
    cl = client.GanetiRapiClient("master.example.com",
195
      username="user", password="pw",
196
      curl_factory=lambda: rapi.testutils.FakeCurl(RapiMock()))
197

    
198
    curl = cl._CreateCurl()
199
    self.assertEqual(curl.getopt(pycurl.HTTPAUTH), pycurl.HTTPAUTH_BASIC)
200
    self.assertEqual(curl.getopt(pycurl.USERPWD), "user:pw")
201

    
202
  def testInvalidAuth(self):
203
    # No username
204
    self.assertRaises(client.Error, client.GanetiRapiClient,
205
                      "master-a.example.com", password="pw")
206
    # No password
207
    self.assertRaises(client.Error, client.GanetiRapiClient,
208
                      "master-b.example.com", username="user")
209

    
210
  def testCertVerifyInvalidCombinations(self):
211
    self.assertRaises(client.Error, client.GenericCurlConfig,
212
                      use_curl_cabundle=True, cafile="cert1.pem")
213
    self.assertRaises(client.Error, client.GenericCurlConfig,
214
                      use_curl_cabundle=True, capath="certs/")
215
    self.assertRaises(client.Error, client.GenericCurlConfig,
216
                      use_curl_cabundle=True,
217
                      cafile="cert1.pem", capath="certs/")
218

    
219
  def testProxySignalVerifyHostname(self):
220
    for use_gnutls in [False, True]:
221
      if use_gnutls:
222
        pcverfn = _FakeGnuTlsPycurlVersion
223
      else:
224
        pcverfn = _FakeOpenSslPycurlVersion
225

    
226
      for proxy in ["", "http://127.0.0.1:1234"]:
227
        for use_signal in [False, True]:
228
          for verify_hostname in [False, True]:
229
            cfgfn = client.GenericCurlConfig(proxy=proxy, use_signal=use_signal,
230
                                             verify_hostname=verify_hostname,
231
                                             _pycurl_version_fn=pcverfn)
232

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

    
238
            curl = cl._CreateCurl()
239
            self.assertEqual(curl.getopt(pycurl.PROXY), proxy)
240
            self.assertEqual(curl.getopt(pycurl.NOSIGNAL), not use_signal)
241

    
242
            if verify_hostname:
243
              self.assertEqual(curl.getopt(pycurl.SSL_VERIFYHOST), 2)
244
            else:
245
              self.assertEqual(curl.getopt(pycurl.SSL_VERIFYHOST), 0)
246

    
247
  def testNoCertVerify(self):
248
    cfgfn = client.GenericCurlConfig()
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.assertFalse(curl.getopt(pycurl.SSL_VERIFYPEER))
256
    self.assertFalse(curl.getopt(pycurl.CAINFO))
257
    self.assertFalse(curl.getopt(pycurl.CAPATH))
258

    
259
  def testCertVerifyCurlBundle(self):
260
    cfgfn = client.GenericCurlConfig(use_curl_cabundle=True)
261

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

    
266
    curl = cl._CreateCurl()
267
    self.assert_(curl.getopt(pycurl.SSL_VERIFYPEER))
268
    self.assertFalse(curl.getopt(pycurl.CAINFO))
269
    self.assertFalse(curl.getopt(pycurl.CAPATH))
270

    
271
  def testCertVerifyCafile(self):
272
    mycert = "/tmp/some/UNUSED/cert/file.pem"
273
    cfgfn = client.GenericCurlConfig(cafile=mycert)
274

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

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

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

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

    
294
    curl = cl._CreateCurl()
295
    self.assert_(curl.getopt(pycurl.SSL_VERIFYPEER))
296
    self.assertEqual(curl.getopt(pycurl.CAPATH), certdir)
297
    self.assertFalse(curl.getopt(pycurl.CAINFO))
298

    
299
  def testCertVerifyCapathGnuTls(self):
300
    certdir = "/tmp/some/UNUSED/cert/directory"
301
    pcverfn = _FakeGnuTlsPycurlVersion
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 testCertVerifyNoSsl(self):
312
    certdir = "/tmp/some/UNUSED/cert/directory"
313
    pcverfn = _FakeNoSslPycurlVersion
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(client.Error, cl._CreateCurl)
322

    
323
  def testCertVerifyFancySsl(self):
324
    certdir = "/tmp/some/UNUSED/cert/directory"
325
    pcverfn = _FakeFancySslPycurlVersion
326
    cfgfn = client.GenericCurlConfig(capath=certdir,
327
                                     _pycurl_version_fn=pcverfn)
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
    self.assertRaises(NotImplementedError, cl._CreateCurl)
334

    
335
  def testCertVerifyCapath(self):
336
    for connect_timeout in [None, 1, 5, 10, 30, 60, 300]:
337
      for timeout in [None, 1, 30, 60, 3600, 24 * 3600]:
338
        cfgfn = client.GenericCurlConfig(connect_timeout=connect_timeout,
339
                                         timeout=timeout)
340

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

    
345
        curl = cl._CreateCurl()
346
        self.assertEqual(curl.getopt(pycurl.CONNECTTIMEOUT), connect_timeout)
347
        self.assertEqual(curl.getopt(pycurl.TIMEOUT), timeout)
348

    
349

    
350
class GanetiRapiClientTests(testutils.GanetiTestCase):
351
  def setUp(self):
352
    testutils.GanetiTestCase.setUp(self)
353

    
354
    self.rapi = RapiMock()
355
    self.curl = rapi.testutils.FakeCurl(self.rapi)
356
    self.client = client.GanetiRapiClient("master.example.com",
357
                                          curl_factory=lambda: self.curl)
358

    
359
  def assertHandler(self, handler_cls):
360
    self.failUnless(isinstance(self.rapi.GetLastHandler(), handler_cls))
361

    
362
  def assertQuery(self, key, value):
363
    self.assertEqual(value, self.rapi.GetLastHandler().queryargs.get(key, None))
364

    
365
  def assertItems(self, items):
366
    self.assertEqual(items, self.rapi.GetLastHandler().items)
367

    
368
  def assertBulk(self):
369
    self.assertTrue(self.rapi.GetLastHandler().useBulk())
370

    
371
  def assertDryRun(self):
372
    self.assertTrue(self.rapi.GetLastHandler().dryRun())
373

    
374
  def assertUseForce(self):
375
    self.assertTrue(self.rapi.GetLastHandler().useForce())
376

    
377
  def testEncodeQuery(self):
378
    query = [
379
      ("a", None),
380
      ("b", 1),
381
      ("c", 2),
382
      ("d", "Foo"),
383
      ("e", True),
384
      ]
385

    
386
    expected = [
387
      ("a", ""),
388
      ("b", 1),
389
      ("c", 2),
390
      ("d", "Foo"),
391
      ("e", 1),
392
      ]
393

    
394
    self.assertEqualValues(self.client._EncodeQuery(query),
395
                           expected)
396

    
397
    # invalid types
398
    for i in [[1, 2, 3], {"moo": "boo"}, (1, 2, 3)]:
399
      self.assertRaises(ValueError, self.client._EncodeQuery, [("x", i)])
400

    
401
  def testCurlSettings(self):
402
    self.rapi.AddResponse("2")
403
    self.assertEqual(2, self.client.GetVersion())
404
    self.assertHandler(rlib2.R_version)
405

    
406
    # Signals should be disabled by default
407
    self.assert_(self.curl.getopt(pycurl.NOSIGNAL))
408

    
409
    # No auth and no proxy
410
    self.assertFalse(self.curl.getopt(pycurl.USERPWD))
411
    self.assert_(self.curl.getopt(pycurl.PROXY) is None)
412

    
413
    # Content-type is required for requests
414
    headers = self.curl.getopt(pycurl.HTTPHEADER)
415
    self.assert_("Content-type: application/json" in headers)
416

    
417
  def testHttpError(self):
418
    self.rapi.AddResponse(None, code=404)
419
    try:
420
      self.client.GetJobStatus(15140)
421
    except client.GanetiApiError, err:
422
      self.assertEqual(err.code, 404)
423
    else:
424
      self.fail("Didn't raise exception")
425

    
426
  def testGetVersion(self):
427
    self.rapi.AddResponse("2")
428
    self.assertEqual(2, self.client.GetVersion())
429
    self.assertHandler(rlib2.R_version)
430

    
431
  def testGetFeatures(self):
432
    for features in [[], ["foo", "bar", "baz"]]:
433
      self.rapi.AddResponse(serializer.DumpJson(features))
434
      self.assertEqual(features, self.client.GetFeatures())
435
      self.assertHandler(rlib2.R_2_features)
436

    
437
  def testGetFeaturesNotFound(self):
438
    self.rapi.AddResponse(None, code=404)
439
    self.assertEqual([], self.client.GetFeatures())
440

    
441
  def testGetOperatingSystems(self):
442
    self.rapi.AddResponse("[\"beos\"]")
443
    self.assertEqual(["beos"], self.client.GetOperatingSystems())
444
    self.assertHandler(rlib2.R_2_os)
445

    
446
  def testGetClusterTags(self):
447
    self.rapi.AddResponse("[\"tag\"]")
448
    self.assertEqual(["tag"], self.client.GetClusterTags())
449
    self.assertHandler(rlib2.R_2_tags)
450

    
451
  def testAddClusterTags(self):
452
    self.rapi.AddResponse("1234")
453
    self.assertEqual(1234,
454
        self.client.AddClusterTags(["awesome"], dry_run=True))
455
    self.assertHandler(rlib2.R_2_tags)
456
    self.assertDryRun()
457
    self.assertQuery("tag", ["awesome"])
458

    
459
  def testDeleteClusterTags(self):
460
    self.rapi.AddResponse("5107")
461
    self.assertEqual(5107, self.client.DeleteClusterTags(["awesome"],
462
                                                         dry_run=True))
463
    self.assertHandler(rlib2.R_2_tags)
464
    self.assertDryRun()
465
    self.assertQuery("tag", ["awesome"])
466

    
467
  def testGetInfo(self):
468
    self.rapi.AddResponse("{}")
469
    self.assertEqual({}, self.client.GetInfo())
470
    self.assertHandler(rlib2.R_2_info)
471

    
472
  def testGetInstances(self):
473
    self.rapi.AddResponse("[]")
474
    self.assertEqual([], self.client.GetInstances(bulk=True))
475
    self.assertHandler(rlib2.R_2_instances)
476
    self.assertBulk()
477

    
478
  def testGetInstance(self):
479
    self.rapi.AddResponse("[]")
480
    self.assertEqual([], self.client.GetInstance("instance"))
481
    self.assertHandler(rlib2.R_2_instances_name)
482
    self.assertItems(["instance"])
483

    
484
  def testGetInstanceInfo(self):
485
    self.rapi.AddResponse("21291")
486
    self.assertEqual(21291, self.client.GetInstanceInfo("inst3"))
487
    self.assertHandler(rlib2.R_2_instances_name_info)
488
    self.assertItems(["inst3"])
489
    self.assertQuery("static", None)
490

    
491
    self.rapi.AddResponse("3428")
492
    self.assertEqual(3428, self.client.GetInstanceInfo("inst31", static=False))
493
    self.assertHandler(rlib2.R_2_instances_name_info)
494
    self.assertItems(["inst31"])
495
    self.assertQuery("static", ["0"])
496

    
497
    self.rapi.AddResponse("15665")
498
    self.assertEqual(15665, self.client.GetInstanceInfo("inst32", static=True))
499
    self.assertHandler(rlib2.R_2_instances_name_info)
500
    self.assertItems(["inst32"])
501
    self.assertQuery("static", ["1"])
502

    
503
  def testInstancesMultiAlloc(self):
504
    response = {
505
      constants.JOB_IDS_KEY: ["23423"],
506
      opcodes.OpInstanceMultiAlloc.ALLOCATABLE_KEY: ["foobar"],
507
      opcodes.OpInstanceMultiAlloc.FAILED_KEY: ["foobar2"],
508
      }
509
    self.rapi.AddResponse(serializer.DumpJson(response))
510
    insts = [self.client.InstanceAllocation("create", "foobar",
511
                                            "plain", [], []),
512
             self.client.InstanceAllocation("create", "foobar2",
513
                                            "drbd8", [{"size": 100}], [])]
514
    resp = self.client.InstancesMultiAlloc(insts)
515
    self.assertEqual(resp, response)
516
    self.assertHandler(rlib2.R_2_instances_multi_alloc)
517

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

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

    
534
    data = serializer.LoadJson(self.rapi.GetLastRequestData())
535

    
536
    for field in ["dry_run", "beparams", "hvparams", "start"]:
537
      self.assertFalse(field in data)
538

    
539
    self.assertEqual(data["name"], "inst1.example.com")
540
    self.assertEqual(data["disk_template"], "plain")
541

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

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

    
563
  def testDeleteInstance(self):
564
    self.rapi.AddResponse("1234")
565
    self.assertEqual(1234, self.client.DeleteInstance("instance", dry_run=True))
566
    self.assertHandler(rlib2.R_2_instances_name)
567
    self.assertItems(["instance"])
568
    self.assertDryRun()
569

    
570
  def testGetInstanceTags(self):
571
    self.rapi.AddResponse("[]")
572
    self.assertEqual([], self.client.GetInstanceTags("fooinstance"))
573
    self.assertHandler(rlib2.R_2_instances_name_tags)
574
    self.assertItems(["fooinstance"])
575

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

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

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

    
605
  def testRebootInstanceDefaultReason(self):
606
    self.rapi.AddResponse("6146")
607
    job_id = self.client.RebootInstance("i-bar", reboot_type="hard",
608
                                        ignore_secondaries=True, dry_run=True)
609
    self.assertEqual(6146, job_id)
610
    self.assertHandler(rlib2.R_2_instances_name_reboot)
611
    self.assertItems(["i-bar"])
612
    self.assertDryRun()
613
    self.assertQuery("type", ["hard"])
614
    self.assertQuery("ignore_secondaries", ["1"])
615

    
616
  def testShutdownInstance(self):
617
    self.rapi.AddResponse("1487")
618
    self.assertEqual(1487, self.client.ShutdownInstance("foo-instance",
619
                                                        dry_run=True))
620
    self.assertHandler(rlib2.R_2_instances_name_shutdown)
621
    self.assertItems(["foo-instance"])
622
    self.assertDryRun()
623

    
624
  def testStartupInstance(self):
625
    self.rapi.AddResponse("27149")
626
    self.assertEqual(27149, self.client.StartupInstance("bar-instance",
627
                                                        dry_run=True))
628
    self.assertHandler(rlib2.R_2_instances_name_startup)
629
    self.assertItems(["bar-instance"])
630
    self.assertDryRun()
631

    
632
  def testReinstallInstance(self):
633
    self.rapi.AddResponse(serializer.DumpJson([]))
634
    self.rapi.AddResponse("19119")
635
    self.assertEqual(19119, self.client.ReinstallInstance("baz-instance",
636
                                                          os="DOS",
637
                                                          no_startup=True))
638
    self.assertHandler(rlib2.R_2_instances_name_reinstall)
639
    self.assertItems(["baz-instance"])
640
    self.assertQuery("os", ["DOS"])
641
    self.assertQuery("nostartup", ["1"])
642
    self.assertEqual(self.rapi.CountPending(), 0)
643

    
644
  def testReinstallInstanceNew(self):
645
    self.rapi.AddResponse(serializer.DumpJson([rlib2._INST_REINSTALL_REQV1]))
646
    self.rapi.AddResponse("25689")
647
    self.assertEqual(25689, self.client.ReinstallInstance("moo-instance",
648
                                                          os="Debian",
649
                                                          no_startup=True))
650
    self.assertHandler(rlib2.R_2_instances_name_reinstall)
651
    self.assertItems(["moo-instance"])
652
    data = serializer.LoadJson(self.rapi.GetLastRequestData())
653
    self.assertEqual(len(data), 2)
654
    self.assertEqual(data["os"], "Debian")
655
    self.assertEqual(data["start"], False)
656
    self.assertEqual(self.rapi.CountPending(), 0)
657

    
658
  def testReinstallInstanceWithOsparams1(self):
659
    self.rapi.AddResponse(serializer.DumpJson([]))
660
    self.assertRaises(client.GanetiApiError, self.client.ReinstallInstance,
661
                      "doo-instance", osparams={"x": "y"})
662
    self.assertEqual(self.rapi.CountPending(), 0)
663

    
664
  def testReinstallInstanceWithOsparams2(self):
665
    osparams = {
666
      "Hello": "World",
667
      "foo": "bar",
668
      }
669
    self.rapi.AddResponse(serializer.DumpJson([rlib2._INST_REINSTALL_REQV1]))
670
    self.rapi.AddResponse("1717")
671
    self.assertEqual(1717, self.client.ReinstallInstance("zoo-instance",
672
                                                         osparams=osparams))
673
    self.assertHandler(rlib2.R_2_instances_name_reinstall)
674
    self.assertItems(["zoo-instance"])
675
    data = serializer.LoadJson(self.rapi.GetLastRequestData())
676
    self.assertEqual(len(data), 2)
677
    self.assertEqual(data["osparams"], osparams)
678
    self.assertEqual(data["start"], True)
679
    self.assertEqual(self.rapi.CountPending(), 0)
680

    
681
  def testReplaceInstanceDisks(self):
682
    self.rapi.AddResponse("999")
683
    job_id = self.client.ReplaceInstanceDisks("instance-name",
684
        disks=[0, 1], iallocator="hail")
685
    self.assertEqual(999, job_id)
686
    self.assertHandler(rlib2.R_2_instances_name_replace_disks)
687
    self.assertItems(["instance-name"])
688
    self.assertQuery("disks", ["0,1"])
689
    self.assertQuery("mode", ["replace_auto"])
690
    self.assertQuery("iallocator", ["hail"])
691

    
692
    self.rapi.AddResponse("1000")
693
    job_id = self.client.ReplaceInstanceDisks("instance-bar",
694
        disks=[1], mode="replace_on_secondary", remote_node="foo-node")
695
    self.assertEqual(1000, job_id)
696
    self.assertItems(["instance-bar"])
697
    self.assertQuery("disks", ["1"])
698
    self.assertQuery("remote_node", ["foo-node"])
699

    
700
    self.rapi.AddResponse("5175")
701
    self.assertEqual(5175, self.client.ReplaceInstanceDisks("instance-moo"))
702
    self.assertItems(["instance-moo"])
703
    self.assertQuery("disks", None)
704

    
705
  def testPrepareExport(self):
706
    self.rapi.AddResponse("8326")
707
    self.assertEqual(8326, self.client.PrepareExport("inst1", "local"))
708
    self.assertHandler(rlib2.R_2_instances_name_prepare_export)
709
    self.assertItems(["inst1"])
710
    self.assertQuery("mode", ["local"])
711

    
712
  def testExportInstance(self):
713
    self.rapi.AddResponse("19695")
714
    job_id = self.client.ExportInstance("inst2", "local", "nodeX",
715
                                        shutdown=True)
716
    self.assertEqual(job_id, 19695)
717
    self.assertHandler(rlib2.R_2_instances_name_export)
718
    self.assertItems(["inst2"])
719

    
720
    data = serializer.LoadJson(self.rapi.GetLastRequestData())
721
    self.assertEqual(data["mode"], "local")
722
    self.assertEqual(data["destination"], "nodeX")
723
    self.assertEqual(data["shutdown"], True)
724

    
725
  def testMigrateInstanceDefaults(self):
726
    self.rapi.AddResponse("24873")
727
    job_id = self.client.MigrateInstance("inst91")
728
    self.assertEqual(job_id, 24873)
729
    self.assertHandler(rlib2.R_2_instances_name_migrate)
730
    self.assertItems(["inst91"])
731

    
732
    data = serializer.LoadJson(self.rapi.GetLastRequestData())
733
    self.assertFalse(data)
734

    
735
  def testMigrateInstance(self):
736
    for mode in constants.HT_MIGRATION_MODES:
737
      for cleanup in [False, True]:
738
        self.rapi.AddResponse("31910")
739
        job_id = self.client.MigrateInstance("inst289", mode=mode,
740
                                             cleanup=cleanup)
741
        self.assertEqual(job_id, 31910)
742
        self.assertHandler(rlib2.R_2_instances_name_migrate)
743
        self.assertItems(["inst289"])
744

    
745
        data = serializer.LoadJson(self.rapi.GetLastRequestData())
746
        self.assertEqual(len(data), 2)
747
        self.assertEqual(data["mode"], mode)
748
        self.assertEqual(data["cleanup"], cleanup)
749

    
750
  def testFailoverInstanceDefaults(self):
751
    self.rapi.AddResponse("7639")
752
    job_id = self.client.FailoverInstance("inst13579")
753
    self.assertEqual(job_id, 7639)
754
    self.assertHandler(rlib2.R_2_instances_name_failover)
755
    self.assertItems(["inst13579"])
756

    
757
    data = serializer.LoadJson(self.rapi.GetLastRequestData())
758
    self.assertFalse(data)
759

    
760
  def testFailoverInstance(self):
761
    for iallocator in ["dumb", "hail"]:
762
      for ignore_consistency in [False, True]:
763
        for target_node in ["node-a", "node2"]:
764
          self.rapi.AddResponse("19161")
765
          job_id = \
766
            self.client.FailoverInstance("inst251", iallocator=iallocator,
767
                                         ignore_consistency=ignore_consistency,
768
                                         target_node=target_node)
769
          self.assertEqual(job_id, 19161)
770
          self.assertHandler(rlib2.R_2_instances_name_failover)
771
          self.assertItems(["inst251"])
772

    
773
          data = serializer.LoadJson(self.rapi.GetLastRequestData())
774
          self.assertEqual(len(data), 3)
775
          self.assertEqual(data["iallocator"], iallocator)
776
          self.assertEqual(data["ignore_consistency"], ignore_consistency)
777
          self.assertEqual(data["target_node"], target_node)
778
          self.assertEqual(self.rapi.CountPending(), 0)
779

    
780
  def testRenameInstanceDefaults(self):
781
    new_name = "newnametha7euqu"
782
    self.rapi.AddResponse("8791")
783
    job_id = self.client.RenameInstance("inst18821", new_name)
784
    self.assertEqual(job_id, 8791)
785
    self.assertHandler(rlib2.R_2_instances_name_rename)
786
    self.assertItems(["inst18821"])
787

    
788
    data = serializer.LoadJson(self.rapi.GetLastRequestData())
789
    self.assertEqualValues(data, {"new_name": new_name, })
790

    
791
  def testRenameInstance(self):
792
    new_name = "new-name-yiux1iin"
793
    for ip_check in [False, True]:
794
      for name_check in [False, True]:
795
        self.rapi.AddResponse("24776")
796
        job_id = self.client.RenameInstance("inst20967", new_name,
797
                                             ip_check=ip_check,
798
                                             name_check=name_check)
799
        self.assertEqual(job_id, 24776)
800
        self.assertHandler(rlib2.R_2_instances_name_rename)
801
        self.assertItems(["inst20967"])
802

    
803
        data = serializer.LoadJson(self.rapi.GetLastRequestData())
804
        self.assertEqual(len(data), 3)
805
        self.assertEqual(data["new_name"], new_name)
806
        self.assertEqual(data["ip_check"], ip_check)
807
        self.assertEqual(data["name_check"], name_check)
808

    
809
  def testGetJobs(self):
810
    self.rapi.AddResponse('[ { "id": "123", "uri": "\\/2\\/jobs\\/123" },'
811
                          '  { "id": "124", "uri": "\\/2\\/jobs\\/124" } ]')
812
    self.assertEqual([123, 124], self.client.GetJobs())
813
    self.assertHandler(rlib2.R_2_jobs)
814

    
815
  def testGetJobStatus(self):
816
    self.rapi.AddResponse("{\"foo\": \"bar\"}")
817
    self.assertEqual({"foo": "bar"}, self.client.GetJobStatus(1234))
818
    self.assertHandler(rlib2.R_2_jobs_id)
819
    self.assertItems(["1234"])
820

    
821
  def testWaitForJobChange(self):
822
    fields = ["id", "summary"]
823
    expected = {
824
      "job_info": [123, "something"],
825
      "log_entries": [],
826
      }
827

    
828
    self.rapi.AddResponse(serializer.DumpJson(expected))
829
    result = self.client.WaitForJobChange(123, fields, [], -1)
830
    self.assertEqualValues(expected, result)
831
    self.assertHandler(rlib2.R_2_jobs_id_wait)
832
    self.assertItems(["123"])
833

    
834
  def testCancelJob(self):
835
    self.rapi.AddResponse("[true, \"Job 123 will be canceled\"]")
836
    self.assertEqual([True, "Job 123 will be canceled"],
837
                     self.client.CancelJob(999, dry_run=True))
838
    self.assertHandler(rlib2.R_2_jobs_id)
839
    self.assertItems(["999"])
840
    self.assertDryRun()
841

    
842
  def testGetNodes(self):
843
    self.rapi.AddResponse("[ { \"id\": \"node1\", \"uri\": \"uri1\" },"
844
                          " { \"id\": \"node2\", \"uri\": \"uri2\" } ]")
845
    self.assertEqual(["node1", "node2"], self.client.GetNodes())
846
    self.assertHandler(rlib2.R_2_nodes)
847

    
848
    self.rapi.AddResponse("[ { \"id\": \"node1\", \"uri\": \"uri1\" },"
849
                          " { \"id\": \"node2\", \"uri\": \"uri2\" } ]")
850
    self.assertEqual([{"id": "node1", "uri": "uri1"},
851
                      {"id": "node2", "uri": "uri2"}],
852
                     self.client.GetNodes(bulk=True))
853
    self.assertHandler(rlib2.R_2_nodes)
854
    self.assertBulk()
855

    
856
  def testGetNode(self):
857
    self.rapi.AddResponse("{}")
858
    self.assertEqual({}, self.client.GetNode("node-foo"))
859
    self.assertHandler(rlib2.R_2_nodes_name)
860
    self.assertItems(["node-foo"])
861

    
862
  def testEvacuateNode(self):
863
    self.rapi.AddResponse(serializer.DumpJson([rlib2._NODE_EVAC_RES1]))
864
    self.rapi.AddResponse("9876")
865
    job_id = self.client.EvacuateNode("node-1", remote_node="node-2")
866
    self.assertEqual(9876, job_id)
867
    self.assertHandler(rlib2.R_2_nodes_name_evacuate)
868
    self.assertItems(["node-1"])
869
    self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
870
                     { "remote_node": "node-2", })
871
    self.assertEqual(self.rapi.CountPending(), 0)
872

    
873
    self.rapi.AddResponse(serializer.DumpJson([rlib2._NODE_EVAC_RES1]))
874
    self.rapi.AddResponse("8888")
875
    job_id = self.client.EvacuateNode("node-3", iallocator="hail", dry_run=True,
876
                                      mode=constants.NODE_EVAC_ALL,
877
                                      early_release=True)
878
    self.assertEqual(8888, job_id)
879
    self.assertItems(["node-3"])
880
    self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()), {
881
      "iallocator": "hail",
882
      "mode": "all",
883
      "early_release": True,
884
      })
885
    self.assertDryRun()
886

    
887
    self.assertRaises(client.GanetiApiError,
888
                      self.client.EvacuateNode,
889
                      "node-4", iallocator="hail", remote_node="node-5")
890
    self.assertEqual(self.rapi.CountPending(), 0)
891

    
892
  def testEvacuateNodeOldResponse(self):
893
    self.rapi.AddResponse(serializer.DumpJson([]))
894
    self.assertRaises(client.GanetiApiError, self.client.EvacuateNode,
895
                      "node-4", accept_old=False)
896
    self.assertEqual(self.rapi.CountPending(), 0)
897

    
898
    for mode in [client.NODE_EVAC_PRI, client.NODE_EVAC_ALL]:
899
      self.rapi.AddResponse(serializer.DumpJson([]))
900
      self.assertRaises(client.GanetiApiError, self.client.EvacuateNode,
901
                        "node-4", accept_old=True, mode=mode)
902
      self.assertEqual(self.rapi.CountPending(), 0)
903

    
904
    self.rapi.AddResponse(serializer.DumpJson([]))
905
    self.rapi.AddResponse(serializer.DumpJson("21533"))
906
    result = self.client.EvacuateNode("node-3", iallocator="hail",
907
                                      dry_run=True, accept_old=True,
908
                                      mode=client.NODE_EVAC_SEC,
909
                                      early_release=True)
910
    self.assertEqual(result, "21533")
911
    self.assertItems(["node-3"])
912
    self.assertQuery("iallocator", ["hail"])
913
    self.assertQuery("early_release", ["1"])
914
    self.assertFalse(self.rapi.GetLastRequestData())
915
    self.assertDryRun()
916
    self.assertEqual(self.rapi.CountPending(), 0)
917

    
918
  def testMigrateNode(self):
919
    self.rapi.AddResponse(serializer.DumpJson([]))
920
    self.rapi.AddResponse("1111")
921
    self.assertEqual(1111, self.client.MigrateNode("node-a", dry_run=True))
922
    self.assertHandler(rlib2.R_2_nodes_name_migrate)
923
    self.assertItems(["node-a"])
924
    self.assert_("mode" not in self.rapi.GetLastHandler().queryargs)
925
    self.assertDryRun()
926
    self.assertFalse(self.rapi.GetLastRequestData())
927

    
928
    self.rapi.AddResponse(serializer.DumpJson([]))
929
    self.rapi.AddResponse("1112")
930
    self.assertEqual(1112, self.client.MigrateNode("node-a", dry_run=True,
931
                                                   mode="live"))
932
    self.assertHandler(rlib2.R_2_nodes_name_migrate)
933
    self.assertItems(["node-a"])
934
    self.assertQuery("mode", ["live"])
935
    self.assertDryRun()
936
    self.assertFalse(self.rapi.GetLastRequestData())
937

    
938
    self.rapi.AddResponse(serializer.DumpJson([]))
939
    self.assertRaises(client.GanetiApiError, self.client.MigrateNode,
940
                      "node-c", target_node="foonode")
941
    self.assertEqual(self.rapi.CountPending(), 0)
942

    
943
  def testMigrateNodeBodyData(self):
944
    self.rapi.AddResponse(serializer.DumpJson([rlib2._NODE_MIGRATE_REQV1]))
945
    self.rapi.AddResponse("27539")
946
    self.assertEqual(27539, self.client.MigrateNode("node-a", dry_run=False,
947
                                                    mode="live"))
948
    self.assertHandler(rlib2.R_2_nodes_name_migrate)
949
    self.assertItems(["node-a"])
950
    self.assertFalse(self.rapi.GetLastHandler().queryargs)
951
    self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
952
                     { "mode": "live", })
953

    
954
    self.rapi.AddResponse(serializer.DumpJson([rlib2._NODE_MIGRATE_REQV1]))
955
    self.rapi.AddResponse("14219")
956
    self.assertEqual(14219, self.client.MigrateNode("node-x", dry_run=True,
957
                                                    target_node="node9",
958
                                                    iallocator="ial"))
959
    self.assertHandler(rlib2.R_2_nodes_name_migrate)
960
    self.assertItems(["node-x"])
961
    self.assertDryRun()
962
    self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
963
                     { "target_node": "node9", "iallocator": "ial", })
964

    
965
    self.assertEqual(self.rapi.CountPending(), 0)
966

    
967
  def testGetNodeRole(self):
968
    self.rapi.AddResponse("\"master\"")
969
    self.assertEqual("master", self.client.GetNodeRole("node-a"))
970
    self.assertHandler(rlib2.R_2_nodes_name_role)
971
    self.assertItems(["node-a"])
972

    
973
  def testSetNodeRole(self):
974
    self.rapi.AddResponse("789")
975
    self.assertEqual(789,
976
        self.client.SetNodeRole("node-foo", "master-candidate", force=True))
977
    self.assertHandler(rlib2.R_2_nodes_name_role)
978
    self.assertItems(["node-foo"])
979
    self.assertQuery("force", ["1"])
980
    self.assertEqual("\"master-candidate\"", self.rapi.GetLastRequestData())
981

    
982
  def testPowercycleNode(self):
983
    self.rapi.AddResponse("23051")
984
    self.assertEqual(23051,
985
        self.client.PowercycleNode("node5468", force=True))
986
    self.assertHandler(rlib2.R_2_nodes_name_powercycle)
987
    self.assertItems(["node5468"])
988
    self.assertQuery("force", ["1"])
989
    self.assertFalse(self.rapi.GetLastRequestData())
990
    self.assertEqual(self.rapi.CountPending(), 0)
991

    
992
  def testModifyNode(self):
993
    self.rapi.AddResponse("3783")
994
    job_id = self.client.ModifyNode("node16979.example.com", drained=True)
995
    self.assertEqual(job_id, 3783)
996
    self.assertHandler(rlib2.R_2_nodes_name_modify)
997
    self.assertItems(["node16979.example.com"])
998
    self.assertEqual(self.rapi.CountPending(), 0)
999

    
1000
  def testGetNodeStorageUnits(self):
1001
    self.rapi.AddResponse("42")
1002
    self.assertEqual(42,
1003
        self.client.GetNodeStorageUnits("node-x", "lvm-pv", "fields"))
1004
    self.assertHandler(rlib2.R_2_nodes_name_storage)
1005
    self.assertItems(["node-x"])
1006
    self.assertQuery("storage_type", ["lvm-pv"])
1007
    self.assertQuery("output_fields", ["fields"])
1008

    
1009
  def testModifyNodeStorageUnits(self):
1010
    self.rapi.AddResponse("14")
1011
    self.assertEqual(14,
1012
        self.client.ModifyNodeStorageUnits("node-z", "lvm-pv", "hda"))
1013
    self.assertHandler(rlib2.R_2_nodes_name_storage_modify)
1014
    self.assertItems(["node-z"])
1015
    self.assertQuery("storage_type", ["lvm-pv"])
1016
    self.assertQuery("name", ["hda"])
1017
    self.assertQuery("allocatable", None)
1018

    
1019
    for allocatable, query_allocatable in [(True, "1"), (False, "0")]:
1020
      self.rapi.AddResponse("7205")
1021
      job_id = self.client.ModifyNodeStorageUnits("node-z", "lvm-pv", "hda",
1022
                                                  allocatable=allocatable)
1023
      self.assertEqual(7205, job_id)
1024
      self.assertHandler(rlib2.R_2_nodes_name_storage_modify)
1025
      self.assertItems(["node-z"])
1026
      self.assertQuery("storage_type", ["lvm-pv"])
1027
      self.assertQuery("name", ["hda"])
1028
      self.assertQuery("allocatable", [query_allocatable])
1029

    
1030
  def testRepairNodeStorageUnits(self):
1031
    self.rapi.AddResponse("99")
1032
    self.assertEqual(99, self.client.RepairNodeStorageUnits("node-z", "lvm-pv",
1033
                                                            "hda"))
1034
    self.assertHandler(rlib2.R_2_nodes_name_storage_repair)
1035
    self.assertItems(["node-z"])
1036
    self.assertQuery("storage_type", ["lvm-pv"])
1037
    self.assertQuery("name", ["hda"])
1038

    
1039
  def testGetNodeTags(self):
1040
    self.rapi.AddResponse("[\"fry\", \"bender\"]")
1041
    self.assertEqual(["fry", "bender"], self.client.GetNodeTags("node-k"))
1042
    self.assertHandler(rlib2.R_2_nodes_name_tags)
1043
    self.assertItems(["node-k"])
1044

    
1045
  def testAddNodeTags(self):
1046
    self.rapi.AddResponse("1234")
1047
    self.assertEqual(1234,
1048
        self.client.AddNodeTags("node-v", ["awesome"], dry_run=True))
1049
    self.assertHandler(rlib2.R_2_nodes_name_tags)
1050
    self.assertItems(["node-v"])
1051
    self.assertDryRun()
1052
    self.assertQuery("tag", ["awesome"])
1053

    
1054
  def testDeleteNodeTags(self):
1055
    self.rapi.AddResponse("16861")
1056
    self.assertEqual(16861, self.client.DeleteNodeTags("node-w", ["awesome"],
1057
                                                       dry_run=True))
1058
    self.assertHandler(rlib2.R_2_nodes_name_tags)
1059
    self.assertItems(["node-w"])
1060
    self.assertDryRun()
1061
    self.assertQuery("tag", ["awesome"])
1062

    
1063
  def testGetGroups(self):
1064
    groups = [{"name": "group1",
1065
               "uri": "/2/groups/group1",
1066
               },
1067
              {"name": "group2",
1068
               "uri": "/2/groups/group2",
1069
               },
1070
              ]
1071
    self.rapi.AddResponse(serializer.DumpJson(groups))
1072
    self.assertEqual(["group1", "group2"], self.client.GetGroups())
1073
    self.assertHandler(rlib2.R_2_groups)
1074

    
1075
  def testGetGroupsBulk(self):
1076
    groups = [{"name": "group1",
1077
               "uri": "/2/groups/group1",
1078
               "node_cnt": 2,
1079
               "node_list": ["gnt1.test",
1080
                             "gnt2.test",
1081
                             ],
1082
               },
1083
              {"name": "group2",
1084
               "uri": "/2/groups/group2",
1085
               "node_cnt": 1,
1086
               "node_list": ["gnt3.test",
1087
                             ],
1088
               },
1089
              ]
1090
    self.rapi.AddResponse(serializer.DumpJson(groups))
1091

    
1092
    self.assertEqual(groups, self.client.GetGroups(bulk=True))
1093
    self.assertHandler(rlib2.R_2_groups)
1094
    self.assertBulk()
1095

    
1096
  def testGetGroup(self):
1097
    group = {"ctime": None,
1098
             "name": "default",
1099
             }
1100
    self.rapi.AddResponse(serializer.DumpJson(group))
1101
    self.assertEqual({"ctime": None, "name": "default"},
1102
                     self.client.GetGroup("default"))
1103
    self.assertHandler(rlib2.R_2_groups_name)
1104
    self.assertItems(["default"])
1105

    
1106
  def testCreateGroup(self):
1107
    self.rapi.AddResponse("12345")
1108
    job_id = self.client.CreateGroup("newgroup", dry_run=True)
1109
    self.assertEqual(job_id, 12345)
1110
    self.assertHandler(rlib2.R_2_groups)
1111
    self.assertDryRun()
1112

    
1113
  def testDeleteGroup(self):
1114
    self.rapi.AddResponse("12346")
1115
    job_id = self.client.DeleteGroup("newgroup", dry_run=True)
1116
    self.assertEqual(job_id, 12346)
1117
    self.assertHandler(rlib2.R_2_groups_name)
1118
    self.assertDryRun()
1119

    
1120
  def testRenameGroup(self):
1121
    self.rapi.AddResponse("12347")
1122
    job_id = self.client.RenameGroup("oldname", "newname")
1123
    self.assertEqual(job_id, 12347)
1124
    self.assertHandler(rlib2.R_2_groups_name_rename)
1125

    
1126
  def testModifyGroup(self):
1127
    self.rapi.AddResponse("12348")
1128
    job_id = self.client.ModifyGroup("mygroup", alloc_policy="foo")
1129
    self.assertEqual(job_id, 12348)
1130
    self.assertHandler(rlib2.R_2_groups_name_modify)
1131

    
1132
  def testAssignGroupNodes(self):
1133
    self.rapi.AddResponse("12349")
1134
    job_id = self.client.AssignGroupNodes("mygroup", ["node1", "node2"],
1135
                                          force=True, dry_run=True)
1136
    self.assertEqual(job_id, 12349)
1137
    self.assertHandler(rlib2.R_2_groups_name_assign_nodes)
1138
    self.assertDryRun()
1139
    self.assertUseForce()
1140

    
1141
  def testGetNetworksBulk(self):
1142
    networks = [{"name": "network1",
1143
               "uri": "/2/networks/network1",
1144
               "network": "192.168.0.0/24",
1145
               },
1146
              {"name": "network2",
1147
               "uri": "/2/networks/network2",
1148
               "network": "192.168.0.0/24",
1149
               },
1150
              ]
1151
    self.rapi.AddResponse(serializer.DumpJson(networks))
1152

    
1153
    self.assertEqual(networks, self.client.GetNetworks(bulk=True))
1154
    self.assertHandler(rlib2.R_2_networks)
1155
    self.assertBulk()
1156

    
1157
  def testGetNetwork(self):
1158
    network = {"ctime": None,
1159
               "name": "network1",
1160
               }
1161
    self.rapi.AddResponse(serializer.DumpJson(network))
1162
    self.assertEqual({"ctime": None, "name": "network1"},
1163
                     self.client.GetNetwork("network1"))
1164
    self.assertHandler(rlib2.R_2_networks_name)
1165
    self.assertItems(["network1"])
1166

    
1167
  def testCreateNetwork(self):
1168
    self.rapi.AddResponse("12345")
1169
    job_id = self.client.CreateNetwork("newnetwork", network="192.168.0.0/24",
1170
                                       dry_run=True)
1171
    self.assertEqual(job_id, 12345)
1172
    self.assertHandler(rlib2.R_2_networks)
1173
    self.assertDryRun()
1174

    
1175
  def testModifyNetwork(self):
1176
    self.rapi.AddResponse("12346")
1177
    job_id = self.client.ModifyNetwork("mynetwork", gateway="192.168.0.10",
1178
                                     dry_run=True)
1179
    self.assertEqual(job_id, 12346)
1180
    self.assertHandler(rlib2.R_2_networks_name_modify)
1181

    
1182
  def testDeleteNetwork(self):
1183
    self.rapi.AddResponse("12347")
1184
    job_id = self.client.DeleteNetwork("newnetwork", dry_run=True)
1185
    self.assertEqual(job_id, 12347)
1186
    self.assertHandler(rlib2.R_2_networks_name)
1187
    self.assertDryRun()
1188

    
1189
  def testConnectNetwork(self):
1190
    self.rapi.AddResponse("12348")
1191
    job_id = self.client.ConnectNetwork("mynetwork", "default",
1192
                                        "bridged", "br0", dry_run=True)
1193
    self.assertEqual(job_id, 12348)
1194
    self.assertHandler(rlib2.R_2_networks_name_connect)
1195
    self.assertDryRun()
1196

    
1197
  def testDisconnectNetwork(self):
1198
    self.rapi.AddResponse("12349")
1199
    job_id = self.client.DisconnectNetwork("mynetwork", "default", dry_run=True)
1200
    self.assertEqual(job_id, 12349)
1201
    self.assertHandler(rlib2.R_2_networks_name_disconnect)
1202
    self.assertDryRun()
1203

    
1204
  def testGetNetworkTags(self):
1205
    self.rapi.AddResponse("[]")
1206
    self.assertEqual([], self.client.GetNetworkTags("fooNetwork"))
1207
    self.assertHandler(rlib2.R_2_networks_name_tags)
1208
    self.assertItems(["fooNetwork"])
1209

    
1210
  def testAddNetworkTags(self):
1211
    self.rapi.AddResponse("1234")
1212
    self.assertEqual(1234,
1213
        self.client.AddNetworkTags("fooNetwork", ["awesome"], dry_run=True))
1214
    self.assertHandler(rlib2.R_2_networks_name_tags)
1215
    self.assertItems(["fooNetwork"])
1216
    self.assertDryRun()
1217
    self.assertQuery("tag", ["awesome"])
1218

    
1219
  def testDeleteNetworkTags(self):
1220
    self.rapi.AddResponse("25826")
1221
    self.assertEqual(25826, self.client.DeleteNetworkTags("foo", ["awesome"],
1222
                                                          dry_run=True))
1223
    self.assertHandler(rlib2.R_2_networks_name_tags)
1224
    self.assertItems(["foo"])
1225
    self.assertDryRun()
1226
    self.assertQuery("tag", ["awesome"])
1227

    
1228
  def testModifyInstance(self):
1229
    self.rapi.AddResponse("23681")
1230
    job_id = self.client.ModifyInstance("inst7210", os_name="linux")
1231
    self.assertEqual(job_id, 23681)
1232
    self.assertItems(["inst7210"])
1233
    self.assertHandler(rlib2.R_2_instances_name_modify)
1234
    self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
1235
                     { "os_name": "linux", })
1236

    
1237
  def testModifyCluster(self):
1238
    for mnh in [None, False, True]:
1239
      self.rapi.AddResponse("14470")
1240
      self.assertEqual(14470,
1241
        self.client.ModifyCluster(maintain_node_health=mnh))
1242
      self.assertHandler(rlib2.R_2_cluster_modify)
1243
      self.assertItems([])
1244
      data = serializer.LoadJson(self.rapi.GetLastRequestData())
1245
      self.assertEqual(len(data), 1)
1246
      self.assertEqual(data["maintain_node_health"], mnh)
1247
      self.assertEqual(self.rapi.CountPending(), 0)
1248

    
1249
  def testRedistributeConfig(self):
1250
    self.rapi.AddResponse("3364")
1251
    job_id = self.client.RedistributeConfig()
1252
    self.assertEqual(job_id, 3364)
1253
    self.assertItems([])
1254
    self.assertHandler(rlib2.R_2_redist_config)
1255

    
1256
  def testActivateInstanceDisks(self):
1257
    self.rapi.AddResponse("23547")
1258
    job_id = self.client.ActivateInstanceDisks("inst28204")
1259
    self.assertEqual(job_id, 23547)
1260
    self.assertItems(["inst28204"])
1261
    self.assertHandler(rlib2.R_2_instances_name_activate_disks)
1262
    self.assertFalse(self.rapi.GetLastHandler().queryargs)
1263

    
1264
  def testActivateInstanceDisksIgnoreSize(self):
1265
    self.rapi.AddResponse("11044")
1266
    job_id = self.client.ActivateInstanceDisks("inst28204", ignore_size=True)
1267
    self.assertEqual(job_id, 11044)
1268
    self.assertItems(["inst28204"])
1269
    self.assertHandler(rlib2.R_2_instances_name_activate_disks)
1270
    self.assertQuery("ignore_size", ["1"])
1271

    
1272
  def testDeactivateInstanceDisks(self):
1273
    self.rapi.AddResponse("14591")
1274
    job_id = self.client.DeactivateInstanceDisks("inst28234")
1275
    self.assertEqual(job_id, 14591)
1276
    self.assertItems(["inst28234"])
1277
    self.assertHandler(rlib2.R_2_instances_name_deactivate_disks)
1278
    self.assertFalse(self.rapi.GetLastHandler().queryargs)
1279

    
1280
  def testRecreateInstanceDisks(self):
1281
    self.rapi.AddResponse("13553")
1282
    job_id = self.client.RecreateInstanceDisks("inst23153")
1283
    self.assertEqual(job_id, 13553)
1284
    self.assertItems(["inst23153"])
1285
    self.assertHandler(rlib2.R_2_instances_name_recreate_disks)
1286
    self.assertFalse(self.rapi.GetLastHandler().queryargs)
1287

    
1288
  def testGetInstanceConsole(self):
1289
    self.rapi.AddResponse("26876")
1290
    job_id = self.client.GetInstanceConsole("inst21491")
1291
    self.assertEqual(job_id, 26876)
1292
    self.assertItems(["inst21491"])
1293
    self.assertHandler(rlib2.R_2_instances_name_console)
1294
    self.assertFalse(self.rapi.GetLastHandler().queryargs)
1295
    self.assertFalse(self.rapi.GetLastRequestData())
1296

    
1297
  def testGrowInstanceDisk(self):
1298
    for idx, wait_for_sync in enumerate([None, False, True]):
1299
      amount = 128 + (512 * idx)
1300
      self.assertEqual(self.rapi.CountPending(), 0)
1301
      self.rapi.AddResponse("30783")
1302
      self.assertEqual(30783,
1303
        self.client.GrowInstanceDisk("eze8ch", idx, amount,
1304
                                     wait_for_sync=wait_for_sync))
1305
      self.assertHandler(rlib2.R_2_instances_name_disk_grow)
1306
      self.assertItems(["eze8ch", str(idx)])
1307
      data = serializer.LoadJson(self.rapi.GetLastRequestData())
1308
      if wait_for_sync is None:
1309
        self.assertEqual(len(data), 1)
1310
        self.assert_("wait_for_sync" not in data)
1311
      else:
1312
        self.assertEqual(len(data), 2)
1313
        self.assertEqual(data["wait_for_sync"], wait_for_sync)
1314
      self.assertEqual(data["amount"], amount)
1315
      self.assertEqual(self.rapi.CountPending(), 0)
1316

    
1317
  def testGetGroupTags(self):
1318
    self.rapi.AddResponse("[]")
1319
    self.assertEqual([], self.client.GetGroupTags("fooGroup"))
1320
    self.assertHandler(rlib2.R_2_groups_name_tags)
1321
    self.assertItems(["fooGroup"])
1322

    
1323
  def testAddGroupTags(self):
1324
    self.rapi.AddResponse("1234")
1325
    self.assertEqual(1234,
1326
        self.client.AddGroupTags("fooGroup", ["awesome"], dry_run=True))
1327
    self.assertHandler(rlib2.R_2_groups_name_tags)
1328
    self.assertItems(["fooGroup"])
1329
    self.assertDryRun()
1330
    self.assertQuery("tag", ["awesome"])
1331

    
1332
  def testDeleteGroupTags(self):
1333
    self.rapi.AddResponse("25826")
1334
    self.assertEqual(25826, self.client.DeleteGroupTags("foo", ["awesome"],
1335
                                                        dry_run=True))
1336
    self.assertHandler(rlib2.R_2_groups_name_tags)
1337
    self.assertItems(["foo"])
1338
    self.assertDryRun()
1339
    self.assertQuery("tag", ["awesome"])
1340

    
1341
  def testQuery(self):
1342
    for idx, what in enumerate(constants.QR_VIA_RAPI):
1343
      for idx2, qfilter in enumerate([None, ["?", "name"]]):
1344
        job_id = 11010 + (idx << 4) + (idx2 << 16)
1345
        fields = sorted(query.ALL_FIELDS[what].keys())[:10]
1346

    
1347
        self.rapi.AddResponse(str(job_id))
1348
        self.assertEqual(self.client.Query(what, fields, qfilter=qfilter),
1349
                         job_id)
1350
        self.assertItems([what])
1351
        self.assertHandler(rlib2.R_2_query)
1352
        self.assertFalse(self.rapi.GetLastHandler().queryargs)
1353
        data = serializer.LoadJson(self.rapi.GetLastRequestData())
1354
        self.assertEqual(data["fields"], fields)
1355
        if qfilter is None:
1356
          self.assertTrue("qfilter" not in data)
1357
        else:
1358
          self.assertEqual(data["qfilter"], qfilter)
1359
        self.assertEqual(self.rapi.CountPending(), 0)
1360

    
1361
  def testQueryFields(self):
1362
    exp_result = objects.QueryFieldsResponse(fields=[
1363
      objects.QueryFieldDefinition(name="pnode", title="PNode",
1364
                                   kind=constants.QFT_NUMBER),
1365
      objects.QueryFieldDefinition(name="other", title="Other",
1366
                                   kind=constants.QFT_BOOL),
1367
      ])
1368

    
1369
    for what in constants.QR_VIA_RAPI:
1370
      for fields in [None, ["name", "_unknown_"], ["&", "?|"]]:
1371
        self.rapi.AddResponse(serializer.DumpJson(exp_result.ToDict()))
1372
        result = self.client.QueryFields(what, fields=fields)
1373
        self.assertItems([what])
1374
        self.assertHandler(rlib2.R_2_query_fields)
1375
        self.assertFalse(self.rapi.GetLastRequestData())
1376

    
1377
        queryargs = self.rapi.GetLastHandler().queryargs
1378
        if fields is None:
1379
          self.assertFalse(queryargs)
1380
        else:
1381
          self.assertEqual(queryargs, {
1382
            "fields": [",".join(fields)],
1383
            })
1384

    
1385
        self.assertEqual(objects.QueryFieldsResponse.FromDict(result).ToDict(),
1386
                         exp_result.ToDict())
1387

    
1388
        self.assertEqual(self.rapi.CountPending(), 0)
1389

    
1390
  def testWaitForJobCompletionNoChange(self):
1391
    resp = serializer.DumpJson({
1392
      "status": constants.JOB_STATUS_WAITING,
1393
      })
1394

    
1395
    for retries in [1, 5, 25]:
1396
      for _ in range(retries):
1397
        self.rapi.AddResponse(resp)
1398

    
1399
      self.assertFalse(self.client.WaitForJobCompletion(22789, period=None,
1400
                                                        retries=retries))
1401
      self.assertHandler(rlib2.R_2_jobs_id)
1402
      self.assertItems(["22789"])
1403

    
1404
      self.assertEqual(self.rapi.CountPending(), 0)
1405

    
1406
  def testWaitForJobCompletionAlreadyFinished(self):
1407
    self.rapi.AddResponse(serializer.DumpJson({
1408
      "status": constants.JOB_STATUS_SUCCESS,
1409
      }))
1410

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

    
1416
    self.assertEqual(self.rapi.CountPending(), 0)
1417

    
1418
  def testWaitForJobCompletionEmptyResponse(self):
1419
    self.rapi.AddResponse("{}")
1420
    self.assertFalse(self.client.WaitForJobCompletion(22793, period=None,
1421
                                                     retries=10))
1422
    self.assertHandler(rlib2.R_2_jobs_id)
1423
    self.assertItems(["22793"])
1424

    
1425
    self.assertEqual(self.rapi.CountPending(), 0)
1426

    
1427
  def testWaitForJobCompletionOutOfRetries(self):
1428
    for retries in [3, 10, 21]:
1429
      for _ in range(retries):
1430
        self.rapi.AddResponse(serializer.DumpJson({
1431
          "status": constants.JOB_STATUS_RUNNING,
1432
          }))
1433

    
1434
      self.assertFalse(self.client.WaitForJobCompletion(30948, period=None,
1435
                                                        retries=retries - 1))
1436
      self.assertHandler(rlib2.R_2_jobs_id)
1437
      self.assertItems(["30948"])
1438

    
1439
      self.assertEqual(self.rapi.CountPending(), 1)
1440
      self.rapi.ResetResponses()
1441

    
1442
  def testWaitForJobCompletionSuccessAndFailure(self):
1443
    for retries in [1, 4, 13]:
1444
      for (success, end_status) in [(False, constants.JOB_STATUS_ERROR),
1445
                                    (True, constants.JOB_STATUS_SUCCESS)]:
1446
        for _ in range(retries):
1447
          self.rapi.AddResponse(serializer.DumpJson({
1448
            "status": constants.JOB_STATUS_RUNNING,
1449
            }))
1450

    
1451
        self.rapi.AddResponse(serializer.DumpJson({
1452
          "status": end_status,
1453
          }))
1454

    
1455
        result = self.client.WaitForJobCompletion(3187, period=None,
1456
                                                  retries=retries + 1)
1457
        self.assertEqual(result, success)
1458
        self.assertHandler(rlib2.R_2_jobs_id)
1459
        self.assertItems(["3187"])
1460

    
1461
        self.assertEqual(self.rapi.CountPending(), 0)
1462

    
1463

    
1464
class RapiTestRunner(unittest.TextTestRunner):
1465
  def run(self, *args):
1466
    global _used_handlers
1467
    assert _used_handlers is None
1468

    
1469
    _used_handlers = set()
1470
    try:
1471
      # Run actual tests
1472
      result = unittest.TextTestRunner.run(self, *args)
1473

    
1474
      diff = (set(connector.CONNECTOR.values()) - _used_handlers -
1475
             _KNOWN_UNUSED)
1476
      if diff:
1477
        raise AssertionError("The following RAPI resources were not used by the"
1478
                             " RAPI client: %r" % utils.CommaJoin(diff))
1479
    finally:
1480
      # Reset global variable
1481
      _used_handlers = None
1482

    
1483
    return result
1484

    
1485

    
1486
if __name__ == "__main__":
1487
  client.UsesRapiClient(testutils.GanetiTestProgram)(testRunner=RapiTestRunner)