Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (56.9 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
                                        reason="Updates")
599
    self.assertEqual(6146, job_id)
600
    self.assertHandler(rlib2.R_2_instances_name_reboot)
601
    self.assertItems(["i-bar"])
602
    self.assertDryRun()
603
    self.assertQuery("type", ["hard"])
604
    self.assertQuery("ignore_secondaries", ["1"])
605
    self.assertQuery("reason", ["Updates"])
606

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

    
619
  def testShutdownInstance(self):
620
    self.rapi.AddResponse("1487")
621
    self.assertEqual(1487, self.client.ShutdownInstance("foo-instance",
622
                                                        dry_run=True,
623
                                                        reason="NoMore"))
624
    self.assertHandler(rlib2.R_2_instances_name_shutdown)
625
    self.assertItems(["foo-instance"])
626
    self.assertDryRun()
627
    self.assertQuery("reason", ["NoMore"])
628

    
629
  def testShutdownInstanceDefaultReason(self):
630
    self.rapi.AddResponse("1487")
631
    self.assertEqual(1487, self.client.ShutdownInstance("foo-instance",
632
                                                        dry_run=True))
633
    self.assertHandler(rlib2.R_2_instances_name_shutdown)
634
    self.assertItems(["foo-instance"])
635
    self.assertDryRun()
636
    self.assertQuery("reason", None)
637

    
638
  def testStartupInstance(self):
639
    self.rapi.AddResponse("27149")
640
    self.assertEqual(27149, self.client.StartupInstance("bar-instance",
641
                                                        dry_run=True))
642
    self.assertHandler(rlib2.R_2_instances_name_startup)
643
    self.assertItems(["bar-instance"])
644
    self.assertDryRun()
645

    
646
  def testReinstallInstance(self):
647
    self.rapi.AddResponse(serializer.DumpJson([]))
648
    self.rapi.AddResponse("19119")
649
    self.assertEqual(19119, self.client.ReinstallInstance("baz-instance",
650
                                                          os="DOS",
651
                                                          no_startup=True))
652
    self.assertHandler(rlib2.R_2_instances_name_reinstall)
653
    self.assertItems(["baz-instance"])
654
    self.assertQuery("os", ["DOS"])
655
    self.assertQuery("nostartup", ["1"])
656
    self.assertEqual(self.rapi.CountPending(), 0)
657

    
658
  def testReinstallInstanceNew(self):
659
    self.rapi.AddResponse(serializer.DumpJson([rlib2._INST_REINSTALL_REQV1]))
660
    self.rapi.AddResponse("25689")
661
    self.assertEqual(25689, self.client.ReinstallInstance("moo-instance",
662
                                                          os="Debian",
663
                                                          no_startup=True))
664
    self.assertHandler(rlib2.R_2_instances_name_reinstall)
665
    self.assertItems(["moo-instance"])
666
    data = serializer.LoadJson(self.rapi.GetLastRequestData())
667
    self.assertEqual(len(data), 2)
668
    self.assertEqual(data["os"], "Debian")
669
    self.assertEqual(data["start"], False)
670
    self.assertEqual(self.rapi.CountPending(), 0)
671

    
672
  def testReinstallInstanceWithOsparams1(self):
673
    self.rapi.AddResponse(serializer.DumpJson([]))
674
    self.assertRaises(client.GanetiApiError, self.client.ReinstallInstance,
675
                      "doo-instance", osparams={"x": "y"})
676
    self.assertEqual(self.rapi.CountPending(), 0)
677

    
678
  def testReinstallInstanceWithOsparams2(self):
679
    osparams = {
680
      "Hello": "World",
681
      "foo": "bar",
682
      }
683
    self.rapi.AddResponse(serializer.DumpJson([rlib2._INST_REINSTALL_REQV1]))
684
    self.rapi.AddResponse("1717")
685
    self.assertEqual(1717, self.client.ReinstallInstance("zoo-instance",
686
                                                         osparams=osparams))
687
    self.assertHandler(rlib2.R_2_instances_name_reinstall)
688
    self.assertItems(["zoo-instance"])
689
    data = serializer.LoadJson(self.rapi.GetLastRequestData())
690
    self.assertEqual(len(data), 2)
691
    self.assertEqual(data["osparams"], osparams)
692
    self.assertEqual(data["start"], True)
693
    self.assertEqual(self.rapi.CountPending(), 0)
694

    
695
  def testReplaceInstanceDisks(self):
696
    self.rapi.AddResponse("999")
697
    job_id = self.client.ReplaceInstanceDisks("instance-name",
698
        disks=[0, 1], iallocator="hail")
699
    self.assertEqual(999, job_id)
700
    self.assertHandler(rlib2.R_2_instances_name_replace_disks)
701
    self.assertItems(["instance-name"])
702
    self.assertQuery("disks", ["0,1"])
703
    self.assertQuery("mode", ["replace_auto"])
704
    self.assertQuery("iallocator", ["hail"])
705

    
706
    self.rapi.AddResponse("1000")
707
    job_id = self.client.ReplaceInstanceDisks("instance-bar",
708
        disks=[1], mode="replace_on_secondary", remote_node="foo-node")
709
    self.assertEqual(1000, job_id)
710
    self.assertItems(["instance-bar"])
711
    self.assertQuery("disks", ["1"])
712
    self.assertQuery("remote_node", ["foo-node"])
713

    
714
    self.rapi.AddResponse("5175")
715
    self.assertEqual(5175, self.client.ReplaceInstanceDisks("instance-moo"))
716
    self.assertItems(["instance-moo"])
717
    self.assertQuery("disks", None)
718

    
719
  def testPrepareExport(self):
720
    self.rapi.AddResponse("8326")
721
    self.assertEqual(8326, self.client.PrepareExport("inst1", "local"))
722
    self.assertHandler(rlib2.R_2_instances_name_prepare_export)
723
    self.assertItems(["inst1"])
724
    self.assertQuery("mode", ["local"])
725

    
726
  def testExportInstance(self):
727
    self.rapi.AddResponse("19695")
728
    job_id = self.client.ExportInstance("inst2", "local", "nodeX",
729
                                        shutdown=True)
730
    self.assertEqual(job_id, 19695)
731
    self.assertHandler(rlib2.R_2_instances_name_export)
732
    self.assertItems(["inst2"])
733

    
734
    data = serializer.LoadJson(self.rapi.GetLastRequestData())
735
    self.assertEqual(data["mode"], "local")
736
    self.assertEqual(data["destination"], "nodeX")
737
    self.assertEqual(data["shutdown"], True)
738

    
739
  def testMigrateInstanceDefaults(self):
740
    self.rapi.AddResponse("24873")
741
    job_id = self.client.MigrateInstance("inst91")
742
    self.assertEqual(job_id, 24873)
743
    self.assertHandler(rlib2.R_2_instances_name_migrate)
744
    self.assertItems(["inst91"])
745

    
746
    data = serializer.LoadJson(self.rapi.GetLastRequestData())
747
    self.assertFalse(data)
748

    
749
  def testMigrateInstance(self):
750
    for mode in constants.HT_MIGRATION_MODES:
751
      for cleanup in [False, True]:
752
        self.rapi.AddResponse("31910")
753
        job_id = self.client.MigrateInstance("inst289", mode=mode,
754
                                             cleanup=cleanup)
755
        self.assertEqual(job_id, 31910)
756
        self.assertHandler(rlib2.R_2_instances_name_migrate)
757
        self.assertItems(["inst289"])
758

    
759
        data = serializer.LoadJson(self.rapi.GetLastRequestData())
760
        self.assertEqual(len(data), 2)
761
        self.assertEqual(data["mode"], mode)
762
        self.assertEqual(data["cleanup"], cleanup)
763

    
764
  def testFailoverInstanceDefaults(self):
765
    self.rapi.AddResponse("7639")
766
    job_id = self.client.FailoverInstance("inst13579")
767
    self.assertEqual(job_id, 7639)
768
    self.assertHandler(rlib2.R_2_instances_name_failover)
769
    self.assertItems(["inst13579"])
770

    
771
    data = serializer.LoadJson(self.rapi.GetLastRequestData())
772
    self.assertFalse(data)
773

    
774
  def testFailoverInstance(self):
775
    for iallocator in ["dumb", "hail"]:
776
      for ignore_consistency in [False, True]:
777
        for target_node in ["node-a", "node2"]:
778
          self.rapi.AddResponse("19161")
779
          job_id = \
780
            self.client.FailoverInstance("inst251", iallocator=iallocator,
781
                                         ignore_consistency=ignore_consistency,
782
                                         target_node=target_node)
783
          self.assertEqual(job_id, 19161)
784
          self.assertHandler(rlib2.R_2_instances_name_failover)
785
          self.assertItems(["inst251"])
786

    
787
          data = serializer.LoadJson(self.rapi.GetLastRequestData())
788
          self.assertEqual(len(data), 3)
789
          self.assertEqual(data["iallocator"], iallocator)
790
          self.assertEqual(data["ignore_consistency"], ignore_consistency)
791
          self.assertEqual(data["target_node"], target_node)
792
          self.assertEqual(self.rapi.CountPending(), 0)
793

    
794
  def testRenameInstanceDefaults(self):
795
    new_name = "newnametha7euqu"
796
    self.rapi.AddResponse("8791")
797
    job_id = self.client.RenameInstance("inst18821", new_name)
798
    self.assertEqual(job_id, 8791)
799
    self.assertHandler(rlib2.R_2_instances_name_rename)
800
    self.assertItems(["inst18821"])
801

    
802
    data = serializer.LoadJson(self.rapi.GetLastRequestData())
803
    self.assertEqualValues(data, {"new_name": new_name, })
804

    
805
  def testRenameInstance(self):
806
    new_name = "new-name-yiux1iin"
807
    for ip_check in [False, True]:
808
      for name_check in [False, True]:
809
        self.rapi.AddResponse("24776")
810
        job_id = self.client.RenameInstance("inst20967", new_name,
811
                                             ip_check=ip_check,
812
                                             name_check=name_check)
813
        self.assertEqual(job_id, 24776)
814
        self.assertHandler(rlib2.R_2_instances_name_rename)
815
        self.assertItems(["inst20967"])
816

    
817
        data = serializer.LoadJson(self.rapi.GetLastRequestData())
818
        self.assertEqual(len(data), 3)
819
        self.assertEqual(data["new_name"], new_name)
820
        self.assertEqual(data["ip_check"], ip_check)
821
        self.assertEqual(data["name_check"], name_check)
822

    
823
  def testGetJobs(self):
824
    self.rapi.AddResponse('[ { "id": "123", "uri": "\\/2\\/jobs\\/123" },'
825
                          '  { "id": "124", "uri": "\\/2\\/jobs\\/124" } ]')
826
    self.assertEqual([123, 124], self.client.GetJobs())
827
    self.assertHandler(rlib2.R_2_jobs)
828

    
829
  def testGetJobStatus(self):
830
    self.rapi.AddResponse("{\"foo\": \"bar\"}")
831
    self.assertEqual({"foo": "bar"}, self.client.GetJobStatus(1234))
832
    self.assertHandler(rlib2.R_2_jobs_id)
833
    self.assertItems(["1234"])
834

    
835
  def testWaitForJobChange(self):
836
    fields = ["id", "summary"]
837
    expected = {
838
      "job_info": [123, "something"],
839
      "log_entries": [],
840
      }
841

    
842
    self.rapi.AddResponse(serializer.DumpJson(expected))
843
    result = self.client.WaitForJobChange(123, fields, [], -1)
844
    self.assertEqualValues(expected, result)
845
    self.assertHandler(rlib2.R_2_jobs_id_wait)
846
    self.assertItems(["123"])
847

    
848
  def testCancelJob(self):
849
    self.rapi.AddResponse("[true, \"Job 123 will be canceled\"]")
850
    self.assertEqual([True, "Job 123 will be canceled"],
851
                     self.client.CancelJob(999, dry_run=True))
852
    self.assertHandler(rlib2.R_2_jobs_id)
853
    self.assertItems(["999"])
854
    self.assertDryRun()
855

    
856
  def testGetNodes(self):
857
    self.rapi.AddResponse("[ { \"id\": \"node1\", \"uri\": \"uri1\" },"
858
                          " { \"id\": \"node2\", \"uri\": \"uri2\" } ]")
859
    self.assertEqual(["node1", "node2"], self.client.GetNodes())
860
    self.assertHandler(rlib2.R_2_nodes)
861

    
862
    self.rapi.AddResponse("[ { \"id\": \"node1\", \"uri\": \"uri1\" },"
863
                          " { \"id\": \"node2\", \"uri\": \"uri2\" } ]")
864
    self.assertEqual([{"id": "node1", "uri": "uri1"},
865
                      {"id": "node2", "uri": "uri2"}],
866
                     self.client.GetNodes(bulk=True))
867
    self.assertHandler(rlib2.R_2_nodes)
868
    self.assertBulk()
869

    
870
  def testGetNode(self):
871
    self.rapi.AddResponse("{}")
872
    self.assertEqual({}, self.client.GetNode("node-foo"))
873
    self.assertHandler(rlib2.R_2_nodes_name)
874
    self.assertItems(["node-foo"])
875

    
876
  def testEvacuateNode(self):
877
    self.rapi.AddResponse(serializer.DumpJson([rlib2._NODE_EVAC_RES1]))
878
    self.rapi.AddResponse("9876")
879
    job_id = self.client.EvacuateNode("node-1", remote_node="node-2")
880
    self.assertEqual(9876, job_id)
881
    self.assertHandler(rlib2.R_2_nodes_name_evacuate)
882
    self.assertItems(["node-1"])
883
    self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
884
                     { "remote_node": "node-2", })
885
    self.assertEqual(self.rapi.CountPending(), 0)
886

    
887
    self.rapi.AddResponse(serializer.DumpJson([rlib2._NODE_EVAC_RES1]))
888
    self.rapi.AddResponse("8888")
889
    job_id = self.client.EvacuateNode("node-3", iallocator="hail", dry_run=True,
890
                                      mode=constants.NODE_EVAC_ALL,
891
                                      early_release=True)
892
    self.assertEqual(8888, job_id)
893
    self.assertItems(["node-3"])
894
    self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()), {
895
      "iallocator": "hail",
896
      "mode": "all",
897
      "early_release": True,
898
      })
899
    self.assertDryRun()
900

    
901
    self.assertRaises(client.GanetiApiError,
902
                      self.client.EvacuateNode,
903
                      "node-4", iallocator="hail", remote_node="node-5")
904
    self.assertEqual(self.rapi.CountPending(), 0)
905

    
906
  def testEvacuateNodeOldResponse(self):
907
    self.rapi.AddResponse(serializer.DumpJson([]))
908
    self.assertRaises(client.GanetiApiError, self.client.EvacuateNode,
909
                      "node-4", accept_old=False)
910
    self.assertEqual(self.rapi.CountPending(), 0)
911

    
912
    for mode in [client.NODE_EVAC_PRI, client.NODE_EVAC_ALL]:
913
      self.rapi.AddResponse(serializer.DumpJson([]))
914
      self.assertRaises(client.GanetiApiError, self.client.EvacuateNode,
915
                        "node-4", accept_old=True, mode=mode)
916
      self.assertEqual(self.rapi.CountPending(), 0)
917

    
918
    self.rapi.AddResponse(serializer.DumpJson([]))
919
    self.rapi.AddResponse(serializer.DumpJson("21533"))
920
    result = self.client.EvacuateNode("node-3", iallocator="hail",
921
                                      dry_run=True, accept_old=True,
922
                                      mode=client.NODE_EVAC_SEC,
923
                                      early_release=True)
924
    self.assertEqual(result, "21533")
925
    self.assertItems(["node-3"])
926
    self.assertQuery("iallocator", ["hail"])
927
    self.assertQuery("early_release", ["1"])
928
    self.assertFalse(self.rapi.GetLastRequestData())
929
    self.assertDryRun()
930
    self.assertEqual(self.rapi.CountPending(), 0)
931

    
932
  def testMigrateNode(self):
933
    self.rapi.AddResponse(serializer.DumpJson([]))
934
    self.rapi.AddResponse("1111")
935
    self.assertEqual(1111, self.client.MigrateNode("node-a", dry_run=True))
936
    self.assertHandler(rlib2.R_2_nodes_name_migrate)
937
    self.assertItems(["node-a"])
938
    self.assert_("mode" not in self.rapi.GetLastHandler().queryargs)
939
    self.assertDryRun()
940
    self.assertFalse(self.rapi.GetLastRequestData())
941

    
942
    self.rapi.AddResponse(serializer.DumpJson([]))
943
    self.rapi.AddResponse("1112")
944
    self.assertEqual(1112, self.client.MigrateNode("node-a", dry_run=True,
945
                                                   mode="live"))
946
    self.assertHandler(rlib2.R_2_nodes_name_migrate)
947
    self.assertItems(["node-a"])
948
    self.assertQuery("mode", ["live"])
949
    self.assertDryRun()
950
    self.assertFalse(self.rapi.GetLastRequestData())
951

    
952
    self.rapi.AddResponse(serializer.DumpJson([]))
953
    self.assertRaises(client.GanetiApiError, self.client.MigrateNode,
954
                      "node-c", target_node="foonode")
955
    self.assertEqual(self.rapi.CountPending(), 0)
956

    
957
  def testMigrateNodeBodyData(self):
958
    self.rapi.AddResponse(serializer.DumpJson([rlib2._NODE_MIGRATE_REQV1]))
959
    self.rapi.AddResponse("27539")
960
    self.assertEqual(27539, self.client.MigrateNode("node-a", dry_run=False,
961
                                                    mode="live"))
962
    self.assertHandler(rlib2.R_2_nodes_name_migrate)
963
    self.assertItems(["node-a"])
964
    self.assertFalse(self.rapi.GetLastHandler().queryargs)
965
    self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
966
                     { "mode": "live", })
967

    
968
    self.rapi.AddResponse(serializer.DumpJson([rlib2._NODE_MIGRATE_REQV1]))
969
    self.rapi.AddResponse("14219")
970
    self.assertEqual(14219, self.client.MigrateNode("node-x", dry_run=True,
971
                                                    target_node="node9",
972
                                                    iallocator="ial"))
973
    self.assertHandler(rlib2.R_2_nodes_name_migrate)
974
    self.assertItems(["node-x"])
975
    self.assertDryRun()
976
    self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
977
                     { "target_node": "node9", "iallocator": "ial", })
978

    
979
    self.assertEqual(self.rapi.CountPending(), 0)
980

    
981
  def testGetNodeRole(self):
982
    self.rapi.AddResponse("\"master\"")
983
    self.assertEqual("master", self.client.GetNodeRole("node-a"))
984
    self.assertHandler(rlib2.R_2_nodes_name_role)
985
    self.assertItems(["node-a"])
986

    
987
  def testSetNodeRole(self):
988
    self.rapi.AddResponse("789")
989
    self.assertEqual(789,
990
        self.client.SetNodeRole("node-foo", "master-candidate", force=True))
991
    self.assertHandler(rlib2.R_2_nodes_name_role)
992
    self.assertItems(["node-foo"])
993
    self.assertQuery("force", ["1"])
994
    self.assertEqual("\"master-candidate\"", self.rapi.GetLastRequestData())
995

    
996
  def testPowercycleNode(self):
997
    self.rapi.AddResponse("23051")
998
    self.assertEqual(23051,
999
        self.client.PowercycleNode("node5468", force=True))
1000
    self.assertHandler(rlib2.R_2_nodes_name_powercycle)
1001
    self.assertItems(["node5468"])
1002
    self.assertQuery("force", ["1"])
1003
    self.assertFalse(self.rapi.GetLastRequestData())
1004
    self.assertEqual(self.rapi.CountPending(), 0)
1005

    
1006
  def testModifyNode(self):
1007
    self.rapi.AddResponse("3783")
1008
    job_id = self.client.ModifyNode("node16979.example.com", drained=True)
1009
    self.assertEqual(job_id, 3783)
1010
    self.assertHandler(rlib2.R_2_nodes_name_modify)
1011
    self.assertItems(["node16979.example.com"])
1012
    self.assertEqual(self.rapi.CountPending(), 0)
1013

    
1014
  def testGetNodeStorageUnits(self):
1015
    self.rapi.AddResponse("42")
1016
    self.assertEqual(42,
1017
        self.client.GetNodeStorageUnits("node-x", "lvm-pv", "fields"))
1018
    self.assertHandler(rlib2.R_2_nodes_name_storage)
1019
    self.assertItems(["node-x"])
1020
    self.assertQuery("storage_type", ["lvm-pv"])
1021
    self.assertQuery("output_fields", ["fields"])
1022

    
1023
  def testModifyNodeStorageUnits(self):
1024
    self.rapi.AddResponse("14")
1025
    self.assertEqual(14,
1026
        self.client.ModifyNodeStorageUnits("node-z", "lvm-pv", "hda"))
1027
    self.assertHandler(rlib2.R_2_nodes_name_storage_modify)
1028
    self.assertItems(["node-z"])
1029
    self.assertQuery("storage_type", ["lvm-pv"])
1030
    self.assertQuery("name", ["hda"])
1031
    self.assertQuery("allocatable", None)
1032

    
1033
    for allocatable, query_allocatable in [(True, "1"), (False, "0")]:
1034
      self.rapi.AddResponse("7205")
1035
      job_id = self.client.ModifyNodeStorageUnits("node-z", "lvm-pv", "hda",
1036
                                                  allocatable=allocatable)
1037
      self.assertEqual(7205, job_id)
1038
      self.assertHandler(rlib2.R_2_nodes_name_storage_modify)
1039
      self.assertItems(["node-z"])
1040
      self.assertQuery("storage_type", ["lvm-pv"])
1041
      self.assertQuery("name", ["hda"])
1042
      self.assertQuery("allocatable", [query_allocatable])
1043

    
1044
  def testRepairNodeStorageUnits(self):
1045
    self.rapi.AddResponse("99")
1046
    self.assertEqual(99, self.client.RepairNodeStorageUnits("node-z", "lvm-pv",
1047
                                                            "hda"))
1048
    self.assertHandler(rlib2.R_2_nodes_name_storage_repair)
1049
    self.assertItems(["node-z"])
1050
    self.assertQuery("storage_type", ["lvm-pv"])
1051
    self.assertQuery("name", ["hda"])
1052

    
1053
  def testGetNodeTags(self):
1054
    self.rapi.AddResponse("[\"fry\", \"bender\"]")
1055
    self.assertEqual(["fry", "bender"], self.client.GetNodeTags("node-k"))
1056
    self.assertHandler(rlib2.R_2_nodes_name_tags)
1057
    self.assertItems(["node-k"])
1058

    
1059
  def testAddNodeTags(self):
1060
    self.rapi.AddResponse("1234")
1061
    self.assertEqual(1234,
1062
        self.client.AddNodeTags("node-v", ["awesome"], dry_run=True))
1063
    self.assertHandler(rlib2.R_2_nodes_name_tags)
1064
    self.assertItems(["node-v"])
1065
    self.assertDryRun()
1066
    self.assertQuery("tag", ["awesome"])
1067

    
1068
  def testDeleteNodeTags(self):
1069
    self.rapi.AddResponse("16861")
1070
    self.assertEqual(16861, self.client.DeleteNodeTags("node-w", ["awesome"],
1071
                                                       dry_run=True))
1072
    self.assertHandler(rlib2.R_2_nodes_name_tags)
1073
    self.assertItems(["node-w"])
1074
    self.assertDryRun()
1075
    self.assertQuery("tag", ["awesome"])
1076

    
1077
  def testGetGroups(self):
1078
    groups = [{"name": "group1",
1079
               "uri": "/2/groups/group1",
1080
               },
1081
              {"name": "group2",
1082
               "uri": "/2/groups/group2",
1083
               },
1084
              ]
1085
    self.rapi.AddResponse(serializer.DumpJson(groups))
1086
    self.assertEqual(["group1", "group2"], self.client.GetGroups())
1087
    self.assertHandler(rlib2.R_2_groups)
1088

    
1089
  def testGetGroupsBulk(self):
1090
    groups = [{"name": "group1",
1091
               "uri": "/2/groups/group1",
1092
               "node_cnt": 2,
1093
               "node_list": ["gnt1.test",
1094
                             "gnt2.test",
1095
                             ],
1096
               },
1097
              {"name": "group2",
1098
               "uri": "/2/groups/group2",
1099
               "node_cnt": 1,
1100
               "node_list": ["gnt3.test",
1101
                             ],
1102
               },
1103
              ]
1104
    self.rapi.AddResponse(serializer.DumpJson(groups))
1105

    
1106
    self.assertEqual(groups, self.client.GetGroups(bulk=True))
1107
    self.assertHandler(rlib2.R_2_groups)
1108
    self.assertBulk()
1109

    
1110
  def testGetGroup(self):
1111
    group = {"ctime": None,
1112
             "name": "default",
1113
             }
1114
    self.rapi.AddResponse(serializer.DumpJson(group))
1115
    self.assertEqual({"ctime": None, "name": "default"},
1116
                     self.client.GetGroup("default"))
1117
    self.assertHandler(rlib2.R_2_groups_name)
1118
    self.assertItems(["default"])
1119

    
1120
  def testCreateGroup(self):
1121
    self.rapi.AddResponse("12345")
1122
    job_id = self.client.CreateGroup("newgroup", dry_run=True)
1123
    self.assertEqual(job_id, 12345)
1124
    self.assertHandler(rlib2.R_2_groups)
1125
    self.assertDryRun()
1126

    
1127
  def testDeleteGroup(self):
1128
    self.rapi.AddResponse("12346")
1129
    job_id = self.client.DeleteGroup("newgroup", dry_run=True)
1130
    self.assertEqual(job_id, 12346)
1131
    self.assertHandler(rlib2.R_2_groups_name)
1132
    self.assertDryRun()
1133

    
1134
  def testRenameGroup(self):
1135
    self.rapi.AddResponse("12347")
1136
    job_id = self.client.RenameGroup("oldname", "newname")
1137
    self.assertEqual(job_id, 12347)
1138
    self.assertHandler(rlib2.R_2_groups_name_rename)
1139

    
1140
  def testModifyGroup(self):
1141
    self.rapi.AddResponse("12348")
1142
    job_id = self.client.ModifyGroup("mygroup", alloc_policy="foo")
1143
    self.assertEqual(job_id, 12348)
1144
    self.assertHandler(rlib2.R_2_groups_name_modify)
1145

    
1146
  def testAssignGroupNodes(self):
1147
    self.rapi.AddResponse("12349")
1148
    job_id = self.client.AssignGroupNodes("mygroup", ["node1", "node2"],
1149
                                          force=True, dry_run=True)
1150
    self.assertEqual(job_id, 12349)
1151
    self.assertHandler(rlib2.R_2_groups_name_assign_nodes)
1152
    self.assertDryRun()
1153
    self.assertUseForce()
1154

    
1155
  def testGetNetworksBulk(self):
1156
    networks = [{"name": "network1",
1157
               "uri": "/2/networks/network1",
1158
               "network": "192.168.0.0/24",
1159
               },
1160
              {"name": "network2",
1161
               "uri": "/2/networks/network2",
1162
               "network": "192.168.0.0/24",
1163
               },
1164
              ]
1165
    self.rapi.AddResponse(serializer.DumpJson(networks))
1166

    
1167
    self.assertEqual(networks, self.client.GetNetworks(bulk=True))
1168
    self.assertHandler(rlib2.R_2_networks)
1169
    self.assertBulk()
1170

    
1171
  def testGetNetwork(self):
1172
    network = {"ctime": None,
1173
               "name": "network1",
1174
               }
1175
    self.rapi.AddResponse(serializer.DumpJson(network))
1176
    self.assertEqual({"ctime": None, "name": "network1"},
1177
                     self.client.GetNetwork("network1"))
1178
    self.assertHandler(rlib2.R_2_networks_name)
1179
    self.assertItems(["network1"])
1180

    
1181
  def testCreateNetwork(self):
1182
    self.rapi.AddResponse("12345")
1183
    job_id = self.client.CreateNetwork("newnetwork", network="192.168.0.0/24",
1184
                                       dry_run=True)
1185
    self.assertEqual(job_id, 12345)
1186
    self.assertHandler(rlib2.R_2_networks)
1187
    self.assertDryRun()
1188

    
1189
  def testModifyNetwork(self):
1190
    self.rapi.AddResponse("12346")
1191
    job_id = self.client.ModifyNetwork("mynetwork", gateway="192.168.0.10",
1192
                                     dry_run=True)
1193
    self.assertEqual(job_id, 12346)
1194
    self.assertHandler(rlib2.R_2_networks_name_modify)
1195

    
1196
  def testDeleteNetwork(self):
1197
    self.rapi.AddResponse("12347")
1198
    job_id = self.client.DeleteNetwork("newnetwork", dry_run=True)
1199
    self.assertEqual(job_id, 12347)
1200
    self.assertHandler(rlib2.R_2_networks_name)
1201
    self.assertDryRun()
1202

    
1203
  def testConnectNetwork(self):
1204
    self.rapi.AddResponse("12348")
1205
    job_id = self.client.ConnectNetwork("mynetwork", "default",
1206
                                        "bridged", "br0", dry_run=True)
1207
    self.assertEqual(job_id, 12348)
1208
    self.assertHandler(rlib2.R_2_networks_name_connect)
1209
    self.assertDryRun()
1210

    
1211
  def testDisconnectNetwork(self):
1212
    self.rapi.AddResponse("12349")
1213
    job_id = self.client.DisconnectNetwork("mynetwork", "default", dry_run=True)
1214
    self.assertEqual(job_id, 12349)
1215
    self.assertHandler(rlib2.R_2_networks_name_disconnect)
1216
    self.assertDryRun()
1217

    
1218
  def testGetNetworkTags(self):
1219
    self.rapi.AddResponse("[]")
1220
    self.assertEqual([], self.client.GetNetworkTags("fooNetwork"))
1221
    self.assertHandler(rlib2.R_2_networks_name_tags)
1222
    self.assertItems(["fooNetwork"])
1223

    
1224
  def testAddNetworkTags(self):
1225
    self.rapi.AddResponse("1234")
1226
    self.assertEqual(1234,
1227
        self.client.AddNetworkTags("fooNetwork", ["awesome"], dry_run=True))
1228
    self.assertHandler(rlib2.R_2_networks_name_tags)
1229
    self.assertItems(["fooNetwork"])
1230
    self.assertDryRun()
1231
    self.assertQuery("tag", ["awesome"])
1232

    
1233
  def testDeleteNetworkTags(self):
1234
    self.rapi.AddResponse("25826")
1235
    self.assertEqual(25826, self.client.DeleteNetworkTags("foo", ["awesome"],
1236
                                                          dry_run=True))
1237
    self.assertHandler(rlib2.R_2_networks_name_tags)
1238
    self.assertItems(["foo"])
1239
    self.assertDryRun()
1240
    self.assertQuery("tag", ["awesome"])
1241

    
1242
  def testModifyInstance(self):
1243
    self.rapi.AddResponse("23681")
1244
    job_id = self.client.ModifyInstance("inst7210", os_name="linux")
1245
    self.assertEqual(job_id, 23681)
1246
    self.assertItems(["inst7210"])
1247
    self.assertHandler(rlib2.R_2_instances_name_modify)
1248
    self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
1249
                     { "os_name": "linux", })
1250

    
1251
  def testModifyCluster(self):
1252
    for mnh in [None, False, True]:
1253
      self.rapi.AddResponse("14470")
1254
      self.assertEqual(14470,
1255
        self.client.ModifyCluster(maintain_node_health=mnh))
1256
      self.assertHandler(rlib2.R_2_cluster_modify)
1257
      self.assertItems([])
1258
      data = serializer.LoadJson(self.rapi.GetLastRequestData())
1259
      self.assertEqual(len(data), 1)
1260
      self.assertEqual(data["maintain_node_health"], mnh)
1261
      self.assertEqual(self.rapi.CountPending(), 0)
1262

    
1263
  def testRedistributeConfig(self):
1264
    self.rapi.AddResponse("3364")
1265
    job_id = self.client.RedistributeConfig()
1266
    self.assertEqual(job_id, 3364)
1267
    self.assertItems([])
1268
    self.assertHandler(rlib2.R_2_redist_config)
1269

    
1270
  def testActivateInstanceDisks(self):
1271
    self.rapi.AddResponse("23547")
1272
    job_id = self.client.ActivateInstanceDisks("inst28204")
1273
    self.assertEqual(job_id, 23547)
1274
    self.assertItems(["inst28204"])
1275
    self.assertHandler(rlib2.R_2_instances_name_activate_disks)
1276
    self.assertFalse(self.rapi.GetLastHandler().queryargs)
1277

    
1278
  def testActivateInstanceDisksIgnoreSize(self):
1279
    self.rapi.AddResponse("11044")
1280
    job_id = self.client.ActivateInstanceDisks("inst28204", ignore_size=True)
1281
    self.assertEqual(job_id, 11044)
1282
    self.assertItems(["inst28204"])
1283
    self.assertHandler(rlib2.R_2_instances_name_activate_disks)
1284
    self.assertQuery("ignore_size", ["1"])
1285

    
1286
  def testDeactivateInstanceDisks(self):
1287
    self.rapi.AddResponse("14591")
1288
    job_id = self.client.DeactivateInstanceDisks("inst28234")
1289
    self.assertEqual(job_id, 14591)
1290
    self.assertItems(["inst28234"])
1291
    self.assertHandler(rlib2.R_2_instances_name_deactivate_disks)
1292
    self.assertFalse(self.rapi.GetLastHandler().queryargs)
1293

    
1294
  def testRecreateInstanceDisks(self):
1295
    self.rapi.AddResponse("13553")
1296
    job_id = self.client.RecreateInstanceDisks("inst23153")
1297
    self.assertEqual(job_id, 13553)
1298
    self.assertItems(["inst23153"])
1299
    self.assertHandler(rlib2.R_2_instances_name_recreate_disks)
1300
    self.assertFalse(self.rapi.GetLastHandler().queryargs)
1301

    
1302
  def testGetInstanceConsole(self):
1303
    self.rapi.AddResponse("26876")
1304
    job_id = self.client.GetInstanceConsole("inst21491")
1305
    self.assertEqual(job_id, 26876)
1306
    self.assertItems(["inst21491"])
1307
    self.assertHandler(rlib2.R_2_instances_name_console)
1308
    self.assertFalse(self.rapi.GetLastHandler().queryargs)
1309
    self.assertFalse(self.rapi.GetLastRequestData())
1310

    
1311
  def testGrowInstanceDisk(self):
1312
    for idx, wait_for_sync in enumerate([None, False, True]):
1313
      amount = 128 + (512 * idx)
1314
      self.assertEqual(self.rapi.CountPending(), 0)
1315
      self.rapi.AddResponse("30783")
1316
      self.assertEqual(30783,
1317
        self.client.GrowInstanceDisk("eze8ch", idx, amount,
1318
                                     wait_for_sync=wait_for_sync))
1319
      self.assertHandler(rlib2.R_2_instances_name_disk_grow)
1320
      self.assertItems(["eze8ch", str(idx)])
1321
      data = serializer.LoadJson(self.rapi.GetLastRequestData())
1322
      if wait_for_sync is None:
1323
        self.assertEqual(len(data), 1)
1324
        self.assert_("wait_for_sync" not in data)
1325
      else:
1326
        self.assertEqual(len(data), 2)
1327
        self.assertEqual(data["wait_for_sync"], wait_for_sync)
1328
      self.assertEqual(data["amount"], amount)
1329
      self.assertEqual(self.rapi.CountPending(), 0)
1330

    
1331
  def testGetGroupTags(self):
1332
    self.rapi.AddResponse("[]")
1333
    self.assertEqual([], self.client.GetGroupTags("fooGroup"))
1334
    self.assertHandler(rlib2.R_2_groups_name_tags)
1335
    self.assertItems(["fooGroup"])
1336

    
1337
  def testAddGroupTags(self):
1338
    self.rapi.AddResponse("1234")
1339
    self.assertEqual(1234,
1340
        self.client.AddGroupTags("fooGroup", ["awesome"], dry_run=True))
1341
    self.assertHandler(rlib2.R_2_groups_name_tags)
1342
    self.assertItems(["fooGroup"])
1343
    self.assertDryRun()
1344
    self.assertQuery("tag", ["awesome"])
1345

    
1346
  def testDeleteGroupTags(self):
1347
    self.rapi.AddResponse("25826")
1348
    self.assertEqual(25826, self.client.DeleteGroupTags("foo", ["awesome"],
1349
                                                        dry_run=True))
1350
    self.assertHandler(rlib2.R_2_groups_name_tags)
1351
    self.assertItems(["foo"])
1352
    self.assertDryRun()
1353
    self.assertQuery("tag", ["awesome"])
1354

    
1355
  def testQuery(self):
1356
    for idx, what in enumerate(constants.QR_VIA_RAPI):
1357
      for idx2, qfilter in enumerate([None, ["?", "name"]]):
1358
        job_id = 11010 + (idx << 4) + (idx2 << 16)
1359
        fields = sorted(query.ALL_FIELDS[what].keys())[:10]
1360

    
1361
        self.rapi.AddResponse(str(job_id))
1362
        self.assertEqual(self.client.Query(what, fields, qfilter=qfilter),
1363
                         job_id)
1364
        self.assertItems([what])
1365
        self.assertHandler(rlib2.R_2_query)
1366
        self.assertFalse(self.rapi.GetLastHandler().queryargs)
1367
        data = serializer.LoadJson(self.rapi.GetLastRequestData())
1368
        self.assertEqual(data["fields"], fields)
1369
        if qfilter is None:
1370
          self.assertTrue("qfilter" not in data)
1371
        else:
1372
          self.assertEqual(data["qfilter"], qfilter)
1373
        self.assertEqual(self.rapi.CountPending(), 0)
1374

    
1375
  def testQueryFields(self):
1376
    exp_result = objects.QueryFieldsResponse(fields=[
1377
      objects.QueryFieldDefinition(name="pnode", title="PNode",
1378
                                   kind=constants.QFT_NUMBER),
1379
      objects.QueryFieldDefinition(name="other", title="Other",
1380
                                   kind=constants.QFT_BOOL),
1381
      ])
1382

    
1383
    for what in constants.QR_VIA_RAPI:
1384
      for fields in [None, ["name", "_unknown_"], ["&", "?|"]]:
1385
        self.rapi.AddResponse(serializer.DumpJson(exp_result.ToDict()))
1386
        result = self.client.QueryFields(what, fields=fields)
1387
        self.assertItems([what])
1388
        self.assertHandler(rlib2.R_2_query_fields)
1389
        self.assertFalse(self.rapi.GetLastRequestData())
1390

    
1391
        queryargs = self.rapi.GetLastHandler().queryargs
1392
        if fields is None:
1393
          self.assertFalse(queryargs)
1394
        else:
1395
          self.assertEqual(queryargs, {
1396
            "fields": [",".join(fields)],
1397
            })
1398

    
1399
        self.assertEqual(objects.QueryFieldsResponse.FromDict(result).ToDict(),
1400
                         exp_result.ToDict())
1401

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

    
1404
  def testWaitForJobCompletionNoChange(self):
1405
    resp = serializer.DumpJson({
1406
      "status": constants.JOB_STATUS_WAITING,
1407
      })
1408

    
1409
    for retries in [1, 5, 25]:
1410
      for _ in range(retries):
1411
        self.rapi.AddResponse(resp)
1412

    
1413
      self.assertFalse(self.client.WaitForJobCompletion(22789, period=None,
1414
                                                        retries=retries))
1415
      self.assertHandler(rlib2.R_2_jobs_id)
1416
      self.assertItems(["22789"])
1417

    
1418
      self.assertEqual(self.rapi.CountPending(), 0)
1419

    
1420
  def testWaitForJobCompletionAlreadyFinished(self):
1421
    self.rapi.AddResponse(serializer.DumpJson({
1422
      "status": constants.JOB_STATUS_SUCCESS,
1423
      }))
1424

    
1425
    self.assertTrue(self.client.WaitForJobCompletion(22793, period=None,
1426
                                                     retries=1))
1427
    self.assertHandler(rlib2.R_2_jobs_id)
1428
    self.assertItems(["22793"])
1429

    
1430
    self.assertEqual(self.rapi.CountPending(), 0)
1431

    
1432
  def testWaitForJobCompletionEmptyResponse(self):
1433
    self.rapi.AddResponse("{}")
1434
    self.assertFalse(self.client.WaitForJobCompletion(22793, period=None,
1435
                                                     retries=10))
1436
    self.assertHandler(rlib2.R_2_jobs_id)
1437
    self.assertItems(["22793"])
1438

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

    
1441
  def testWaitForJobCompletionOutOfRetries(self):
1442
    for retries in [3, 10, 21]:
1443
      for _ in range(retries):
1444
        self.rapi.AddResponse(serializer.DumpJson({
1445
          "status": constants.JOB_STATUS_RUNNING,
1446
          }))
1447

    
1448
      self.assertFalse(self.client.WaitForJobCompletion(30948, period=None,
1449
                                                        retries=retries - 1))
1450
      self.assertHandler(rlib2.R_2_jobs_id)
1451
      self.assertItems(["30948"])
1452

    
1453
      self.assertEqual(self.rapi.CountPending(), 1)
1454
      self.rapi.ResetResponses()
1455

    
1456
  def testWaitForJobCompletionSuccessAndFailure(self):
1457
    for retries in [1, 4, 13]:
1458
      for (success, end_status) in [(False, constants.JOB_STATUS_ERROR),
1459
                                    (True, constants.JOB_STATUS_SUCCESS)]:
1460
        for _ in range(retries):
1461
          self.rapi.AddResponse(serializer.DumpJson({
1462
            "status": constants.JOB_STATUS_RUNNING,
1463
            }))
1464

    
1465
        self.rapi.AddResponse(serializer.DumpJson({
1466
          "status": end_status,
1467
          }))
1468

    
1469
        result = self.client.WaitForJobCompletion(3187, period=None,
1470
                                                  retries=retries + 1)
1471
        self.assertEqual(result, success)
1472
        self.assertHandler(rlib2.R_2_jobs_id)
1473
        self.assertItems(["3187"])
1474

    
1475
        self.assertEqual(self.rapi.CountPending(), 0)
1476

    
1477

    
1478
class RapiTestRunner(unittest.TextTestRunner):
1479
  def run(self, *args):
1480
    global _used_handlers
1481
    assert _used_handlers is None
1482

    
1483
    _used_handlers = set()
1484
    try:
1485
      # Run actual tests
1486
      result = unittest.TextTestRunner.run(self, *args)
1487

    
1488
      diff = (set(connector.CONNECTOR.values()) - _used_handlers -
1489
             _KNOWN_UNUSED)
1490
      if diff:
1491
        raise AssertionError("The following RAPI resources were not used by the"
1492
                             " RAPI client: %r" % utils.CommaJoin(diff))
1493
    finally:
1494
      # Reset global variable
1495
      _used_handlers = None
1496

    
1497
    return result
1498

    
1499

    
1500
if __name__ == "__main__":
1501
  client.UsesRapiClient(testutils.GanetiTestProgram)(testRunner=RapiTestRunner)