Statistics
| Branch: | Tag: | Revision:

root / test / py / ganeti.rapi.client_unittest.py @ 55cec070

History | View | Annotate | Download (56.4 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
    self.assertHandler(rlib2.R_2_instances_name_shutdown)
624
    self.assertItems(["foo-instance"])
625
    self.assertDryRun()
626

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

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

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

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

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

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

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

    
703
    self.rapi.AddResponse("5175")
704
    self.assertEqual(5175, self.client.ReplaceInstanceDisks("instance-moo"))
705
    self.assertItems(["instance-moo"])
706
    self.assertQuery("disks", None)
707

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

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

    
723
    data = serializer.LoadJson(self.rapi.GetLastRequestData())
724
    self.assertEqual(data["mode"], "local")
725
    self.assertEqual(data["destination"], "nodeX")
726
    self.assertEqual(data["shutdown"], True)
727

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

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

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

    
748
        data = serializer.LoadJson(self.rapi.GetLastRequestData())
749
        self.assertEqual(len(data), 2)
750
        self.assertEqual(data["mode"], mode)
751
        self.assertEqual(data["cleanup"], cleanup)
752

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

    
760
    data = serializer.LoadJson(self.rapi.GetLastRequestData())
761
    self.assertFalse(data)
762

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

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

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

    
791
    data = serializer.LoadJson(self.rapi.GetLastRequestData())
792
    self.assertEqualValues(data, {"new_name": new_name, })
793

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

    
806
        data = serializer.LoadJson(self.rapi.GetLastRequestData())
807
        self.assertEqual(len(data), 3)
808
        self.assertEqual(data["new_name"], new_name)
809
        self.assertEqual(data["ip_check"], ip_check)
810
        self.assertEqual(data["name_check"], name_check)
811

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
968
    self.assertEqual(self.rapi.CountPending(), 0)
969

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

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

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

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

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

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

    
1022
    for allocatable, query_allocatable in [(True, "1"), (False, "0")]:
1023
      self.rapi.AddResponse("7205")
1024
      job_id = self.client.ModifyNodeStorageUnits("node-z", "lvm-pv", "hda",
1025
                                                  allocatable=allocatable)
1026
      self.assertEqual(7205, job_id)
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", [query_allocatable])
1032

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

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

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

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

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

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

    
1095
    self.assertEqual(groups, self.client.GetGroups(bulk=True))
1096
    self.assertHandler(rlib2.R_2_groups)
1097
    self.assertBulk()
1098

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

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

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

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

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

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

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

    
1156
    self.assertEqual(networks, self.client.GetNetworks(bulk=True))
1157
    self.assertHandler(rlib2.R_2_networks)
1158
    self.assertBulk()
1159

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1388
        self.assertEqual(objects.QueryFieldsResponse.FromDict(result).ToDict(),
1389
                         exp_result.ToDict())
1390

    
1391
        self.assertEqual(self.rapi.CountPending(), 0)
1392

    
1393
  def testWaitForJobCompletionNoChange(self):
1394
    resp = serializer.DumpJson({
1395
      "status": constants.JOB_STATUS_WAITING,
1396
      })
1397

    
1398
    for retries in [1, 5, 25]:
1399
      for _ in range(retries):
1400
        self.rapi.AddResponse(resp)
1401

    
1402
      self.assertFalse(self.client.WaitForJobCompletion(22789, period=None,
1403
                                                        retries=retries))
1404
      self.assertHandler(rlib2.R_2_jobs_id)
1405
      self.assertItems(["22789"])
1406

    
1407
      self.assertEqual(self.rapi.CountPending(), 0)
1408

    
1409
  def testWaitForJobCompletionAlreadyFinished(self):
1410
    self.rapi.AddResponse(serializer.DumpJson({
1411
      "status": constants.JOB_STATUS_SUCCESS,
1412
      }))
1413

    
1414
    self.assertTrue(self.client.WaitForJobCompletion(22793, period=None,
1415
                                                     retries=1))
1416
    self.assertHandler(rlib2.R_2_jobs_id)
1417
    self.assertItems(["22793"])
1418

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

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

    
1428
    self.assertEqual(self.rapi.CountPending(), 0)
1429

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

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

    
1442
      self.assertEqual(self.rapi.CountPending(), 1)
1443
      self.rapi.ResetResponses()
1444

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

    
1454
        self.rapi.AddResponse(serializer.DumpJson({
1455
          "status": end_status,
1456
          }))
1457

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

    
1464
        self.assertEqual(self.rapi.CountPending(), 0)
1465

    
1466

    
1467
class RapiTestRunner(unittest.TextTestRunner):
1468
  def run(self, *args):
1469
    global _used_handlers
1470
    assert _used_handlers is None
1471

    
1472
    _used_handlers = set()
1473
    try:
1474
      # Run actual tests
1475
      result = unittest.TextTestRunner.run(self, *args)
1476

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

    
1486
    return result
1487

    
1488

    
1489
if __name__ == "__main__":
1490
  client.UsesRapiClient(testutils.GanetiTestProgram)(testRunner=RapiTestRunner)