Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (57.3 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
  def testGetJobStatus(self):
841
    self.rapi.AddResponse("{\"foo\": \"bar\"}")
842
    self.assertEqual({"foo": "bar"}, self.client.GetJobStatus(1234))
843
    self.assertHandler(rlib2.R_2_jobs_id)
844
    self.assertItems(["1234"])
845

    
846
  def testWaitForJobChange(self):
847
    fields = ["id", "summary"]
848
    expected = {
849
      "job_info": [123, "something"],
850
      "log_entries": [],
851
      }
852

    
853
    self.rapi.AddResponse(serializer.DumpJson(expected))
854
    result = self.client.WaitForJobChange(123, fields, [], -1)
855
    self.assertEqualValues(expected, result)
856
    self.assertHandler(rlib2.R_2_jobs_id_wait)
857
    self.assertItems(["123"])
858

    
859
  def testCancelJob(self):
860
    self.rapi.AddResponse("[true, \"Job 123 will be canceled\"]")
861
    self.assertEqual([True, "Job 123 will be canceled"],
862
                     self.client.CancelJob(999, dry_run=True))
863
    self.assertHandler(rlib2.R_2_jobs_id)
864
    self.assertItems(["999"])
865
    self.assertDryRun()
866

    
867
  def testGetNodes(self):
868
    self.rapi.AddResponse("[ { \"id\": \"node1\", \"uri\": \"uri1\" },"
869
                          " { \"id\": \"node2\", \"uri\": \"uri2\" } ]")
870
    self.assertEqual(["node1", "node2"], self.client.GetNodes())
871
    self.assertHandler(rlib2.R_2_nodes)
872

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

    
881
  def testGetNode(self):
882
    self.rapi.AddResponse("{}")
883
    self.assertEqual({}, self.client.GetNode("node-foo"))
884
    self.assertHandler(rlib2.R_2_nodes_name)
885
    self.assertItems(["node-foo"])
886

    
887
  def testEvacuateNode(self):
888
    self.rapi.AddResponse(serializer.DumpJson([rlib2._NODE_EVAC_RES1]))
889
    self.rapi.AddResponse("9876")
890
    job_id = self.client.EvacuateNode("node-1", remote_node="node-2")
891
    self.assertEqual(9876, job_id)
892
    self.assertHandler(rlib2.R_2_nodes_name_evacuate)
893
    self.assertItems(["node-1"])
894
    self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
895
                     { "remote_node": "node-2", })
896
    self.assertEqual(self.rapi.CountPending(), 0)
897

    
898
    self.rapi.AddResponse(serializer.DumpJson([rlib2._NODE_EVAC_RES1]))
899
    self.rapi.AddResponse("8888")
900
    job_id = self.client.EvacuateNode("node-3", iallocator="hail", dry_run=True,
901
                                      mode=constants.NODE_EVAC_ALL,
902
                                      early_release=True)
903
    self.assertEqual(8888, job_id)
904
    self.assertItems(["node-3"])
905
    self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()), {
906
      "iallocator": "hail",
907
      "mode": "all",
908
      "early_release": True,
909
      })
910
    self.assertDryRun()
911

    
912
    self.assertRaises(client.GanetiApiError,
913
                      self.client.EvacuateNode,
914
                      "node-4", iallocator="hail", remote_node="node-5")
915
    self.assertEqual(self.rapi.CountPending(), 0)
916

    
917
  def testEvacuateNodeOldResponse(self):
918
    self.rapi.AddResponse(serializer.DumpJson([]))
919
    self.assertRaises(client.GanetiApiError, self.client.EvacuateNode,
920
                      "node-4", accept_old=False)
921
    self.assertEqual(self.rapi.CountPending(), 0)
922

    
923
    for mode in [client.NODE_EVAC_PRI, client.NODE_EVAC_ALL]:
924
      self.rapi.AddResponse(serializer.DumpJson([]))
925
      self.assertRaises(client.GanetiApiError, self.client.EvacuateNode,
926
                        "node-4", accept_old=True, mode=mode)
927
      self.assertEqual(self.rapi.CountPending(), 0)
928

    
929
    self.rapi.AddResponse(serializer.DumpJson([]))
930
    self.rapi.AddResponse(serializer.DumpJson("21533"))
931
    result = self.client.EvacuateNode("node-3", iallocator="hail",
932
                                      dry_run=True, accept_old=True,
933
                                      mode=client.NODE_EVAC_SEC,
934
                                      early_release=True)
935
    self.assertEqual(result, "21533")
936
    self.assertItems(["node-3"])
937
    self.assertQuery("iallocator", ["hail"])
938
    self.assertQuery("early_release", ["1"])
939
    self.assertFalse(self.rapi.GetLastRequestData())
940
    self.assertDryRun()
941
    self.assertEqual(self.rapi.CountPending(), 0)
942

    
943
  def testMigrateNode(self):
944
    self.rapi.AddResponse(serializer.DumpJson([]))
945
    self.rapi.AddResponse("1111")
946
    self.assertEqual(1111, self.client.MigrateNode("node-a", dry_run=True))
947
    self.assertHandler(rlib2.R_2_nodes_name_migrate)
948
    self.assertItems(["node-a"])
949
    self.assert_("mode" not in self.rapi.GetLastHandler().queryargs)
950
    self.assertDryRun()
951
    self.assertFalse(self.rapi.GetLastRequestData())
952

    
953
    self.rapi.AddResponse(serializer.DumpJson([]))
954
    self.rapi.AddResponse("1112")
955
    self.assertEqual(1112, self.client.MigrateNode("node-a", dry_run=True,
956
                                                   mode="live"))
957
    self.assertHandler(rlib2.R_2_nodes_name_migrate)
958
    self.assertItems(["node-a"])
959
    self.assertQuery("mode", ["live"])
960
    self.assertDryRun()
961
    self.assertFalse(self.rapi.GetLastRequestData())
962

    
963
    self.rapi.AddResponse(serializer.DumpJson([]))
964
    self.assertRaises(client.GanetiApiError, self.client.MigrateNode,
965
                      "node-c", target_node="foonode")
966
    self.assertEqual(self.rapi.CountPending(), 0)
967

    
968
  def testMigrateNodeBodyData(self):
969
    self.rapi.AddResponse(serializer.DumpJson([rlib2._NODE_MIGRATE_REQV1]))
970
    self.rapi.AddResponse("27539")
971
    self.assertEqual(27539, self.client.MigrateNode("node-a", dry_run=False,
972
                                                    mode="live"))
973
    self.assertHandler(rlib2.R_2_nodes_name_migrate)
974
    self.assertItems(["node-a"])
975
    self.assertFalse(self.rapi.GetLastHandler().queryargs)
976
    self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
977
                     { "mode": "live", })
978

    
979
    self.rapi.AddResponse(serializer.DumpJson([rlib2._NODE_MIGRATE_REQV1]))
980
    self.rapi.AddResponse("14219")
981
    self.assertEqual(14219, self.client.MigrateNode("node-x", dry_run=True,
982
                                                    target_node="node9",
983
                                                    iallocator="ial"))
984
    self.assertHandler(rlib2.R_2_nodes_name_migrate)
985
    self.assertItems(["node-x"])
986
    self.assertDryRun()
987
    self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
988
                     { "target_node": "node9", "iallocator": "ial", })
989

    
990
    self.assertEqual(self.rapi.CountPending(), 0)
991

    
992
  def testGetNodeRole(self):
993
    self.rapi.AddResponse("\"master\"")
994
    self.assertEqual("master", self.client.GetNodeRole("node-a"))
995
    self.assertHandler(rlib2.R_2_nodes_name_role)
996
    self.assertItems(["node-a"])
997

    
998
  def testSetNodeRole(self):
999
    self.rapi.AddResponse("789")
1000
    self.assertEqual(789,
1001
        self.client.SetNodeRole("node-foo", "master-candidate", force=True))
1002
    self.assertHandler(rlib2.R_2_nodes_name_role)
1003
    self.assertItems(["node-foo"])
1004
    self.assertQuery("force", ["1"])
1005
    self.assertEqual("\"master-candidate\"", self.rapi.GetLastRequestData())
1006

    
1007
  def testPowercycleNode(self):
1008
    self.rapi.AddResponse("23051")
1009
    self.assertEqual(23051,
1010
        self.client.PowercycleNode("node5468", force=True))
1011
    self.assertHandler(rlib2.R_2_nodes_name_powercycle)
1012
    self.assertItems(["node5468"])
1013
    self.assertQuery("force", ["1"])
1014
    self.assertFalse(self.rapi.GetLastRequestData())
1015
    self.assertEqual(self.rapi.CountPending(), 0)
1016

    
1017
  def testModifyNode(self):
1018
    self.rapi.AddResponse("3783")
1019
    job_id = self.client.ModifyNode("node16979.example.com", drained=True)
1020
    self.assertEqual(job_id, 3783)
1021
    self.assertHandler(rlib2.R_2_nodes_name_modify)
1022
    self.assertItems(["node16979.example.com"])
1023
    self.assertEqual(self.rapi.CountPending(), 0)
1024

    
1025
  def testGetNodeStorageUnits(self):
1026
    self.rapi.AddResponse("42")
1027
    self.assertEqual(42,
1028
        self.client.GetNodeStorageUnits("node-x", "lvm-pv", "fields"))
1029
    self.assertHandler(rlib2.R_2_nodes_name_storage)
1030
    self.assertItems(["node-x"])
1031
    self.assertQuery("storage_type", ["lvm-pv"])
1032
    self.assertQuery("output_fields", ["fields"])
1033

    
1034
  def testModifyNodeStorageUnits(self):
1035
    self.rapi.AddResponse("14")
1036
    self.assertEqual(14,
1037
        self.client.ModifyNodeStorageUnits("node-z", "lvm-pv", "hda"))
1038
    self.assertHandler(rlib2.R_2_nodes_name_storage_modify)
1039
    self.assertItems(["node-z"])
1040
    self.assertQuery("storage_type", ["lvm-pv"])
1041
    self.assertQuery("name", ["hda"])
1042
    self.assertQuery("allocatable", None)
1043

    
1044
    for allocatable, query_allocatable in [(True, "1"), (False, "0")]:
1045
      self.rapi.AddResponse("7205")
1046
      job_id = self.client.ModifyNodeStorageUnits("node-z", "lvm-pv", "hda",
1047
                                                  allocatable=allocatable)
1048
      self.assertEqual(7205, job_id)
1049
      self.assertHandler(rlib2.R_2_nodes_name_storage_modify)
1050
      self.assertItems(["node-z"])
1051
      self.assertQuery("storage_type", ["lvm-pv"])
1052
      self.assertQuery("name", ["hda"])
1053
      self.assertQuery("allocatable", [query_allocatable])
1054

    
1055
  def testRepairNodeStorageUnits(self):
1056
    self.rapi.AddResponse("99")
1057
    self.assertEqual(99, self.client.RepairNodeStorageUnits("node-z", "lvm-pv",
1058
                                                            "hda"))
1059
    self.assertHandler(rlib2.R_2_nodes_name_storage_repair)
1060
    self.assertItems(["node-z"])
1061
    self.assertQuery("storage_type", ["lvm-pv"])
1062
    self.assertQuery("name", ["hda"])
1063

    
1064
  def testGetNodeTags(self):
1065
    self.rapi.AddResponse("[\"fry\", \"bender\"]")
1066
    self.assertEqual(["fry", "bender"], self.client.GetNodeTags("node-k"))
1067
    self.assertHandler(rlib2.R_2_nodes_name_tags)
1068
    self.assertItems(["node-k"])
1069

    
1070
  def testAddNodeTags(self):
1071
    self.rapi.AddResponse("1234")
1072
    self.assertEqual(1234,
1073
        self.client.AddNodeTags("node-v", ["awesome"], dry_run=True))
1074
    self.assertHandler(rlib2.R_2_nodes_name_tags)
1075
    self.assertItems(["node-v"])
1076
    self.assertDryRun()
1077
    self.assertQuery("tag", ["awesome"])
1078

    
1079
  def testDeleteNodeTags(self):
1080
    self.rapi.AddResponse("16861")
1081
    self.assertEqual(16861, self.client.DeleteNodeTags("node-w", ["awesome"],
1082
                                                       dry_run=True))
1083
    self.assertHandler(rlib2.R_2_nodes_name_tags)
1084
    self.assertItems(["node-w"])
1085
    self.assertDryRun()
1086
    self.assertQuery("tag", ["awesome"])
1087

    
1088
  def testGetGroups(self):
1089
    groups = [{"name": "group1",
1090
               "uri": "/2/groups/group1",
1091
               },
1092
              {"name": "group2",
1093
               "uri": "/2/groups/group2",
1094
               },
1095
              ]
1096
    self.rapi.AddResponse(serializer.DumpJson(groups))
1097
    self.assertEqual(["group1", "group2"], self.client.GetGroups())
1098
    self.assertHandler(rlib2.R_2_groups)
1099

    
1100
  def testGetGroupsBulk(self):
1101
    groups = [{"name": "group1",
1102
               "uri": "/2/groups/group1",
1103
               "node_cnt": 2,
1104
               "node_list": ["gnt1.test",
1105
                             "gnt2.test",
1106
                             ],
1107
               },
1108
              {"name": "group2",
1109
               "uri": "/2/groups/group2",
1110
               "node_cnt": 1,
1111
               "node_list": ["gnt3.test",
1112
                             ],
1113
               },
1114
              ]
1115
    self.rapi.AddResponse(serializer.DumpJson(groups))
1116

    
1117
    self.assertEqual(groups, self.client.GetGroups(bulk=True))
1118
    self.assertHandler(rlib2.R_2_groups)
1119
    self.assertBulk()
1120

    
1121
  def testGetGroup(self):
1122
    group = {"ctime": None,
1123
             "name": "default",
1124
             }
1125
    self.rapi.AddResponse(serializer.DumpJson(group))
1126
    self.assertEqual({"ctime": None, "name": "default"},
1127
                     self.client.GetGroup("default"))
1128
    self.assertHandler(rlib2.R_2_groups_name)
1129
    self.assertItems(["default"])
1130

    
1131
  def testCreateGroup(self):
1132
    self.rapi.AddResponse("12345")
1133
    job_id = self.client.CreateGroup("newgroup", dry_run=True)
1134
    self.assertEqual(job_id, 12345)
1135
    self.assertHandler(rlib2.R_2_groups)
1136
    self.assertDryRun()
1137

    
1138
  def testDeleteGroup(self):
1139
    self.rapi.AddResponse("12346")
1140
    job_id = self.client.DeleteGroup("newgroup", dry_run=True)
1141
    self.assertEqual(job_id, 12346)
1142
    self.assertHandler(rlib2.R_2_groups_name)
1143
    self.assertDryRun()
1144

    
1145
  def testRenameGroup(self):
1146
    self.rapi.AddResponse("12347")
1147
    job_id = self.client.RenameGroup("oldname", "newname")
1148
    self.assertEqual(job_id, 12347)
1149
    self.assertHandler(rlib2.R_2_groups_name_rename)
1150

    
1151
  def testModifyGroup(self):
1152
    self.rapi.AddResponse("12348")
1153
    job_id = self.client.ModifyGroup("mygroup", alloc_policy="foo")
1154
    self.assertEqual(job_id, 12348)
1155
    self.assertHandler(rlib2.R_2_groups_name_modify)
1156

    
1157
  def testAssignGroupNodes(self):
1158
    self.rapi.AddResponse("12349")
1159
    job_id = self.client.AssignGroupNodes("mygroup", ["node1", "node2"],
1160
                                          force=True, dry_run=True)
1161
    self.assertEqual(job_id, 12349)
1162
    self.assertHandler(rlib2.R_2_groups_name_assign_nodes)
1163
    self.assertDryRun()
1164
    self.assertUseForce()
1165

    
1166
  def testGetNetworksBulk(self):
1167
    networks = [{"name": "network1",
1168
               "uri": "/2/networks/network1",
1169
               "network": "192.168.0.0/24",
1170
               },
1171
              {"name": "network2",
1172
               "uri": "/2/networks/network2",
1173
               "network": "192.168.0.0/24",
1174
               },
1175
              ]
1176
    self.rapi.AddResponse(serializer.DumpJson(networks))
1177

    
1178
    self.assertEqual(networks, self.client.GetNetworks(bulk=True))
1179
    self.assertHandler(rlib2.R_2_networks)
1180
    self.assertBulk()
1181

    
1182
  def testGetNetwork(self):
1183
    network = {"ctime": None,
1184
               "name": "network1",
1185
               }
1186
    self.rapi.AddResponse(serializer.DumpJson(network))
1187
    self.assertEqual({"ctime": None, "name": "network1"},
1188
                     self.client.GetNetwork("network1"))
1189
    self.assertHandler(rlib2.R_2_networks_name)
1190
    self.assertItems(["network1"])
1191

    
1192
  def testCreateNetwork(self):
1193
    self.rapi.AddResponse("12345")
1194
    job_id = self.client.CreateNetwork("newnetwork", network="192.168.0.0/24",
1195
                                       dry_run=True)
1196
    self.assertEqual(job_id, 12345)
1197
    self.assertHandler(rlib2.R_2_networks)
1198
    self.assertDryRun()
1199

    
1200
  def testModifyNetwork(self):
1201
    self.rapi.AddResponse("12346")
1202
    job_id = self.client.ModifyNetwork("mynetwork", gateway="192.168.0.10",
1203
                                     dry_run=True)
1204
    self.assertEqual(job_id, 12346)
1205
    self.assertHandler(rlib2.R_2_networks_name_modify)
1206

    
1207
  def testDeleteNetwork(self):
1208
    self.rapi.AddResponse("12347")
1209
    job_id = self.client.DeleteNetwork("newnetwork", dry_run=True)
1210
    self.assertEqual(job_id, 12347)
1211
    self.assertHandler(rlib2.R_2_networks_name)
1212
    self.assertDryRun()
1213

    
1214
  def testConnectNetwork(self):
1215
    self.rapi.AddResponse("12348")
1216
    job_id = self.client.ConnectNetwork("mynetwork", "default",
1217
                                        "bridged", "br0", dry_run=True)
1218
    self.assertEqual(job_id, 12348)
1219
    self.assertHandler(rlib2.R_2_networks_name_connect)
1220
    self.assertDryRun()
1221

    
1222
  def testDisconnectNetwork(self):
1223
    self.rapi.AddResponse("12349")
1224
    job_id = self.client.DisconnectNetwork("mynetwork", "default", dry_run=True)
1225
    self.assertEqual(job_id, 12349)
1226
    self.assertHandler(rlib2.R_2_networks_name_disconnect)
1227
    self.assertDryRun()
1228

    
1229
  def testGetNetworkTags(self):
1230
    self.rapi.AddResponse("[]")
1231
    self.assertEqual([], self.client.GetNetworkTags("fooNetwork"))
1232
    self.assertHandler(rlib2.R_2_networks_name_tags)
1233
    self.assertItems(["fooNetwork"])
1234

    
1235
  def testAddNetworkTags(self):
1236
    self.rapi.AddResponse("1234")
1237
    self.assertEqual(1234,
1238
        self.client.AddNetworkTags("fooNetwork", ["awesome"], dry_run=True))
1239
    self.assertHandler(rlib2.R_2_networks_name_tags)
1240
    self.assertItems(["fooNetwork"])
1241
    self.assertDryRun()
1242
    self.assertQuery("tag", ["awesome"])
1243

    
1244
  def testDeleteNetworkTags(self):
1245
    self.rapi.AddResponse("25826")
1246
    self.assertEqual(25826, self.client.DeleteNetworkTags("foo", ["awesome"],
1247
                                                          dry_run=True))
1248
    self.assertHandler(rlib2.R_2_networks_name_tags)
1249
    self.assertItems(["foo"])
1250
    self.assertDryRun()
1251
    self.assertQuery("tag", ["awesome"])
1252

    
1253
  def testModifyInstance(self):
1254
    self.rapi.AddResponse("23681")
1255
    job_id = self.client.ModifyInstance("inst7210", os_name="linux")
1256
    self.assertEqual(job_id, 23681)
1257
    self.assertItems(["inst7210"])
1258
    self.assertHandler(rlib2.R_2_instances_name_modify)
1259
    self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
1260
                     { "os_name": "linux", })
1261

    
1262
  def testModifyCluster(self):
1263
    for mnh in [None, False, True]:
1264
      self.rapi.AddResponse("14470")
1265
      self.assertEqual(14470,
1266
        self.client.ModifyCluster(maintain_node_health=mnh))
1267
      self.assertHandler(rlib2.R_2_cluster_modify)
1268
      self.assertItems([])
1269
      data = serializer.LoadJson(self.rapi.GetLastRequestData())
1270
      self.assertEqual(len(data), 1)
1271
      self.assertEqual(data["maintain_node_health"], mnh)
1272
      self.assertEqual(self.rapi.CountPending(), 0)
1273

    
1274
  def testRedistributeConfig(self):
1275
    self.rapi.AddResponse("3364")
1276
    job_id = self.client.RedistributeConfig()
1277
    self.assertEqual(job_id, 3364)
1278
    self.assertItems([])
1279
    self.assertHandler(rlib2.R_2_redist_config)
1280

    
1281
  def testActivateInstanceDisks(self):
1282
    self.rapi.AddResponse("23547")
1283
    job_id = self.client.ActivateInstanceDisks("inst28204")
1284
    self.assertEqual(job_id, 23547)
1285
    self.assertItems(["inst28204"])
1286
    self.assertHandler(rlib2.R_2_instances_name_activate_disks)
1287
    self.assertFalse(self.rapi.GetLastHandler().queryargs)
1288

    
1289
  def testActivateInstanceDisksIgnoreSize(self):
1290
    self.rapi.AddResponse("11044")
1291
    job_id = self.client.ActivateInstanceDisks("inst28204", ignore_size=True)
1292
    self.assertEqual(job_id, 11044)
1293
    self.assertItems(["inst28204"])
1294
    self.assertHandler(rlib2.R_2_instances_name_activate_disks)
1295
    self.assertQuery("ignore_size", ["1"])
1296

    
1297
  def testDeactivateInstanceDisks(self):
1298
    self.rapi.AddResponse("14591")
1299
    job_id = self.client.DeactivateInstanceDisks("inst28234")
1300
    self.assertEqual(job_id, 14591)
1301
    self.assertItems(["inst28234"])
1302
    self.assertHandler(rlib2.R_2_instances_name_deactivate_disks)
1303
    self.assertFalse(self.rapi.GetLastHandler().queryargs)
1304

    
1305
  def testRecreateInstanceDisks(self):
1306
    self.rapi.AddResponse("13553")
1307
    job_id = self.client.RecreateInstanceDisks("inst23153")
1308
    self.assertEqual(job_id, 13553)
1309
    self.assertItems(["inst23153"])
1310
    self.assertHandler(rlib2.R_2_instances_name_recreate_disks)
1311
    self.assertFalse(self.rapi.GetLastHandler().queryargs)
1312

    
1313
  def testGetInstanceConsole(self):
1314
    self.rapi.AddResponse("26876")
1315
    job_id = self.client.GetInstanceConsole("inst21491")
1316
    self.assertEqual(job_id, 26876)
1317
    self.assertItems(["inst21491"])
1318
    self.assertHandler(rlib2.R_2_instances_name_console)
1319
    self.assertFalse(self.rapi.GetLastHandler().queryargs)
1320
    self.assertFalse(self.rapi.GetLastRequestData())
1321

    
1322
  def testGrowInstanceDisk(self):
1323
    for idx, wait_for_sync in enumerate([None, False, True]):
1324
      amount = 128 + (512 * idx)
1325
      self.assertEqual(self.rapi.CountPending(), 0)
1326
      self.rapi.AddResponse("30783")
1327
      self.assertEqual(30783,
1328
        self.client.GrowInstanceDisk("eze8ch", idx, amount,
1329
                                     wait_for_sync=wait_for_sync))
1330
      self.assertHandler(rlib2.R_2_instances_name_disk_grow)
1331
      self.assertItems(["eze8ch", str(idx)])
1332
      data = serializer.LoadJson(self.rapi.GetLastRequestData())
1333
      if wait_for_sync is None:
1334
        self.assertEqual(len(data), 1)
1335
        self.assert_("wait_for_sync" not in data)
1336
      else:
1337
        self.assertEqual(len(data), 2)
1338
        self.assertEqual(data["wait_for_sync"], wait_for_sync)
1339
      self.assertEqual(data["amount"], amount)
1340
      self.assertEqual(self.rapi.CountPending(), 0)
1341

    
1342
  def testGetGroupTags(self):
1343
    self.rapi.AddResponse("[]")
1344
    self.assertEqual([], self.client.GetGroupTags("fooGroup"))
1345
    self.assertHandler(rlib2.R_2_groups_name_tags)
1346
    self.assertItems(["fooGroup"])
1347

    
1348
  def testAddGroupTags(self):
1349
    self.rapi.AddResponse("1234")
1350
    self.assertEqual(1234,
1351
        self.client.AddGroupTags("fooGroup", ["awesome"], dry_run=True))
1352
    self.assertHandler(rlib2.R_2_groups_name_tags)
1353
    self.assertItems(["fooGroup"])
1354
    self.assertDryRun()
1355
    self.assertQuery("tag", ["awesome"])
1356

    
1357
  def testDeleteGroupTags(self):
1358
    self.rapi.AddResponse("25826")
1359
    self.assertEqual(25826, self.client.DeleteGroupTags("foo", ["awesome"],
1360
                                                        dry_run=True))
1361
    self.assertHandler(rlib2.R_2_groups_name_tags)
1362
    self.assertItems(["foo"])
1363
    self.assertDryRun()
1364
    self.assertQuery("tag", ["awesome"])
1365

    
1366
  def testQuery(self):
1367
    for idx, what in enumerate(constants.QR_VIA_RAPI):
1368
      for idx2, qfilter in enumerate([None, ["?", "name"]]):
1369
        job_id = 11010 + (idx << 4) + (idx2 << 16)
1370
        fields = sorted(query.ALL_FIELDS[what].keys())[:10]
1371

    
1372
        self.rapi.AddResponse(str(job_id))
1373
        self.assertEqual(self.client.Query(what, fields, qfilter=qfilter),
1374
                         job_id)
1375
        self.assertItems([what])
1376
        self.assertHandler(rlib2.R_2_query)
1377
        self.assertFalse(self.rapi.GetLastHandler().queryargs)
1378
        data = serializer.LoadJson(self.rapi.GetLastRequestData())
1379
        self.assertEqual(data["fields"], fields)
1380
        if qfilter is None:
1381
          self.assertTrue("qfilter" not in data)
1382
        else:
1383
          self.assertEqual(data["qfilter"], qfilter)
1384
        self.assertEqual(self.rapi.CountPending(), 0)
1385

    
1386
  def testQueryFields(self):
1387
    exp_result = objects.QueryFieldsResponse(fields=[
1388
      objects.QueryFieldDefinition(name="pnode", title="PNode",
1389
                                   kind=constants.QFT_NUMBER),
1390
      objects.QueryFieldDefinition(name="other", title="Other",
1391
                                   kind=constants.QFT_BOOL),
1392
      ])
1393

    
1394
    for what in constants.QR_VIA_RAPI:
1395
      for fields in [None, ["name", "_unknown_"], ["&", "?|"]]:
1396
        self.rapi.AddResponse(serializer.DumpJson(exp_result.ToDict()))
1397
        result = self.client.QueryFields(what, fields=fields)
1398
        self.assertItems([what])
1399
        self.assertHandler(rlib2.R_2_query_fields)
1400
        self.assertFalse(self.rapi.GetLastRequestData())
1401

    
1402
        queryargs = self.rapi.GetLastHandler().queryargs
1403
        if fields is None:
1404
          self.assertFalse(queryargs)
1405
        else:
1406
          self.assertEqual(queryargs, {
1407
            "fields": [",".join(fields)],
1408
            })
1409

    
1410
        self.assertEqual(objects.QueryFieldsResponse.FromDict(result).ToDict(),
1411
                         exp_result.ToDict())
1412

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

    
1415
  def testWaitForJobCompletionNoChange(self):
1416
    resp = serializer.DumpJson({
1417
      "status": constants.JOB_STATUS_WAITING,
1418
      })
1419

    
1420
    for retries in [1, 5, 25]:
1421
      for _ in range(retries):
1422
        self.rapi.AddResponse(resp)
1423

    
1424
      self.assertFalse(self.client.WaitForJobCompletion(22789, period=None,
1425
                                                        retries=retries))
1426
      self.assertHandler(rlib2.R_2_jobs_id)
1427
      self.assertItems(["22789"])
1428

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

    
1431
  def testWaitForJobCompletionAlreadyFinished(self):
1432
    self.rapi.AddResponse(serializer.DumpJson({
1433
      "status": constants.JOB_STATUS_SUCCESS,
1434
      }))
1435

    
1436
    self.assertTrue(self.client.WaitForJobCompletion(22793, period=None,
1437
                                                     retries=1))
1438
    self.assertHandler(rlib2.R_2_jobs_id)
1439
    self.assertItems(["22793"])
1440

    
1441
    self.assertEqual(self.rapi.CountPending(), 0)
1442

    
1443
  def testWaitForJobCompletionEmptyResponse(self):
1444
    self.rapi.AddResponse("{}")
1445
    self.assertFalse(self.client.WaitForJobCompletion(22793, period=None,
1446
                                                     retries=10))
1447
    self.assertHandler(rlib2.R_2_jobs_id)
1448
    self.assertItems(["22793"])
1449

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

    
1452
  def testWaitForJobCompletionOutOfRetries(self):
1453
    for retries in [3, 10, 21]:
1454
      for _ in range(retries):
1455
        self.rapi.AddResponse(serializer.DumpJson({
1456
          "status": constants.JOB_STATUS_RUNNING,
1457
          }))
1458

    
1459
      self.assertFalse(self.client.WaitForJobCompletion(30948, period=None,
1460
                                                        retries=retries - 1))
1461
      self.assertHandler(rlib2.R_2_jobs_id)
1462
      self.assertItems(["30948"])
1463

    
1464
      self.assertEqual(self.rapi.CountPending(), 1)
1465
      self.rapi.ResetResponses()
1466

    
1467
  def testWaitForJobCompletionSuccessAndFailure(self):
1468
    for retries in [1, 4, 13]:
1469
      for (success, end_status) in [(False, constants.JOB_STATUS_ERROR),
1470
                                    (True, constants.JOB_STATUS_SUCCESS)]:
1471
        for _ in range(retries):
1472
          self.rapi.AddResponse(serializer.DumpJson({
1473
            "status": constants.JOB_STATUS_RUNNING,
1474
            }))
1475

    
1476
        self.rapi.AddResponse(serializer.DumpJson({
1477
          "status": end_status,
1478
          }))
1479

    
1480
        result = self.client.WaitForJobCompletion(3187, period=None,
1481
                                                  retries=retries + 1)
1482
        self.assertEqual(result, success)
1483
        self.assertHandler(rlib2.R_2_jobs_id)
1484
        self.assertItems(["3187"])
1485

    
1486
        self.assertEqual(self.rapi.CountPending(), 0)
1487

    
1488

    
1489
class RapiTestRunner(unittest.TextTestRunner):
1490
  def run(self, *args):
1491
    global _used_handlers
1492
    assert _used_handlers is None
1493

    
1494
    _used_handlers = set()
1495
    try:
1496
      # Run actual tests
1497
      result = unittest.TextTestRunner.run(self, *args)
1498

    
1499
      diff = (set(connector.CONNECTOR.values()) - _used_handlers -
1500
             _KNOWN_UNUSED)
1501
      if diff:
1502
        raise AssertionError("The following RAPI resources were not used by the"
1503
                             " RAPI client: %r" % utils.CommaJoin(diff))
1504
    finally:
1505
      # Reset global variable
1506
      _used_handlers = None
1507

    
1508
    return result
1509

    
1510

    
1511
if __name__ == "__main__":
1512
  client.UsesRapiClient(testutils.GanetiTestProgram)(testRunner=RapiTestRunner)