Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (58.1 kB)

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

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

    
21

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

    
24

    
25
import unittest
26
import warnings
27
import pycurl
28

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

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

    
44
import testutils
45

    
46

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

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

    
56

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

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

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

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

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

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

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

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

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

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

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

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

    
101
    return (code, NotImplemented, response)
102

    
103

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

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

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

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

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

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

    
151

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

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

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

    
171

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

    
176

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

    
181

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

    
186

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

    
191

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
349

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
648
  def testStartupInstanceDefaultReason(self):
649
    self.rapi.AddResponse("27149")
650
    self.assertEqual(27149, self.client.StartupInstance("bar-instance",
651
                                                        dry_run=True))
652
    self.assertHandler(rlib2.R_2_instances_name_startup)
653
    self.assertItems(["bar-instance"])
654
    self.assertDryRun()
655
    self.assertQuery("reason", None)
656

    
657
  def testReinstallInstance(self):
658
    self.rapi.AddResponse(serializer.DumpJson([]))
659
    self.rapi.AddResponse("19119")
660
    self.assertEqual(19119, self.client.ReinstallInstance("baz-instance",
661
                                                          os="DOS",
662
                                                          no_startup=True))
663
    self.assertHandler(rlib2.R_2_instances_name_reinstall)
664
    self.assertItems(["baz-instance"])
665
    self.assertQuery("os", ["DOS"])
666
    self.assertQuery("nostartup", ["1"])
667
    self.assertEqual(self.rapi.CountPending(), 0)
668

    
669
  def testReinstallInstanceNew(self):
670
    self.rapi.AddResponse(serializer.DumpJson([rlib2._INST_REINSTALL_REQV1]))
671
    self.rapi.AddResponse("25689")
672
    self.assertEqual(25689, self.client.ReinstallInstance("moo-instance",
673
                                                          os="Debian",
674
                                                          no_startup=True))
675
    self.assertHandler(rlib2.R_2_instances_name_reinstall)
676
    self.assertItems(["moo-instance"])
677
    data = serializer.LoadJson(self.rapi.GetLastRequestData())
678
    self.assertEqual(len(data), 2)
679
    self.assertEqual(data["os"], "Debian")
680
    self.assertEqual(data["start"], False)
681
    self.assertEqual(self.rapi.CountPending(), 0)
682

    
683
  def testReinstallInstanceWithOsparams1(self):
684
    self.rapi.AddResponse(serializer.DumpJson([]))
685
    self.assertRaises(client.GanetiApiError, self.client.ReinstallInstance,
686
                      "doo-instance", osparams={"x": "y"})
687
    self.assertEqual(self.rapi.CountPending(), 0)
688

    
689
  def testReinstallInstanceWithOsparams2(self):
690
    osparams = {
691
      "Hello": "World",
692
      "foo": "bar",
693
      }
694
    self.rapi.AddResponse(serializer.DumpJson([rlib2._INST_REINSTALL_REQV1]))
695
    self.rapi.AddResponse("1717")
696
    self.assertEqual(1717, self.client.ReinstallInstance("zoo-instance",
697
                                                         osparams=osparams))
698
    self.assertHandler(rlib2.R_2_instances_name_reinstall)
699
    self.assertItems(["zoo-instance"])
700
    data = serializer.LoadJson(self.rapi.GetLastRequestData())
701
    self.assertEqual(len(data), 2)
702
    self.assertEqual(data["osparams"], osparams)
703
    self.assertEqual(data["start"], True)
704
    self.assertEqual(self.rapi.CountPending(), 0)
705

    
706
  def testReplaceInstanceDisks(self):
707
    self.rapi.AddResponse("999")
708
    job_id = self.client.ReplaceInstanceDisks("instance-name",
709
        disks=[0, 1], iallocator="hail")
710
    self.assertEqual(999, job_id)
711
    self.assertHandler(rlib2.R_2_instances_name_replace_disks)
712
    self.assertItems(["instance-name"])
713
    self.assertQuery("disks", ["0,1"])
714
    self.assertQuery("mode", ["replace_auto"])
715
    self.assertQuery("iallocator", ["hail"])
716

    
717
    self.rapi.AddResponse("1000")
718
    job_id = self.client.ReplaceInstanceDisks("instance-bar",
719
        disks=[1], mode="replace_on_secondary", remote_node="foo-node")
720
    self.assertEqual(1000, job_id)
721
    self.assertItems(["instance-bar"])
722
    self.assertQuery("disks", ["1"])
723
    self.assertQuery("remote_node", ["foo-node"])
724

    
725
    self.rapi.AddResponse("5175")
726
    self.assertEqual(5175, self.client.ReplaceInstanceDisks("instance-moo"))
727
    self.assertItems(["instance-moo"])
728
    self.assertQuery("disks", None)
729

    
730
  def testPrepareExport(self):
731
    self.rapi.AddResponse("8326")
732
    self.assertEqual(8326, self.client.PrepareExport("inst1", "local"))
733
    self.assertHandler(rlib2.R_2_instances_name_prepare_export)
734
    self.assertItems(["inst1"])
735
    self.assertQuery("mode", ["local"])
736

    
737
  def testExportInstance(self):
738
    self.rapi.AddResponse("19695")
739
    job_id = self.client.ExportInstance("inst2", "local", "nodeX",
740
                                        shutdown=True)
741
    self.assertEqual(job_id, 19695)
742
    self.assertHandler(rlib2.R_2_instances_name_export)
743
    self.assertItems(["inst2"])
744

    
745
    data = serializer.LoadJson(self.rapi.GetLastRequestData())
746
    self.assertEqual(data["mode"], "local")
747
    self.assertEqual(data["destination"], "nodeX")
748
    self.assertEqual(data["shutdown"], True)
749

    
750
  def testMigrateInstanceDefaults(self):
751
    self.rapi.AddResponse("24873")
752
    job_id = self.client.MigrateInstance("inst91")
753
    self.assertEqual(job_id, 24873)
754
    self.assertHandler(rlib2.R_2_instances_name_migrate)
755
    self.assertItems(["inst91"])
756

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

    
760
  def testMigrateInstance(self):
761
    for mode in constants.HT_MIGRATION_MODES:
762
      for cleanup in [False, True]:
763
        self.rapi.AddResponse("31910")
764
        job_id = self.client.MigrateInstance("inst289", mode=mode,
765
                                             cleanup=cleanup)
766
        self.assertEqual(job_id, 31910)
767
        self.assertHandler(rlib2.R_2_instances_name_migrate)
768
        self.assertItems(["inst289"])
769

    
770
        data = serializer.LoadJson(self.rapi.GetLastRequestData())
771
        self.assertEqual(len(data), 2)
772
        self.assertEqual(data["mode"], mode)
773
        self.assertEqual(data["cleanup"], cleanup)
774

    
775
  def testFailoverInstanceDefaults(self):
776
    self.rapi.AddResponse("7639")
777
    job_id = self.client.FailoverInstance("inst13579")
778
    self.assertEqual(job_id, 7639)
779
    self.assertHandler(rlib2.R_2_instances_name_failover)
780
    self.assertItems(["inst13579"])
781

    
782
    data = serializer.LoadJson(self.rapi.GetLastRequestData())
783
    self.assertFalse(data)
784

    
785
  def testFailoverInstance(self):
786
    for iallocator in ["dumb", "hail"]:
787
      for ignore_consistency in [False, True]:
788
        for target_node in ["node-a", "node2"]:
789
          self.rapi.AddResponse("19161")
790
          job_id = \
791
            self.client.FailoverInstance("inst251", iallocator=iallocator,
792
                                         ignore_consistency=ignore_consistency,
793
                                         target_node=target_node)
794
          self.assertEqual(job_id, 19161)
795
          self.assertHandler(rlib2.R_2_instances_name_failover)
796
          self.assertItems(["inst251"])
797

    
798
          data = serializer.LoadJson(self.rapi.GetLastRequestData())
799
          self.assertEqual(len(data), 3)
800
          self.assertEqual(data["iallocator"], iallocator)
801
          self.assertEqual(data["ignore_consistency"], ignore_consistency)
802
          self.assertEqual(data["target_node"], target_node)
803
          self.assertEqual(self.rapi.CountPending(), 0)
804

    
805
  def testRenameInstanceDefaults(self):
806
    new_name = "newnametha7euqu"
807
    self.rapi.AddResponse("8791")
808
    job_id = self.client.RenameInstance("inst18821", new_name)
809
    self.assertEqual(job_id, 8791)
810
    self.assertHandler(rlib2.R_2_instances_name_rename)
811
    self.assertItems(["inst18821"])
812

    
813
    data = serializer.LoadJson(self.rapi.GetLastRequestData())
814
    self.assertEqualValues(data, {"new_name": new_name, })
815

    
816
  def testRenameInstance(self):
817
    new_name = "new-name-yiux1iin"
818
    for ip_check in [False, True]:
819
      for name_check in [False, True]:
820
        self.rapi.AddResponse("24776")
821
        job_id = self.client.RenameInstance("inst20967", new_name,
822
                                             ip_check=ip_check,
823
                                             name_check=name_check)
824
        self.assertEqual(job_id, 24776)
825
        self.assertHandler(rlib2.R_2_instances_name_rename)
826
        self.assertItems(["inst20967"])
827

    
828
        data = serializer.LoadJson(self.rapi.GetLastRequestData())
829
        self.assertEqual(len(data), 3)
830
        self.assertEqual(data["new_name"], new_name)
831
        self.assertEqual(data["ip_check"], ip_check)
832
        self.assertEqual(data["name_check"], name_check)
833

    
834
  def testGetJobs(self):
835
    self.rapi.AddResponse('[ { "id": "123", "uri": "\\/2\\/jobs\\/123" },'
836
                          '  { "id": "124", "uri": "\\/2\\/jobs\\/124" } ]')
837
    self.assertEqual([123, 124], self.client.GetJobs())
838
    self.assertHandler(rlib2.R_2_jobs)
839

    
840
    self.rapi.AddResponse('[ { "id": "123", "uri": "\\/2\\/jobs\\/123" },'
841
                          '  { "id": "124", "uri": "\\/2\\/jobs\\/124" } ]')
842
    self.assertEqual([{"id": "123", "uri": "/2/jobs/123"},
843
                      {"id": "124", "uri": "/2/jobs/124"}],
844
                      self.client.GetJobs(bulk=True))
845
    self.assertHandler(rlib2.R_2_jobs)
846
    self.assertBulk()
847

    
848
  def testGetJobStatus(self):
849
    self.rapi.AddResponse("{\"foo\": \"bar\"}")
850
    self.assertEqual({"foo": "bar"}, self.client.GetJobStatus(1234))
851
    self.assertHandler(rlib2.R_2_jobs_id)
852
    self.assertItems(["1234"])
853

    
854
  def testWaitForJobChange(self):
855
    fields = ["id", "summary"]
856
    expected = {
857
      "job_info": [123, "something"],
858
      "log_entries": [],
859
      }
860

    
861
    self.rapi.AddResponse(serializer.DumpJson(expected))
862
    result = self.client.WaitForJobChange(123, fields, [], -1)
863
    self.assertEqualValues(expected, result)
864
    self.assertHandler(rlib2.R_2_jobs_id_wait)
865
    self.assertItems(["123"])
866

    
867
  def testCancelJob(self):
868
    self.rapi.AddResponse("[true, \"Job 123 will be canceled\"]")
869
    self.assertEqual([True, "Job 123 will be canceled"],
870
                     self.client.CancelJob(999, dry_run=True))
871
    self.assertHandler(rlib2.R_2_jobs_id)
872
    self.assertItems(["999"])
873
    self.assertDryRun()
874

    
875
  def testGetNodes(self):
876
    self.rapi.AddResponse("[ { \"id\": \"node1\", \"uri\": \"uri1\" },"
877
                          " { \"id\": \"node2\", \"uri\": \"uri2\" } ]")
878
    self.assertEqual(["node1", "node2"], self.client.GetNodes())
879
    self.assertHandler(rlib2.R_2_nodes)
880

    
881
    self.rapi.AddResponse("[ { \"id\": \"node1\", \"uri\": \"uri1\" },"
882
                          " { \"id\": \"node2\", \"uri\": \"uri2\" } ]")
883
    self.assertEqual([{"id": "node1", "uri": "uri1"},
884
                      {"id": "node2", "uri": "uri2"}],
885
                     self.client.GetNodes(bulk=True))
886
    self.assertHandler(rlib2.R_2_nodes)
887
    self.assertBulk()
888

    
889
  def testGetNode(self):
890
    self.rapi.AddResponse("{}")
891
    self.assertEqual({}, self.client.GetNode("node-foo"))
892
    self.assertHandler(rlib2.R_2_nodes_name)
893
    self.assertItems(["node-foo"])
894

    
895
  def testEvacuateNode(self):
896
    self.rapi.AddResponse(serializer.DumpJson([rlib2._NODE_EVAC_RES1]))
897
    self.rapi.AddResponse("9876")
898
    job_id = self.client.EvacuateNode("node-1", remote_node="node-2")
899
    self.assertEqual(9876, job_id)
900
    self.assertHandler(rlib2.R_2_nodes_name_evacuate)
901
    self.assertItems(["node-1"])
902
    self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
903
                     { "remote_node": "node-2", })
904
    self.assertEqual(self.rapi.CountPending(), 0)
905

    
906
    self.rapi.AddResponse(serializer.DumpJson([rlib2._NODE_EVAC_RES1]))
907
    self.rapi.AddResponse("8888")
908
    job_id = self.client.EvacuateNode("node-3", iallocator="hail", dry_run=True,
909
                                      mode=constants.NODE_EVAC_ALL,
910
                                      early_release=True)
911
    self.assertEqual(8888, job_id)
912
    self.assertItems(["node-3"])
913
    self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()), {
914
      "iallocator": "hail",
915
      "mode": "all",
916
      "early_release": True,
917
      })
918
    self.assertDryRun()
919

    
920
    self.assertRaises(client.GanetiApiError,
921
                      self.client.EvacuateNode,
922
                      "node-4", iallocator="hail", remote_node="node-5")
923
    self.assertEqual(self.rapi.CountPending(), 0)
924

    
925
  def testEvacuateNodeOldResponse(self):
926
    self.rapi.AddResponse(serializer.DumpJson([]))
927
    self.assertRaises(client.GanetiApiError, self.client.EvacuateNode,
928
                      "node-4", accept_old=False)
929
    self.assertEqual(self.rapi.CountPending(), 0)
930

    
931
    for mode in [client.NODE_EVAC_PRI, client.NODE_EVAC_ALL]:
932
      self.rapi.AddResponse(serializer.DumpJson([]))
933
      self.assertRaises(client.GanetiApiError, self.client.EvacuateNode,
934
                        "node-4", accept_old=True, mode=mode)
935
      self.assertEqual(self.rapi.CountPending(), 0)
936

    
937
    self.rapi.AddResponse(serializer.DumpJson([]))
938
    self.rapi.AddResponse(serializer.DumpJson("21533"))
939
    result = self.client.EvacuateNode("node-3", iallocator="hail",
940
                                      dry_run=True, accept_old=True,
941
                                      mode=client.NODE_EVAC_SEC,
942
                                      early_release=True)
943
    self.assertEqual(result, "21533")
944
    self.assertItems(["node-3"])
945
    self.assertQuery("iallocator", ["hail"])
946
    self.assertQuery("early_release", ["1"])
947
    self.assertFalse(self.rapi.GetLastRequestData())
948
    self.assertDryRun()
949
    self.assertEqual(self.rapi.CountPending(), 0)
950

    
951
  def testMigrateNode(self):
952
    self.rapi.AddResponse(serializer.DumpJson([]))
953
    self.rapi.AddResponse("1111")
954
    self.assertEqual(1111, self.client.MigrateNode("node-a", dry_run=True))
955
    self.assertHandler(rlib2.R_2_nodes_name_migrate)
956
    self.assertItems(["node-a"])
957
    self.assert_("mode" not in self.rapi.GetLastHandler().queryargs)
958
    self.assertDryRun()
959
    self.assertFalse(self.rapi.GetLastRequestData())
960

    
961
    self.rapi.AddResponse(serializer.DumpJson([]))
962
    self.rapi.AddResponse("1112")
963
    self.assertEqual(1112, self.client.MigrateNode("node-a", dry_run=True,
964
                                                   mode="live"))
965
    self.assertHandler(rlib2.R_2_nodes_name_migrate)
966
    self.assertItems(["node-a"])
967
    self.assertQuery("mode", ["live"])
968
    self.assertDryRun()
969
    self.assertFalse(self.rapi.GetLastRequestData())
970

    
971
    self.rapi.AddResponse(serializer.DumpJson([]))
972
    self.assertRaises(client.GanetiApiError, self.client.MigrateNode,
973
                      "node-c", target_node="foonode")
974
    self.assertEqual(self.rapi.CountPending(), 0)
975

    
976
  def testMigrateNodeBodyData(self):
977
    self.rapi.AddResponse(serializer.DumpJson([rlib2._NODE_MIGRATE_REQV1]))
978
    self.rapi.AddResponse("27539")
979
    self.assertEqual(27539, self.client.MigrateNode("node-a", dry_run=False,
980
                                                    mode="live"))
981
    self.assertHandler(rlib2.R_2_nodes_name_migrate)
982
    self.assertItems(["node-a"])
983
    self.assertFalse(self.rapi.GetLastHandler().queryargs)
984
    self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
985
                     { "mode": "live", })
986

    
987
    self.rapi.AddResponse(serializer.DumpJson([rlib2._NODE_MIGRATE_REQV1]))
988
    self.rapi.AddResponse("14219")
989
    self.assertEqual(14219, self.client.MigrateNode("node-x", dry_run=True,
990
                                                    target_node="node9",
991
                                                    iallocator="ial"))
992
    self.assertHandler(rlib2.R_2_nodes_name_migrate)
993
    self.assertItems(["node-x"])
994
    self.assertDryRun()
995
    self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
996
                     { "target_node": "node9", "iallocator": "ial", })
997

    
998
    self.assertEqual(self.rapi.CountPending(), 0)
999

    
1000
  def testGetNodeRole(self):
1001
    self.rapi.AddResponse("\"master\"")
1002
    self.assertEqual("master", self.client.GetNodeRole("node-a"))
1003
    self.assertHandler(rlib2.R_2_nodes_name_role)
1004
    self.assertItems(["node-a"])
1005

    
1006
  def testSetNodeRole(self):
1007
    self.rapi.AddResponse("789")
1008
    self.assertEqual(789,
1009
        self.client.SetNodeRole("node-foo", "master-candidate", force=True))
1010
    self.assertHandler(rlib2.R_2_nodes_name_role)
1011
    self.assertItems(["node-foo"])
1012
    self.assertQuery("force", ["1"])
1013
    self.assertEqual("\"master-candidate\"", self.rapi.GetLastRequestData())
1014

    
1015
  def testPowercycleNode(self):
1016
    self.rapi.AddResponse("23051")
1017
    self.assertEqual(23051,
1018
        self.client.PowercycleNode("node5468", force=True))
1019
    self.assertHandler(rlib2.R_2_nodes_name_powercycle)
1020
    self.assertItems(["node5468"])
1021
    self.assertQuery("force", ["1"])
1022
    self.assertFalse(self.rapi.GetLastRequestData())
1023
    self.assertEqual(self.rapi.CountPending(), 0)
1024

    
1025
  def testModifyNode(self):
1026
    self.rapi.AddResponse("3783")
1027
    job_id = self.client.ModifyNode("node16979.example.com", drained=True)
1028
    self.assertEqual(job_id, 3783)
1029
    self.assertHandler(rlib2.R_2_nodes_name_modify)
1030
    self.assertItems(["node16979.example.com"])
1031
    self.assertEqual(self.rapi.CountPending(), 0)
1032

    
1033
  def testGetNodeStorageUnits(self):
1034
    self.rapi.AddResponse("42")
1035
    self.assertEqual(42,
1036
        self.client.GetNodeStorageUnits("node-x", "lvm-pv", "fields"))
1037
    self.assertHandler(rlib2.R_2_nodes_name_storage)
1038
    self.assertItems(["node-x"])
1039
    self.assertQuery("storage_type", ["lvm-pv"])
1040
    self.assertQuery("output_fields", ["fields"])
1041

    
1042
  def testModifyNodeStorageUnits(self):
1043
    self.rapi.AddResponse("14")
1044
    self.assertEqual(14,
1045
        self.client.ModifyNodeStorageUnits("node-z", "lvm-pv", "hda"))
1046
    self.assertHandler(rlib2.R_2_nodes_name_storage_modify)
1047
    self.assertItems(["node-z"])
1048
    self.assertQuery("storage_type", ["lvm-pv"])
1049
    self.assertQuery("name", ["hda"])
1050
    self.assertQuery("allocatable", None)
1051

    
1052
    for allocatable, query_allocatable in [(True, "1"), (False, "0")]:
1053
      self.rapi.AddResponse("7205")
1054
      job_id = self.client.ModifyNodeStorageUnits("node-z", "lvm-pv", "hda",
1055
                                                  allocatable=allocatable)
1056
      self.assertEqual(7205, job_id)
1057
      self.assertHandler(rlib2.R_2_nodes_name_storage_modify)
1058
      self.assertItems(["node-z"])
1059
      self.assertQuery("storage_type", ["lvm-pv"])
1060
      self.assertQuery("name", ["hda"])
1061
      self.assertQuery("allocatable", [query_allocatable])
1062

    
1063
  def testRepairNodeStorageUnits(self):
1064
    self.rapi.AddResponse("99")
1065
    self.assertEqual(99, self.client.RepairNodeStorageUnits("node-z", "lvm-pv",
1066
                                                            "hda"))
1067
    self.assertHandler(rlib2.R_2_nodes_name_storage_repair)
1068
    self.assertItems(["node-z"])
1069
    self.assertQuery("storage_type", ["lvm-pv"])
1070
    self.assertQuery("name", ["hda"])
1071

    
1072
  def testGetNodeTags(self):
1073
    self.rapi.AddResponse("[\"fry\", \"bender\"]")
1074
    self.assertEqual(["fry", "bender"], self.client.GetNodeTags("node-k"))
1075
    self.assertHandler(rlib2.R_2_nodes_name_tags)
1076
    self.assertItems(["node-k"])
1077

    
1078
  def testAddNodeTags(self):
1079
    self.rapi.AddResponse("1234")
1080
    self.assertEqual(1234,
1081
        self.client.AddNodeTags("node-v", ["awesome"], dry_run=True))
1082
    self.assertHandler(rlib2.R_2_nodes_name_tags)
1083
    self.assertItems(["node-v"])
1084
    self.assertDryRun()
1085
    self.assertQuery("tag", ["awesome"])
1086

    
1087
  def testDeleteNodeTags(self):
1088
    self.rapi.AddResponse("16861")
1089
    self.assertEqual(16861, self.client.DeleteNodeTags("node-w", ["awesome"],
1090
                                                       dry_run=True))
1091
    self.assertHandler(rlib2.R_2_nodes_name_tags)
1092
    self.assertItems(["node-w"])
1093
    self.assertDryRun()
1094
    self.assertQuery("tag", ["awesome"])
1095

    
1096
  def testGetGroups(self):
1097
    groups = [{"name": "group1",
1098
               "uri": "/2/groups/group1",
1099
               },
1100
              {"name": "group2",
1101
               "uri": "/2/groups/group2",
1102
               },
1103
              ]
1104
    self.rapi.AddResponse(serializer.DumpJson(groups))
1105
    self.assertEqual(["group1", "group2"], self.client.GetGroups())
1106
    self.assertHandler(rlib2.R_2_groups)
1107

    
1108
  def testGetGroupsBulk(self):
1109
    groups = [{"name": "group1",
1110
               "uri": "/2/groups/group1",
1111
               "node_cnt": 2,
1112
               "node_list": ["gnt1.test",
1113
                             "gnt2.test",
1114
                             ],
1115
               },
1116
              {"name": "group2",
1117
               "uri": "/2/groups/group2",
1118
               "node_cnt": 1,
1119
               "node_list": ["gnt3.test",
1120
                             ],
1121
               },
1122
              ]
1123
    self.rapi.AddResponse(serializer.DumpJson(groups))
1124

    
1125
    self.assertEqual(groups, self.client.GetGroups(bulk=True))
1126
    self.assertHandler(rlib2.R_2_groups)
1127
    self.assertBulk()
1128

    
1129
  def testGetGroup(self):
1130
    group = {"ctime": None,
1131
             "name": "default",
1132
             }
1133
    self.rapi.AddResponse(serializer.DumpJson(group))
1134
    self.assertEqual({"ctime": None, "name": "default"},
1135
                     self.client.GetGroup("default"))
1136
    self.assertHandler(rlib2.R_2_groups_name)
1137
    self.assertItems(["default"])
1138

    
1139
  def testCreateGroup(self):
1140
    self.rapi.AddResponse("12345")
1141
    job_id = self.client.CreateGroup("newgroup", dry_run=True)
1142
    self.assertEqual(job_id, 12345)
1143
    self.assertHandler(rlib2.R_2_groups)
1144
    self.assertDryRun()
1145

    
1146
  def testDeleteGroup(self):
1147
    self.rapi.AddResponse("12346")
1148
    job_id = self.client.DeleteGroup("newgroup", dry_run=True)
1149
    self.assertEqual(job_id, 12346)
1150
    self.assertHandler(rlib2.R_2_groups_name)
1151
    self.assertDryRun()
1152

    
1153
  def testRenameGroup(self):
1154
    self.rapi.AddResponse("12347")
1155
    job_id = self.client.RenameGroup("oldname", "newname")
1156
    self.assertEqual(job_id, 12347)
1157
    self.assertHandler(rlib2.R_2_groups_name_rename)
1158

    
1159
  def testModifyGroup(self):
1160
    self.rapi.AddResponse("12348")
1161
    job_id = self.client.ModifyGroup("mygroup", alloc_policy="foo")
1162
    self.assertEqual(job_id, 12348)
1163
    self.assertHandler(rlib2.R_2_groups_name_modify)
1164

    
1165
  def testAssignGroupNodes(self):
1166
    self.rapi.AddResponse("12349")
1167
    job_id = self.client.AssignGroupNodes("mygroup", ["node1", "node2"],
1168
                                          force=True, dry_run=True)
1169
    self.assertEqual(job_id, 12349)
1170
    self.assertHandler(rlib2.R_2_groups_name_assign_nodes)
1171
    self.assertDryRun()
1172
    self.assertUseForce()
1173

    
1174
  def testGetNetworksBulk(self):
1175
    networks = [{"name": "network1",
1176
               "uri": "/2/networks/network1",
1177
               "network": "192.168.0.0/24",
1178
               },
1179
              {"name": "network2",
1180
               "uri": "/2/networks/network2",
1181
               "network": "192.168.0.0/24",
1182
               },
1183
              ]
1184
    self.rapi.AddResponse(serializer.DumpJson(networks))
1185

    
1186
    self.assertEqual(networks, self.client.GetNetworks(bulk=True))
1187
    self.assertHandler(rlib2.R_2_networks)
1188
    self.assertBulk()
1189

    
1190
  def testGetNetwork(self):
1191
    network = {"ctime": None,
1192
               "name": "network1",
1193
               }
1194
    self.rapi.AddResponse(serializer.DumpJson(network))
1195
    self.assertEqual({"ctime": None, "name": "network1"},
1196
                     self.client.GetNetwork("network1"))
1197
    self.assertHandler(rlib2.R_2_networks_name)
1198
    self.assertItems(["network1"])
1199

    
1200
  def testCreateNetwork(self):
1201
    self.rapi.AddResponse("12345")
1202
    job_id = self.client.CreateNetwork("newnetwork", network="192.168.0.0/24",
1203
                                       dry_run=True)
1204
    self.assertEqual(job_id, 12345)
1205
    self.assertHandler(rlib2.R_2_networks)
1206
    self.assertDryRun()
1207

    
1208
  def testModifyNetwork(self):
1209
    self.rapi.AddResponse("12346")
1210
    job_id = self.client.ModifyNetwork("mynetwork", gateway="192.168.0.10",
1211
                                     dry_run=True)
1212
    self.assertEqual(job_id, 12346)
1213
    self.assertHandler(rlib2.R_2_networks_name_modify)
1214

    
1215
  def testDeleteNetwork(self):
1216
    self.rapi.AddResponse("12347")
1217
    job_id = self.client.DeleteNetwork("newnetwork", dry_run=True)
1218
    self.assertEqual(job_id, 12347)
1219
    self.assertHandler(rlib2.R_2_networks_name)
1220
    self.assertDryRun()
1221

    
1222
  def testConnectNetwork(self):
1223
    self.rapi.AddResponse("12348")
1224
    job_id = self.client.ConnectNetwork("mynetwork", "default",
1225
                                        "bridged", "br0", dry_run=True)
1226
    self.assertEqual(job_id, 12348)
1227
    self.assertHandler(rlib2.R_2_networks_name_connect)
1228
    self.assertDryRun()
1229

    
1230
  def testDisconnectNetwork(self):
1231
    self.rapi.AddResponse("12349")
1232
    job_id = self.client.DisconnectNetwork("mynetwork", "default", dry_run=True)
1233
    self.assertEqual(job_id, 12349)
1234
    self.assertHandler(rlib2.R_2_networks_name_disconnect)
1235
    self.assertDryRun()
1236

    
1237
  def testGetNetworkTags(self):
1238
    self.rapi.AddResponse("[]")
1239
    self.assertEqual([], self.client.GetNetworkTags("fooNetwork"))
1240
    self.assertHandler(rlib2.R_2_networks_name_tags)
1241
    self.assertItems(["fooNetwork"])
1242

    
1243
  def testAddNetworkTags(self):
1244
    self.rapi.AddResponse("1234")
1245
    self.assertEqual(1234,
1246
        self.client.AddNetworkTags("fooNetwork", ["awesome"], dry_run=True))
1247
    self.assertHandler(rlib2.R_2_networks_name_tags)
1248
    self.assertItems(["fooNetwork"])
1249
    self.assertDryRun()
1250
    self.assertQuery("tag", ["awesome"])
1251

    
1252
  def testDeleteNetworkTags(self):
1253
    self.rapi.AddResponse("25826")
1254
    self.assertEqual(25826, self.client.DeleteNetworkTags("foo", ["awesome"],
1255
                                                          dry_run=True))
1256
    self.assertHandler(rlib2.R_2_networks_name_tags)
1257
    self.assertItems(["foo"])
1258
    self.assertDryRun()
1259
    self.assertQuery("tag", ["awesome"])
1260

    
1261
  def testModifyInstance(self):
1262
    self.rapi.AddResponse("23681")
1263
    job_id = self.client.ModifyInstance("inst7210", os_name="linux")
1264
    self.assertEqual(job_id, 23681)
1265
    self.assertItems(["inst7210"])
1266
    self.assertHandler(rlib2.R_2_instances_name_modify)
1267
    self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
1268
                     { "os_name": "linux", })
1269

    
1270
  def testSnapshotInstance(self):
1271
    self.rapi.AddResponse("23681")
1272
    snap = [0, {"snapshot_name": "snap1"}]
1273
    job_id = self.client.SnapshotInstance("inst7210", disks=[snap])
1274
    self.assertEqual(job_id, 23681)
1275
    self.assertItems(["inst7210"])
1276
    self.assertHandler(rlib2.R_2_instances_name_snapshot)
1277
    self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
1278
                     {"disks": [snap]})
1279

    
1280
  def testModifyCluster(self):
1281
    for mnh in [None, False, True]:
1282
      self.rapi.AddResponse("14470")
1283
      self.assertEqual(14470,
1284
        self.client.ModifyCluster(maintain_node_health=mnh))
1285
      self.assertHandler(rlib2.R_2_cluster_modify)
1286
      self.assertItems([])
1287
      data = serializer.LoadJson(self.rapi.GetLastRequestData())
1288
      self.assertEqual(len(data), 1)
1289
      self.assertEqual(data["maintain_node_health"], mnh)
1290
      self.assertEqual(self.rapi.CountPending(), 0)
1291

    
1292
  def testRedistributeConfig(self):
1293
    self.rapi.AddResponse("3364")
1294
    job_id = self.client.RedistributeConfig()
1295
    self.assertEqual(job_id, 3364)
1296
    self.assertItems([])
1297
    self.assertHandler(rlib2.R_2_redist_config)
1298

    
1299
  def testActivateInstanceDisks(self):
1300
    self.rapi.AddResponse("23547")
1301
    job_id = self.client.ActivateInstanceDisks("inst28204")
1302
    self.assertEqual(job_id, 23547)
1303
    self.assertItems(["inst28204"])
1304
    self.assertHandler(rlib2.R_2_instances_name_activate_disks)
1305
    self.assertFalse(self.rapi.GetLastHandler().queryargs)
1306

    
1307
  def testActivateInstanceDisksIgnoreSize(self):
1308
    self.rapi.AddResponse("11044")
1309
    job_id = self.client.ActivateInstanceDisks("inst28204", ignore_size=True)
1310
    self.assertEqual(job_id, 11044)
1311
    self.assertItems(["inst28204"])
1312
    self.assertHandler(rlib2.R_2_instances_name_activate_disks)
1313
    self.assertQuery("ignore_size", ["1"])
1314

    
1315
  def testDeactivateInstanceDisks(self):
1316
    self.rapi.AddResponse("14591")
1317
    job_id = self.client.DeactivateInstanceDisks("inst28234")
1318
    self.assertEqual(job_id, 14591)
1319
    self.assertItems(["inst28234"])
1320
    self.assertHandler(rlib2.R_2_instances_name_deactivate_disks)
1321
    self.assertFalse(self.rapi.GetLastHandler().queryargs)
1322

    
1323
  def testRecreateInstanceDisks(self):
1324
    self.rapi.AddResponse("13553")
1325
    job_id = self.client.RecreateInstanceDisks("inst23153")
1326
    self.assertEqual(job_id, 13553)
1327
    self.assertItems(["inst23153"])
1328
    self.assertHandler(rlib2.R_2_instances_name_recreate_disks)
1329
    self.assertFalse(self.rapi.GetLastHandler().queryargs)
1330

    
1331
  def testGetInstanceConsole(self):
1332
    self.rapi.AddResponse("26876")
1333
    job_id = self.client.GetInstanceConsole("inst21491")
1334
    self.assertEqual(job_id, 26876)
1335
    self.assertItems(["inst21491"])
1336
    self.assertHandler(rlib2.R_2_instances_name_console)
1337
    self.assertFalse(self.rapi.GetLastHandler().queryargs)
1338
    self.assertFalse(self.rapi.GetLastRequestData())
1339

    
1340
  def testGrowInstanceDisk(self):
1341
    for idx, wait_for_sync in enumerate([None, False, True]):
1342
      amount = 128 + (512 * idx)
1343
      self.assertEqual(self.rapi.CountPending(), 0)
1344
      self.rapi.AddResponse("30783")
1345
      self.assertEqual(30783,
1346
        self.client.GrowInstanceDisk("eze8ch", idx, amount,
1347
                                     wait_for_sync=wait_for_sync))
1348
      self.assertHandler(rlib2.R_2_instances_name_disk_grow)
1349
      self.assertItems(["eze8ch", str(idx)])
1350
      data = serializer.LoadJson(self.rapi.GetLastRequestData())
1351
      if wait_for_sync is None:
1352
        self.assertEqual(len(data), 1)
1353
        self.assert_("wait_for_sync" not in data)
1354
      else:
1355
        self.assertEqual(len(data), 2)
1356
        self.assertEqual(data["wait_for_sync"], wait_for_sync)
1357
      self.assertEqual(data["amount"], amount)
1358
      self.assertEqual(self.rapi.CountPending(), 0)
1359

    
1360
  def testGetGroupTags(self):
1361
    self.rapi.AddResponse("[]")
1362
    self.assertEqual([], self.client.GetGroupTags("fooGroup"))
1363
    self.assertHandler(rlib2.R_2_groups_name_tags)
1364
    self.assertItems(["fooGroup"])
1365

    
1366
  def testAddGroupTags(self):
1367
    self.rapi.AddResponse("1234")
1368
    self.assertEqual(1234,
1369
        self.client.AddGroupTags("fooGroup", ["awesome"], dry_run=True))
1370
    self.assertHandler(rlib2.R_2_groups_name_tags)
1371
    self.assertItems(["fooGroup"])
1372
    self.assertDryRun()
1373
    self.assertQuery("tag", ["awesome"])
1374

    
1375
  def testDeleteGroupTags(self):
1376
    self.rapi.AddResponse("25826")
1377
    self.assertEqual(25826, self.client.DeleteGroupTags("foo", ["awesome"],
1378
                                                        dry_run=True))
1379
    self.assertHandler(rlib2.R_2_groups_name_tags)
1380
    self.assertItems(["foo"])
1381
    self.assertDryRun()
1382
    self.assertQuery("tag", ["awesome"])
1383

    
1384
  def testQuery(self):
1385
    for idx, what in enumerate(constants.QR_VIA_RAPI):
1386
      for idx2, qfilter in enumerate([None, ["?", "name"]]):
1387
        job_id = 11010 + (idx << 4) + (idx2 << 16)
1388
        fields = sorted(query.ALL_FIELDS[what].keys())[:10]
1389

    
1390
        self.rapi.AddResponse(str(job_id))
1391
        self.assertEqual(self.client.Query(what, fields, qfilter=qfilter),
1392
                         job_id)
1393
        self.assertItems([what])
1394
        self.assertHandler(rlib2.R_2_query)
1395
        self.assertFalse(self.rapi.GetLastHandler().queryargs)
1396
        data = serializer.LoadJson(self.rapi.GetLastRequestData())
1397
        self.assertEqual(data["fields"], fields)
1398
        if qfilter is None:
1399
          self.assertTrue("qfilter" not in data)
1400
        else:
1401
          self.assertEqual(data["qfilter"], qfilter)
1402
        self.assertEqual(self.rapi.CountPending(), 0)
1403

    
1404
  def testQueryFields(self):
1405
    exp_result = objects.QueryFieldsResponse(fields=[
1406
      objects.QueryFieldDefinition(name="pnode", title="PNode",
1407
                                   kind=constants.QFT_NUMBER),
1408
      objects.QueryFieldDefinition(name="other", title="Other",
1409
                                   kind=constants.QFT_BOOL),
1410
      ])
1411

    
1412
    for what in constants.QR_VIA_RAPI:
1413
      for fields in [None, ["name", "_unknown_"], ["&", "?|"]]:
1414
        self.rapi.AddResponse(serializer.DumpJson(exp_result.ToDict()))
1415
        result = self.client.QueryFields(what, fields=fields)
1416
        self.assertItems([what])
1417
        self.assertHandler(rlib2.R_2_query_fields)
1418
        self.assertFalse(self.rapi.GetLastRequestData())
1419

    
1420
        queryargs = self.rapi.GetLastHandler().queryargs
1421
        if fields is None:
1422
          self.assertFalse(queryargs)
1423
        else:
1424
          self.assertEqual(queryargs, {
1425
            "fields": [",".join(fields)],
1426
            })
1427

    
1428
        self.assertEqual(objects.QueryFieldsResponse.FromDict(result).ToDict(),
1429
                         exp_result.ToDict())
1430

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

    
1433
  def testWaitForJobCompletionNoChange(self):
1434
    resp = serializer.DumpJson({
1435
      "status": constants.JOB_STATUS_WAITING,
1436
      })
1437

    
1438
    for retries in [1, 5, 25]:
1439
      for _ in range(retries):
1440
        self.rapi.AddResponse(resp)
1441

    
1442
      self.assertFalse(self.client.WaitForJobCompletion(22789, period=None,
1443
                                                        retries=retries))
1444
      self.assertHandler(rlib2.R_2_jobs_id)
1445
      self.assertItems(["22789"])
1446

    
1447
      self.assertEqual(self.rapi.CountPending(), 0)
1448

    
1449
  def testWaitForJobCompletionAlreadyFinished(self):
1450
    self.rapi.AddResponse(serializer.DumpJson({
1451
      "status": constants.JOB_STATUS_SUCCESS,
1452
      }))
1453

    
1454
    self.assertTrue(self.client.WaitForJobCompletion(22793, period=None,
1455
                                                     retries=1))
1456
    self.assertHandler(rlib2.R_2_jobs_id)
1457
    self.assertItems(["22793"])
1458

    
1459
    self.assertEqual(self.rapi.CountPending(), 0)
1460

    
1461
  def testWaitForJobCompletionEmptyResponse(self):
1462
    self.rapi.AddResponse("{}")
1463
    self.assertFalse(self.client.WaitForJobCompletion(22793, period=None,
1464
                                                     retries=10))
1465
    self.assertHandler(rlib2.R_2_jobs_id)
1466
    self.assertItems(["22793"])
1467

    
1468
    self.assertEqual(self.rapi.CountPending(), 0)
1469

    
1470
  def testWaitForJobCompletionOutOfRetries(self):
1471
    for retries in [3, 10, 21]:
1472
      for _ in range(retries):
1473
        self.rapi.AddResponse(serializer.DumpJson({
1474
          "status": constants.JOB_STATUS_RUNNING,
1475
          }))
1476

    
1477
      self.assertFalse(self.client.WaitForJobCompletion(30948, period=None,
1478
                                                        retries=retries - 1))
1479
      self.assertHandler(rlib2.R_2_jobs_id)
1480
      self.assertItems(["30948"])
1481

    
1482
      self.assertEqual(self.rapi.CountPending(), 1)
1483
      self.rapi.ResetResponses()
1484

    
1485
  def testWaitForJobCompletionSuccessAndFailure(self):
1486
    for retries in [1, 4, 13]:
1487
      for (success, end_status) in [(False, constants.JOB_STATUS_ERROR),
1488
                                    (True, constants.JOB_STATUS_SUCCESS)]:
1489
        for _ in range(retries):
1490
          self.rapi.AddResponse(serializer.DumpJson({
1491
            "status": constants.JOB_STATUS_RUNNING,
1492
            }))
1493

    
1494
        self.rapi.AddResponse(serializer.DumpJson({
1495
          "status": end_status,
1496
          }))
1497

    
1498
        result = self.client.WaitForJobCompletion(3187, period=None,
1499
                                                  retries=retries + 1)
1500
        self.assertEqual(result, success)
1501
        self.assertHandler(rlib2.R_2_jobs_id)
1502
        self.assertItems(["3187"])
1503

    
1504
        self.assertEqual(self.rapi.CountPending(), 0)
1505

    
1506

    
1507
class RapiTestRunner(unittest.TextTestRunner):
1508
  def run(self, *args):
1509
    global _used_handlers
1510
    assert _used_handlers is None
1511

    
1512
    _used_handlers = set()
1513
    try:
1514
      # Run actual tests
1515
      result = unittest.TextTestRunner.run(self, *args)
1516

    
1517
      diff = (set(connector.CONNECTOR.values()) - _used_handlers -
1518
             _KNOWN_UNUSED)
1519
      if diff:
1520
        raise AssertionError("The following RAPI resources were not used by the"
1521
                             " RAPI client: %r" % utils.CommaJoin(diff))
1522
    finally:
1523
      # Reset global variable
1524
      _used_handlers = None
1525

    
1526
    return result
1527

    
1528

    
1529
if __name__ == "__main__":
1530
  client.UsesRapiClient(testutils.GanetiTestProgram)(testRunner=RapiTestRunner)