Statistics
| Branch: | Tag: | Revision:

root / test / py / ganeti.rapi.client_unittest.py @ 595149d5

History | View | Annotate | Download (55.8 kB)

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

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

    
21

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

    
24

    
25
import unittest
26
import warnings
27
import pycurl
28

    
29
from ganeti import opcodes
30
from ganeti import constants
31
from ganeti import http
32
from ganeti import serializer
33
from ganeti import utils
34
from ganeti import query
35
from ganeti import objects
36
from ganeti import rapi
37
from ganeti import errors
38

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

    
44
import testutils
45

    
46

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

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

    
56

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

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

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

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

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

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

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

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

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

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

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

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

    
101
    return (code, NotImplemented, response)
102

    
103

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

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

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

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

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

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

    
151

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

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

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

    
171

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

    
176

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

    
181

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

    
186

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

    
191

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

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

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

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

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

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

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

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

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

    
247
  def testNoCertVerify(self):
248
    cfgfn = client.GenericCurlConfig()
249

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
321
    self.assertRaises(client.Error, cl._CreateCurl)
322

    
323
  def testCertVerifyFancySsl(self):
324
    certdir = "/tmp/some/UNUSED/cert/directory"
325
    pcverfn = _FakeFancySslPycurlVersion
326
    cfgfn = client.GenericCurlConfig(capath=certdir,
327
                                     _pycurl_version_fn=pcverfn)
328

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

    
333
    self.assertRaises(NotImplementedError, cl._CreateCurl)
334

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

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

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

    
349

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
605
  def testShutdownInstance(self):
606
    self.rapi.AddResponse("1487")
607
    self.assertEqual(1487, self.client.ShutdownInstance("foo-instance",
608
                                                        dry_run=True))
609
    self.assertHandler(rlib2.R_2_instances_name_shutdown)
610
    self.assertItems(["foo-instance"])
611
    self.assertDryRun()
612

    
613
  def testStartupInstance(self):
614
    self.rapi.AddResponse("27149")
615
    self.assertEqual(27149, self.client.StartupInstance("bar-instance",
616
                                                        dry_run=True))
617
    self.assertHandler(rlib2.R_2_instances_name_startup)
618
    self.assertItems(["bar-instance"])
619
    self.assertDryRun()
620

    
621
  def testReinstallInstance(self):
622
    self.rapi.AddResponse(serializer.DumpJson([]))
623
    self.rapi.AddResponse("19119")
624
    self.assertEqual(19119, self.client.ReinstallInstance("baz-instance",
625
                                                          os="DOS",
626
                                                          no_startup=True))
627
    self.assertHandler(rlib2.R_2_instances_name_reinstall)
628
    self.assertItems(["baz-instance"])
629
    self.assertQuery("os", ["DOS"])
630
    self.assertQuery("nostartup", ["1"])
631
    self.assertEqual(self.rapi.CountPending(), 0)
632

    
633
  def testReinstallInstanceNew(self):
634
    self.rapi.AddResponse(serializer.DumpJson([rlib2._INST_REINSTALL_REQV1]))
635
    self.rapi.AddResponse("25689")
636
    self.assertEqual(25689, self.client.ReinstallInstance("moo-instance",
637
                                                          os="Debian",
638
                                                          no_startup=True))
639
    self.assertHandler(rlib2.R_2_instances_name_reinstall)
640
    self.assertItems(["moo-instance"])
641
    data = serializer.LoadJson(self.rapi.GetLastRequestData())
642
    self.assertEqual(len(data), 2)
643
    self.assertEqual(data["os"], "Debian")
644
    self.assertEqual(data["start"], False)
645
    self.assertEqual(self.rapi.CountPending(), 0)
646

    
647
  def testReinstallInstanceWithOsparams1(self):
648
    self.rapi.AddResponse(serializer.DumpJson([]))
649
    self.assertRaises(client.GanetiApiError, self.client.ReinstallInstance,
650
                      "doo-instance", osparams={"x": "y"})
651
    self.assertEqual(self.rapi.CountPending(), 0)
652

    
653
  def testReinstallInstanceWithOsparams2(self):
654
    osparams = {
655
      "Hello": "World",
656
      "foo": "bar",
657
      }
658
    self.rapi.AddResponse(serializer.DumpJson([rlib2._INST_REINSTALL_REQV1]))
659
    self.rapi.AddResponse("1717")
660
    self.assertEqual(1717, self.client.ReinstallInstance("zoo-instance",
661
                                                         osparams=osparams))
662
    self.assertHandler(rlib2.R_2_instances_name_reinstall)
663
    self.assertItems(["zoo-instance"])
664
    data = serializer.LoadJson(self.rapi.GetLastRequestData())
665
    self.assertEqual(len(data), 2)
666
    self.assertEqual(data["osparams"], osparams)
667
    self.assertEqual(data["start"], True)
668
    self.assertEqual(self.rapi.CountPending(), 0)
669

    
670
  def testReplaceInstanceDisks(self):
671
    self.rapi.AddResponse("999")
672
    job_id = self.client.ReplaceInstanceDisks("instance-name",
673
        disks=[0, 1], iallocator="hail")
674
    self.assertEqual(999, job_id)
675
    self.assertHandler(rlib2.R_2_instances_name_replace_disks)
676
    self.assertItems(["instance-name"])
677
    self.assertQuery("disks", ["0,1"])
678
    self.assertQuery("mode", ["replace_auto"])
679
    self.assertQuery("iallocator", ["hail"])
680

    
681
    self.rapi.AddResponse("1000")
682
    job_id = self.client.ReplaceInstanceDisks("instance-bar",
683
        disks=[1], mode="replace_on_secondary", remote_node="foo-node")
684
    self.assertEqual(1000, job_id)
685
    self.assertItems(["instance-bar"])
686
    self.assertQuery("disks", ["1"])
687
    self.assertQuery("remote_node", ["foo-node"])
688

    
689
    self.rapi.AddResponse("5175")
690
    self.assertEqual(5175, self.client.ReplaceInstanceDisks("instance-moo"))
691
    self.assertItems(["instance-moo"])
692
    self.assertQuery("disks", None)
693

    
694
  def testPrepareExport(self):
695
    self.rapi.AddResponse("8326")
696
    self.assertEqual(8326, self.client.PrepareExport("inst1", "local"))
697
    self.assertHandler(rlib2.R_2_instances_name_prepare_export)
698
    self.assertItems(["inst1"])
699
    self.assertQuery("mode", ["local"])
700

    
701
  def testExportInstance(self):
702
    self.rapi.AddResponse("19695")
703
    job_id = self.client.ExportInstance("inst2", "local", "nodeX",
704
                                        shutdown=True)
705
    self.assertEqual(job_id, 19695)
706
    self.assertHandler(rlib2.R_2_instances_name_export)
707
    self.assertItems(["inst2"])
708

    
709
    data = serializer.LoadJson(self.rapi.GetLastRequestData())
710
    self.assertEqual(data["mode"], "local")
711
    self.assertEqual(data["destination"], "nodeX")
712
    self.assertEqual(data["shutdown"], True)
713

    
714
  def testMigrateInstanceDefaults(self):
715
    self.rapi.AddResponse("24873")
716
    job_id = self.client.MigrateInstance("inst91")
717
    self.assertEqual(job_id, 24873)
718
    self.assertHandler(rlib2.R_2_instances_name_migrate)
719
    self.assertItems(["inst91"])
720

    
721
    data = serializer.LoadJson(self.rapi.GetLastRequestData())
722
    self.assertFalse(data)
723

    
724
  def testMigrateInstance(self):
725
    for mode in constants.HT_MIGRATION_MODES:
726
      for cleanup in [False, True]:
727
        self.rapi.AddResponse("31910")
728
        job_id = self.client.MigrateInstance("inst289", mode=mode,
729
                                             cleanup=cleanup)
730
        self.assertEqual(job_id, 31910)
731
        self.assertHandler(rlib2.R_2_instances_name_migrate)
732
        self.assertItems(["inst289"])
733

    
734
        data = serializer.LoadJson(self.rapi.GetLastRequestData())
735
        self.assertEqual(len(data), 2)
736
        self.assertEqual(data["mode"], mode)
737
        self.assertEqual(data["cleanup"], cleanup)
738

    
739
  def testFailoverInstanceDefaults(self):
740
    self.rapi.AddResponse("7639")
741
    job_id = self.client.FailoverInstance("inst13579")
742
    self.assertEqual(job_id, 7639)
743
    self.assertHandler(rlib2.R_2_instances_name_failover)
744
    self.assertItems(["inst13579"])
745

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

    
749
  def testFailoverInstance(self):
750
    for iallocator in ["dumb", "hail"]:
751
      for ignore_consistency in [False, True]:
752
        for target_node in ["node-a", "node2"]:
753
          self.rapi.AddResponse("19161")
754
          job_id = \
755
            self.client.FailoverInstance("inst251", iallocator=iallocator,
756
                                         ignore_consistency=ignore_consistency,
757
                                         target_node=target_node)
758
          self.assertEqual(job_id, 19161)
759
          self.assertHandler(rlib2.R_2_instances_name_failover)
760
          self.assertItems(["inst251"])
761

    
762
          data = serializer.LoadJson(self.rapi.GetLastRequestData())
763
          self.assertEqual(len(data), 3)
764
          self.assertEqual(data["iallocator"], iallocator)
765
          self.assertEqual(data["ignore_consistency"], ignore_consistency)
766
          self.assertEqual(data["target_node"], target_node)
767
          self.assertEqual(self.rapi.CountPending(), 0)
768

    
769
  def testRenameInstanceDefaults(self):
770
    new_name = "newnametha7euqu"
771
    self.rapi.AddResponse("8791")
772
    job_id = self.client.RenameInstance("inst18821", new_name)
773
    self.assertEqual(job_id, 8791)
774
    self.assertHandler(rlib2.R_2_instances_name_rename)
775
    self.assertItems(["inst18821"])
776

    
777
    data = serializer.LoadJson(self.rapi.GetLastRequestData())
778
    self.assertEqualValues(data, {"new_name": new_name, })
779

    
780
  def testRenameInstance(self):
781
    new_name = "new-name-yiux1iin"
782
    for ip_check in [False, True]:
783
      for name_check in [False, True]:
784
        self.rapi.AddResponse("24776")
785
        job_id = self.client.RenameInstance("inst20967", new_name,
786
                                             ip_check=ip_check,
787
                                             name_check=name_check)
788
        self.assertEqual(job_id, 24776)
789
        self.assertHandler(rlib2.R_2_instances_name_rename)
790
        self.assertItems(["inst20967"])
791

    
792
        data = serializer.LoadJson(self.rapi.GetLastRequestData())
793
        self.assertEqual(len(data), 3)
794
        self.assertEqual(data["new_name"], new_name)
795
        self.assertEqual(data["ip_check"], ip_check)
796
        self.assertEqual(data["name_check"], name_check)
797

    
798
  def testGetJobs(self):
799
    self.rapi.AddResponse('[ { "id": "123", "uri": "\\/2\\/jobs\\/123" },'
800
                          '  { "id": "124", "uri": "\\/2\\/jobs\\/124" } ]')
801
    self.assertEqual([123, 124], self.client.GetJobs())
802
    self.assertHandler(rlib2.R_2_jobs)
803

    
804
  def testGetJobStatus(self):
805
    self.rapi.AddResponse("{\"foo\": \"bar\"}")
806
    self.assertEqual({"foo": "bar"}, self.client.GetJobStatus(1234))
807
    self.assertHandler(rlib2.R_2_jobs_id)
808
    self.assertItems(["1234"])
809

    
810
  def testWaitForJobChange(self):
811
    fields = ["id", "summary"]
812
    expected = {
813
      "job_info": [123, "something"],
814
      "log_entries": [],
815
      }
816

    
817
    self.rapi.AddResponse(serializer.DumpJson(expected))
818
    result = self.client.WaitForJobChange(123, fields, [], -1)
819
    self.assertEqualValues(expected, result)
820
    self.assertHandler(rlib2.R_2_jobs_id_wait)
821
    self.assertItems(["123"])
822

    
823
  def testCancelJob(self):
824
    self.rapi.AddResponse("[true, \"Job 123 will be canceled\"]")
825
    self.assertEqual([True, "Job 123 will be canceled"],
826
                     self.client.CancelJob(999, dry_run=True))
827
    self.assertHandler(rlib2.R_2_jobs_id)
828
    self.assertItems(["999"])
829
    self.assertDryRun()
830

    
831
  def testGetNodes(self):
832
    self.rapi.AddResponse("[ { \"id\": \"node1\", \"uri\": \"uri1\" },"
833
                          " { \"id\": \"node2\", \"uri\": \"uri2\" } ]")
834
    self.assertEqual(["node1", "node2"], self.client.GetNodes())
835
    self.assertHandler(rlib2.R_2_nodes)
836

    
837
    self.rapi.AddResponse("[ { \"id\": \"node1\", \"uri\": \"uri1\" },"
838
                          " { \"id\": \"node2\", \"uri\": \"uri2\" } ]")
839
    self.assertEqual([{"id": "node1", "uri": "uri1"},
840
                      {"id": "node2", "uri": "uri2"}],
841
                     self.client.GetNodes(bulk=True))
842
    self.assertHandler(rlib2.R_2_nodes)
843
    self.assertBulk()
844

    
845
  def testGetNode(self):
846
    self.rapi.AddResponse("{}")
847
    self.assertEqual({}, self.client.GetNode("node-foo"))
848
    self.assertHandler(rlib2.R_2_nodes_name)
849
    self.assertItems(["node-foo"])
850

    
851
  def testEvacuateNode(self):
852
    self.rapi.AddResponse(serializer.DumpJson([rlib2._NODE_EVAC_RES1]))
853
    self.rapi.AddResponse("9876")
854
    job_id = self.client.EvacuateNode("node-1", remote_node="node-2")
855
    self.assertEqual(9876, job_id)
856
    self.assertHandler(rlib2.R_2_nodes_name_evacuate)
857
    self.assertItems(["node-1"])
858
    self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
859
                     { "remote_node": "node-2", })
860
    self.assertEqual(self.rapi.CountPending(), 0)
861

    
862
    self.rapi.AddResponse(serializer.DumpJson([rlib2._NODE_EVAC_RES1]))
863
    self.rapi.AddResponse("8888")
864
    job_id = self.client.EvacuateNode("node-3", iallocator="hail", dry_run=True,
865
                                      mode=constants.NODE_EVAC_ALL,
866
                                      early_release=True)
867
    self.assertEqual(8888, job_id)
868
    self.assertItems(["node-3"])
869
    self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()), {
870
      "iallocator": "hail",
871
      "mode": "all",
872
      "early_release": True,
873
      })
874
    self.assertDryRun()
875

    
876
    self.assertRaises(client.GanetiApiError,
877
                      self.client.EvacuateNode,
878
                      "node-4", iallocator="hail", remote_node="node-5")
879
    self.assertEqual(self.rapi.CountPending(), 0)
880

    
881
  def testEvacuateNodeOldResponse(self):
882
    self.rapi.AddResponse(serializer.DumpJson([]))
883
    self.assertRaises(client.GanetiApiError, self.client.EvacuateNode,
884
                      "node-4", accept_old=False)
885
    self.assertEqual(self.rapi.CountPending(), 0)
886

    
887
    for mode in [client.NODE_EVAC_PRI, client.NODE_EVAC_ALL]:
888
      self.rapi.AddResponse(serializer.DumpJson([]))
889
      self.assertRaises(client.GanetiApiError, self.client.EvacuateNode,
890
                        "node-4", accept_old=True, mode=mode)
891
      self.assertEqual(self.rapi.CountPending(), 0)
892

    
893
    self.rapi.AddResponse(serializer.DumpJson([]))
894
    self.rapi.AddResponse(serializer.DumpJson("21533"))
895
    result = self.client.EvacuateNode("node-3", iallocator="hail",
896
                                      dry_run=True, accept_old=True,
897
                                      mode=client.NODE_EVAC_SEC,
898
                                      early_release=True)
899
    self.assertEqual(result, "21533")
900
    self.assertItems(["node-3"])
901
    self.assertQuery("iallocator", ["hail"])
902
    self.assertQuery("early_release", ["1"])
903
    self.assertFalse(self.rapi.GetLastRequestData())
904
    self.assertDryRun()
905
    self.assertEqual(self.rapi.CountPending(), 0)
906

    
907
  def testMigrateNode(self):
908
    self.rapi.AddResponse(serializer.DumpJson([]))
909
    self.rapi.AddResponse("1111")
910
    self.assertEqual(1111, self.client.MigrateNode("node-a", dry_run=True))
911
    self.assertHandler(rlib2.R_2_nodes_name_migrate)
912
    self.assertItems(["node-a"])
913
    self.assert_("mode" not in self.rapi.GetLastHandler().queryargs)
914
    self.assertDryRun()
915
    self.assertFalse(self.rapi.GetLastRequestData())
916

    
917
    self.rapi.AddResponse(serializer.DumpJson([]))
918
    self.rapi.AddResponse("1112")
919
    self.assertEqual(1112, self.client.MigrateNode("node-a", dry_run=True,
920
                                                   mode="live"))
921
    self.assertHandler(rlib2.R_2_nodes_name_migrate)
922
    self.assertItems(["node-a"])
923
    self.assertQuery("mode", ["live"])
924
    self.assertDryRun()
925
    self.assertFalse(self.rapi.GetLastRequestData())
926

    
927
    self.rapi.AddResponse(serializer.DumpJson([]))
928
    self.assertRaises(client.GanetiApiError, self.client.MigrateNode,
929
                      "node-c", target_node="foonode")
930
    self.assertEqual(self.rapi.CountPending(), 0)
931

    
932
  def testMigrateNodeBodyData(self):
933
    self.rapi.AddResponse(serializer.DumpJson([rlib2._NODE_MIGRATE_REQV1]))
934
    self.rapi.AddResponse("27539")
935
    self.assertEqual(27539, self.client.MigrateNode("node-a", dry_run=False,
936
                                                    mode="live"))
937
    self.assertHandler(rlib2.R_2_nodes_name_migrate)
938
    self.assertItems(["node-a"])
939
    self.assertFalse(self.rapi.GetLastHandler().queryargs)
940
    self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
941
                     { "mode": "live", })
942

    
943
    self.rapi.AddResponse(serializer.DumpJson([rlib2._NODE_MIGRATE_REQV1]))
944
    self.rapi.AddResponse("14219")
945
    self.assertEqual(14219, self.client.MigrateNode("node-x", dry_run=True,
946
                                                    target_node="node9",
947
                                                    iallocator="ial"))
948
    self.assertHandler(rlib2.R_2_nodes_name_migrate)
949
    self.assertItems(["node-x"])
950
    self.assertDryRun()
951
    self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
952
                     { "target_node": "node9", "iallocator": "ial", })
953

    
954
    self.assertEqual(self.rapi.CountPending(), 0)
955

    
956
  def testGetNodeRole(self):
957
    self.rapi.AddResponse("\"master\"")
958
    self.assertEqual("master", self.client.GetNodeRole("node-a"))
959
    self.assertHandler(rlib2.R_2_nodes_name_role)
960
    self.assertItems(["node-a"])
961

    
962
  def testSetNodeRole(self):
963
    self.rapi.AddResponse("789")
964
    self.assertEqual(789,
965
        self.client.SetNodeRole("node-foo", "master-candidate", force=True))
966
    self.assertHandler(rlib2.R_2_nodes_name_role)
967
    self.assertItems(["node-foo"])
968
    self.assertQuery("force", ["1"])
969
    self.assertEqual("\"master-candidate\"", self.rapi.GetLastRequestData())
970

    
971
  def testPowercycleNode(self):
972
    self.rapi.AddResponse("23051")
973
    self.assertEqual(23051,
974
        self.client.PowercycleNode("node5468", force=True))
975
    self.assertHandler(rlib2.R_2_nodes_name_powercycle)
976
    self.assertItems(["node5468"])
977
    self.assertQuery("force", ["1"])
978
    self.assertFalse(self.rapi.GetLastRequestData())
979
    self.assertEqual(self.rapi.CountPending(), 0)
980

    
981
  def testModifyNode(self):
982
    self.rapi.AddResponse("3783")
983
    job_id = self.client.ModifyNode("node16979.example.com", drained=True)
984
    self.assertEqual(job_id, 3783)
985
    self.assertHandler(rlib2.R_2_nodes_name_modify)
986
    self.assertItems(["node16979.example.com"])
987
    self.assertEqual(self.rapi.CountPending(), 0)
988

    
989
  def testGetNodeStorageUnits(self):
990
    self.rapi.AddResponse("42")
991
    self.assertEqual(42,
992
        self.client.GetNodeStorageUnits("node-x", "lvm-pv", "fields"))
993
    self.assertHandler(rlib2.R_2_nodes_name_storage)
994
    self.assertItems(["node-x"])
995
    self.assertQuery("storage_type", ["lvm-pv"])
996
    self.assertQuery("output_fields", ["fields"])
997

    
998
  def testModifyNodeStorageUnits(self):
999
    self.rapi.AddResponse("14")
1000
    self.assertEqual(14,
1001
        self.client.ModifyNodeStorageUnits("node-z", "lvm-pv", "hda"))
1002
    self.assertHandler(rlib2.R_2_nodes_name_storage_modify)
1003
    self.assertItems(["node-z"])
1004
    self.assertQuery("storage_type", ["lvm-pv"])
1005
    self.assertQuery("name", ["hda"])
1006
    self.assertQuery("allocatable", None)
1007

    
1008
    for allocatable, query_allocatable in [(True, "1"), (False, "0")]:
1009
      self.rapi.AddResponse("7205")
1010
      job_id = self.client.ModifyNodeStorageUnits("node-z", "lvm-pv", "hda",
1011
                                                  allocatable=allocatable)
1012
      self.assertEqual(7205, job_id)
1013
      self.assertHandler(rlib2.R_2_nodes_name_storage_modify)
1014
      self.assertItems(["node-z"])
1015
      self.assertQuery("storage_type", ["lvm-pv"])
1016
      self.assertQuery("name", ["hda"])
1017
      self.assertQuery("allocatable", [query_allocatable])
1018

    
1019
  def testRepairNodeStorageUnits(self):
1020
    self.rapi.AddResponse("99")
1021
    self.assertEqual(99, self.client.RepairNodeStorageUnits("node-z", "lvm-pv",
1022
                                                            "hda"))
1023
    self.assertHandler(rlib2.R_2_nodes_name_storage_repair)
1024
    self.assertItems(["node-z"])
1025
    self.assertQuery("storage_type", ["lvm-pv"])
1026
    self.assertQuery("name", ["hda"])
1027

    
1028
  def testGetNodeTags(self):
1029
    self.rapi.AddResponse("[\"fry\", \"bender\"]")
1030
    self.assertEqual(["fry", "bender"], self.client.GetNodeTags("node-k"))
1031
    self.assertHandler(rlib2.R_2_nodes_name_tags)
1032
    self.assertItems(["node-k"])
1033

    
1034
  def testAddNodeTags(self):
1035
    self.rapi.AddResponse("1234")
1036
    self.assertEqual(1234,
1037
        self.client.AddNodeTags("node-v", ["awesome"], dry_run=True))
1038
    self.assertHandler(rlib2.R_2_nodes_name_tags)
1039
    self.assertItems(["node-v"])
1040
    self.assertDryRun()
1041
    self.assertQuery("tag", ["awesome"])
1042

    
1043
  def testDeleteNodeTags(self):
1044
    self.rapi.AddResponse("16861")
1045
    self.assertEqual(16861, self.client.DeleteNodeTags("node-w", ["awesome"],
1046
                                                       dry_run=True))
1047
    self.assertHandler(rlib2.R_2_nodes_name_tags)
1048
    self.assertItems(["node-w"])
1049
    self.assertDryRun()
1050
    self.assertQuery("tag", ["awesome"])
1051

    
1052
  def testGetGroups(self):
1053
    groups = [{"name": "group1",
1054
               "uri": "/2/groups/group1",
1055
               },
1056
              {"name": "group2",
1057
               "uri": "/2/groups/group2",
1058
               },
1059
              ]
1060
    self.rapi.AddResponse(serializer.DumpJson(groups))
1061
    self.assertEqual(["group1", "group2"], self.client.GetGroups())
1062
    self.assertHandler(rlib2.R_2_groups)
1063

    
1064
  def testGetGroupsBulk(self):
1065
    groups = [{"name": "group1",
1066
               "uri": "/2/groups/group1",
1067
               "node_cnt": 2,
1068
               "node_list": ["gnt1.test",
1069
                             "gnt2.test",
1070
                             ],
1071
               },
1072
              {"name": "group2",
1073
               "uri": "/2/groups/group2",
1074
               "node_cnt": 1,
1075
               "node_list": ["gnt3.test",
1076
                             ],
1077
               },
1078
              ]
1079
    self.rapi.AddResponse(serializer.DumpJson(groups))
1080

    
1081
    self.assertEqual(groups, self.client.GetGroups(bulk=True))
1082
    self.assertHandler(rlib2.R_2_groups)
1083
    self.assertBulk()
1084

    
1085
  def testGetGroup(self):
1086
    group = {"ctime": None,
1087
             "name": "default",
1088
             }
1089
    self.rapi.AddResponse(serializer.DumpJson(group))
1090
    self.assertEqual({"ctime": None, "name": "default"},
1091
                     self.client.GetGroup("default"))
1092
    self.assertHandler(rlib2.R_2_groups_name)
1093
    self.assertItems(["default"])
1094

    
1095
  def testCreateGroup(self):
1096
    self.rapi.AddResponse("12345")
1097
    job_id = self.client.CreateGroup("newgroup", dry_run=True)
1098
    self.assertEqual(job_id, 12345)
1099
    self.assertHandler(rlib2.R_2_groups)
1100
    self.assertDryRun()
1101

    
1102
  def testDeleteGroup(self):
1103
    self.rapi.AddResponse("12346")
1104
    job_id = self.client.DeleteGroup("newgroup", dry_run=True)
1105
    self.assertEqual(job_id, 12346)
1106
    self.assertHandler(rlib2.R_2_groups_name)
1107
    self.assertDryRun()
1108

    
1109
  def testRenameGroup(self):
1110
    self.rapi.AddResponse("12347")
1111
    job_id = self.client.RenameGroup("oldname", "newname")
1112
    self.assertEqual(job_id, 12347)
1113
    self.assertHandler(rlib2.R_2_groups_name_rename)
1114

    
1115
  def testModifyGroup(self):
1116
    self.rapi.AddResponse("12348")
1117
    job_id = self.client.ModifyGroup("mygroup", alloc_policy="foo")
1118
    self.assertEqual(job_id, 12348)
1119
    self.assertHandler(rlib2.R_2_groups_name_modify)
1120

    
1121
  def testAssignGroupNodes(self):
1122
    self.rapi.AddResponse("12349")
1123
    job_id = self.client.AssignGroupNodes("mygroup", ["node1", "node2"],
1124
                                          force=True, dry_run=True)
1125
    self.assertEqual(job_id, 12349)
1126
    self.assertHandler(rlib2.R_2_groups_name_assign_nodes)
1127
    self.assertDryRun()
1128
    self.assertUseForce()
1129

    
1130
  def testGetNetworksBulk(self):
1131
    networks = [{"name": "network1",
1132
               "uri": "/2/networks/network1",
1133
               "network": "192.168.0.0/24",
1134
               },
1135
              {"name": "network2",
1136
               "uri": "/2/networks/network2",
1137
               "network": "192.168.0.0/24",
1138
               },
1139
              ]
1140
    self.rapi.AddResponse(serializer.DumpJson(networks))
1141

    
1142
    self.assertEqual(networks, self.client.GetNetworks(bulk=True))
1143
    self.assertHandler(rlib2.R_2_networks)
1144
    self.assertBulk()
1145

    
1146
  def testGetNetwork(self):
1147
    network = {"ctime": None,
1148
               "name": "network1",
1149
               }
1150
    self.rapi.AddResponse(serializer.DumpJson(network))
1151
    self.assertEqual({"ctime": None, "name": "network1"},
1152
                     self.client.GetNetwork("network1"))
1153
    self.assertHandler(rlib2.R_2_networks_name)
1154
    self.assertItems(["network1"])
1155

    
1156
  def testCreateNetwork(self):
1157
    self.rapi.AddResponse("12345")
1158
    job_id = self.client.CreateNetwork("newnetwork", network="192.168.0.0/24",
1159
                                       dry_run=True)
1160
    self.assertEqual(job_id, 12345)
1161
    self.assertHandler(rlib2.R_2_networks)
1162
    self.assertDryRun()
1163

    
1164
  def testModifyNetwork(self):
1165
    self.rapi.AddResponse("12346")
1166
    job_id = self.client.ModifyNetwork("mynetwork", gateway="192.168.0.10",
1167
                                     dry_run=True)
1168
    self.assertEqual(job_id, 12346)
1169
    self.assertHandler(rlib2.R_2_networks_name_modify)
1170

    
1171
  def testDeleteNetwork(self):
1172
    self.rapi.AddResponse("12347")
1173
    job_id = self.client.DeleteNetwork("newnetwork", dry_run=True)
1174
    self.assertEqual(job_id, 12347)
1175
    self.assertHandler(rlib2.R_2_networks_name)
1176
    self.assertDryRun()
1177

    
1178
  def testConnectNetwork(self):
1179
    self.rapi.AddResponse("12348")
1180
    job_id = self.client.ConnectNetwork("mynetwork", "default",
1181
                                        "bridged", "br0", dry_run=True)
1182
    self.assertEqual(job_id, 12348)
1183
    self.assertHandler(rlib2.R_2_networks_name_connect)
1184
    self.assertDryRun()
1185

    
1186
  def testDisconnectNetwork(self):
1187
    self.rapi.AddResponse("12349")
1188
    job_id = self.client.DisconnectNetwork("mynetwork", "default", dry_run=True)
1189
    self.assertEqual(job_id, 12349)
1190
    self.assertHandler(rlib2.R_2_networks_name_disconnect)
1191
    self.assertDryRun()
1192

    
1193
  def testGetNetworkTags(self):
1194
    self.rapi.AddResponse("[]")
1195
    self.assertEqual([], self.client.GetNetworkTags("fooNetwork"))
1196
    self.assertHandler(rlib2.R_2_networks_name_tags)
1197
    self.assertItems(["fooNetwork"])
1198

    
1199
  def testAddNetworkTags(self):
1200
    self.rapi.AddResponse("1234")
1201
    self.assertEqual(1234,
1202
        self.client.AddNetworkTags("fooNetwork", ["awesome"], dry_run=True))
1203
    self.assertHandler(rlib2.R_2_networks_name_tags)
1204
    self.assertItems(["fooNetwork"])
1205
    self.assertDryRun()
1206
    self.assertQuery("tag", ["awesome"])
1207

    
1208
  def testDeleteNetworkTags(self):
1209
    self.rapi.AddResponse("25826")
1210
    self.assertEqual(25826, self.client.DeleteNetworkTags("foo", ["awesome"],
1211
                                                          dry_run=True))
1212
    self.assertHandler(rlib2.R_2_networks_name_tags)
1213
    self.assertItems(["foo"])
1214
    self.assertDryRun()
1215
    self.assertQuery("tag", ["awesome"])
1216

    
1217
  def testModifyInstance(self):
1218
    self.rapi.AddResponse("23681")
1219
    job_id = self.client.ModifyInstance("inst7210", os_name="linux")
1220
    self.assertEqual(job_id, 23681)
1221
    self.assertItems(["inst7210"])
1222
    self.assertHandler(rlib2.R_2_instances_name_modify)
1223
    self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
1224
                     { "os_name": "linux", })
1225

    
1226
  def testModifyCluster(self):
1227
    for mnh in [None, False, True]:
1228
      self.rapi.AddResponse("14470")
1229
      self.assertEqual(14470,
1230
        self.client.ModifyCluster(maintain_node_health=mnh))
1231
      self.assertHandler(rlib2.R_2_cluster_modify)
1232
      self.assertItems([])
1233
      data = serializer.LoadJson(self.rapi.GetLastRequestData())
1234
      self.assertEqual(len(data), 1)
1235
      self.assertEqual(data["maintain_node_health"], mnh)
1236
      self.assertEqual(self.rapi.CountPending(), 0)
1237

    
1238
  def testRedistributeConfig(self):
1239
    self.rapi.AddResponse("3364")
1240
    job_id = self.client.RedistributeConfig()
1241
    self.assertEqual(job_id, 3364)
1242
    self.assertItems([])
1243
    self.assertHandler(rlib2.R_2_redist_config)
1244

    
1245
  def testActivateInstanceDisks(self):
1246
    self.rapi.AddResponse("23547")
1247
    job_id = self.client.ActivateInstanceDisks("inst28204")
1248
    self.assertEqual(job_id, 23547)
1249
    self.assertItems(["inst28204"])
1250
    self.assertHandler(rlib2.R_2_instances_name_activate_disks)
1251
    self.assertFalse(self.rapi.GetLastHandler().queryargs)
1252

    
1253
  def testActivateInstanceDisksIgnoreSize(self):
1254
    self.rapi.AddResponse("11044")
1255
    job_id = self.client.ActivateInstanceDisks("inst28204", ignore_size=True)
1256
    self.assertEqual(job_id, 11044)
1257
    self.assertItems(["inst28204"])
1258
    self.assertHandler(rlib2.R_2_instances_name_activate_disks)
1259
    self.assertQuery("ignore_size", ["1"])
1260

    
1261
  def testDeactivateInstanceDisks(self):
1262
    self.rapi.AddResponse("14591")
1263
    job_id = self.client.DeactivateInstanceDisks("inst28234")
1264
    self.assertEqual(job_id, 14591)
1265
    self.assertItems(["inst28234"])
1266
    self.assertHandler(rlib2.R_2_instances_name_deactivate_disks)
1267
    self.assertFalse(self.rapi.GetLastHandler().queryargs)
1268

    
1269
  def testRecreateInstanceDisks(self):
1270
    self.rapi.AddResponse("13553")
1271
    job_id = self.client.RecreateInstanceDisks("inst23153")
1272
    self.assertEqual(job_id, 13553)
1273
    self.assertItems(["inst23153"])
1274
    self.assertHandler(rlib2.R_2_instances_name_recreate_disks)
1275
    self.assertFalse(self.rapi.GetLastHandler().queryargs)
1276

    
1277
  def testGetInstanceConsole(self):
1278
    self.rapi.AddResponse("26876")
1279
    job_id = self.client.GetInstanceConsole("inst21491")
1280
    self.assertEqual(job_id, 26876)
1281
    self.assertItems(["inst21491"])
1282
    self.assertHandler(rlib2.R_2_instances_name_console)
1283
    self.assertFalse(self.rapi.GetLastHandler().queryargs)
1284
    self.assertFalse(self.rapi.GetLastRequestData())
1285

    
1286
  def testGrowInstanceDisk(self):
1287
    for idx, wait_for_sync in enumerate([None, False, True]):
1288
      amount = 128 + (512 * idx)
1289
      self.assertEqual(self.rapi.CountPending(), 0)
1290
      self.rapi.AddResponse("30783")
1291
      self.assertEqual(30783,
1292
        self.client.GrowInstanceDisk("eze8ch", idx, amount,
1293
                                     wait_for_sync=wait_for_sync))
1294
      self.assertHandler(rlib2.R_2_instances_name_disk_grow)
1295
      self.assertItems(["eze8ch", str(idx)])
1296
      data = serializer.LoadJson(self.rapi.GetLastRequestData())
1297
      if wait_for_sync is None:
1298
        self.assertEqual(len(data), 1)
1299
        self.assert_("wait_for_sync" not in data)
1300
      else:
1301
        self.assertEqual(len(data), 2)
1302
        self.assertEqual(data["wait_for_sync"], wait_for_sync)
1303
      self.assertEqual(data["amount"], amount)
1304
      self.assertEqual(self.rapi.CountPending(), 0)
1305

    
1306
  def testGetGroupTags(self):
1307
    self.rapi.AddResponse("[]")
1308
    self.assertEqual([], self.client.GetGroupTags("fooGroup"))
1309
    self.assertHandler(rlib2.R_2_groups_name_tags)
1310
    self.assertItems(["fooGroup"])
1311

    
1312
  def testAddGroupTags(self):
1313
    self.rapi.AddResponse("1234")
1314
    self.assertEqual(1234,
1315
        self.client.AddGroupTags("fooGroup", ["awesome"], dry_run=True))
1316
    self.assertHandler(rlib2.R_2_groups_name_tags)
1317
    self.assertItems(["fooGroup"])
1318
    self.assertDryRun()
1319
    self.assertQuery("tag", ["awesome"])
1320

    
1321
  def testDeleteGroupTags(self):
1322
    self.rapi.AddResponse("25826")
1323
    self.assertEqual(25826, self.client.DeleteGroupTags("foo", ["awesome"],
1324
                                                        dry_run=True))
1325
    self.assertHandler(rlib2.R_2_groups_name_tags)
1326
    self.assertItems(["foo"])
1327
    self.assertDryRun()
1328
    self.assertQuery("tag", ["awesome"])
1329

    
1330
  def testQuery(self):
1331
    for idx, what in enumerate(constants.QR_VIA_RAPI):
1332
      for idx2, qfilter in enumerate([None, ["?", "name"]]):
1333
        job_id = 11010 + (idx << 4) + (idx2 << 16)
1334
        fields = sorted(query.ALL_FIELDS[what].keys())[:10]
1335

    
1336
        self.rapi.AddResponse(str(job_id))
1337
        self.assertEqual(self.client.Query(what, fields, qfilter=qfilter),
1338
                         job_id)
1339
        self.assertItems([what])
1340
        self.assertHandler(rlib2.R_2_query)
1341
        self.assertFalse(self.rapi.GetLastHandler().queryargs)
1342
        data = serializer.LoadJson(self.rapi.GetLastRequestData())
1343
        self.assertEqual(data["fields"], fields)
1344
        if qfilter is None:
1345
          self.assertTrue("qfilter" not in data)
1346
        else:
1347
          self.assertEqual(data["qfilter"], qfilter)
1348
        self.assertEqual(self.rapi.CountPending(), 0)
1349

    
1350
  def testQueryFields(self):
1351
    exp_result = objects.QueryFieldsResponse(fields=[
1352
      objects.QueryFieldDefinition(name="pnode", title="PNode",
1353
                                   kind=constants.QFT_NUMBER),
1354
      objects.QueryFieldDefinition(name="other", title="Other",
1355
                                   kind=constants.QFT_BOOL),
1356
      ])
1357

    
1358
    for what in constants.QR_VIA_RAPI:
1359
      for fields in [None, ["name", "_unknown_"], ["&", "?|"]]:
1360
        self.rapi.AddResponse(serializer.DumpJson(exp_result.ToDict()))
1361
        result = self.client.QueryFields(what, fields=fields)
1362
        self.assertItems([what])
1363
        self.assertHandler(rlib2.R_2_query_fields)
1364
        self.assertFalse(self.rapi.GetLastRequestData())
1365

    
1366
        queryargs = self.rapi.GetLastHandler().queryargs
1367
        if fields is None:
1368
          self.assertFalse(queryargs)
1369
        else:
1370
          self.assertEqual(queryargs, {
1371
            "fields": [",".join(fields)],
1372
            })
1373

    
1374
        self.assertEqual(objects.QueryFieldsResponse.FromDict(result).ToDict(),
1375
                         exp_result.ToDict())
1376

    
1377
        self.assertEqual(self.rapi.CountPending(), 0)
1378

    
1379
  def testWaitForJobCompletionNoChange(self):
1380
    resp = serializer.DumpJson({
1381
      "status": constants.JOB_STATUS_WAITING,
1382
      })
1383

    
1384
    for retries in [1, 5, 25]:
1385
      for _ in range(retries):
1386
        self.rapi.AddResponse(resp)
1387

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

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

    
1395
  def testWaitForJobCompletionAlreadyFinished(self):
1396
    self.rapi.AddResponse(serializer.DumpJson({
1397
      "status": constants.JOB_STATUS_SUCCESS,
1398
      }))
1399

    
1400
    self.assertTrue(self.client.WaitForJobCompletion(22793, period=None,
1401
                                                     retries=1))
1402
    self.assertHandler(rlib2.R_2_jobs_id)
1403
    self.assertItems(["22793"])
1404

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

    
1407
  def testWaitForJobCompletionEmptyResponse(self):
1408
    self.rapi.AddResponse("{}")
1409
    self.assertFalse(self.client.WaitForJobCompletion(22793, period=None,
1410
                                                     retries=10))
1411
    self.assertHandler(rlib2.R_2_jobs_id)
1412
    self.assertItems(["22793"])
1413

    
1414
    self.assertEqual(self.rapi.CountPending(), 0)
1415

    
1416
  def testWaitForJobCompletionOutOfRetries(self):
1417
    for retries in [3, 10, 21]:
1418
      for _ in range(retries):
1419
        self.rapi.AddResponse(serializer.DumpJson({
1420
          "status": constants.JOB_STATUS_RUNNING,
1421
          }))
1422

    
1423
      self.assertFalse(self.client.WaitForJobCompletion(30948, period=None,
1424
                                                        retries=retries - 1))
1425
      self.assertHandler(rlib2.R_2_jobs_id)
1426
      self.assertItems(["30948"])
1427

    
1428
      self.assertEqual(self.rapi.CountPending(), 1)
1429
      self.rapi.ResetResponses()
1430

    
1431
  def testWaitForJobCompletionSuccessAndFailure(self):
1432
    for retries in [1, 4, 13]:
1433
      for (success, end_status) in [(False, constants.JOB_STATUS_ERROR),
1434
                                    (True, constants.JOB_STATUS_SUCCESS)]:
1435
        for _ in range(retries):
1436
          self.rapi.AddResponse(serializer.DumpJson({
1437
            "status": constants.JOB_STATUS_RUNNING,
1438
            }))
1439

    
1440
        self.rapi.AddResponse(serializer.DumpJson({
1441
          "status": end_status,
1442
          }))
1443

    
1444
        result = self.client.WaitForJobCompletion(3187, period=None,
1445
                                                  retries=retries + 1)
1446
        self.assertEqual(result, success)
1447
        self.assertHandler(rlib2.R_2_jobs_id)
1448
        self.assertItems(["3187"])
1449

    
1450
        self.assertEqual(self.rapi.CountPending(), 0)
1451

    
1452

    
1453
class RapiTestRunner(unittest.TextTestRunner):
1454
  def run(self, *args):
1455
    global _used_handlers
1456
    assert _used_handlers is None
1457

    
1458
    _used_handlers = set()
1459
    try:
1460
      # Run actual tests
1461
      result = unittest.TextTestRunner.run(self, *args)
1462

    
1463
      diff = (set(connector.CONNECTOR.values()) - _used_handlers -
1464
             _KNOWN_UNUSED)
1465
      if diff:
1466
        raise AssertionError("The following RAPI resources were not used by the"
1467
                             " RAPI client: %r" % utils.CommaJoin(diff))
1468
    finally:
1469
      # Reset global variable
1470
      _used_handlers = None
1471

    
1472
    return result
1473

    
1474

    
1475
if __name__ == "__main__":
1476
  client.UsesRapiClient(testutils.GanetiTestProgram)(testRunner=RapiTestRunner)