Statistics
| Branch: | Tag: | Revision:

root / test / ganeti.rapi.client_unittest.py @ 47099cd1

History | View | Annotate | Download (49.5 kB)

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

    
4
# Copyright (C) 2010 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 re
26
import unittest
27
import warnings
28
import pycurl
29

    
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

    
37
from ganeti.rapi import connector
38
from ganeti.rapi import rlib2
39
from ganeti.rapi import client
40

    
41
import testutils
42

    
43

    
44
_URI_RE = re.compile(r"https://(?P<host>.*):(?P<port>\d+)(?P<path>/.*)")
45

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

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

    
55

    
56
def _GetPathFromUri(uri):
57
  """Gets the path and query from a URI.
58

59
  """
60
  match = _URI_RE.match(uri)
61
  if match:
62
    return match.groupdict()["path"]
63
  else:
64
    return None
65

    
66

    
67
class FakeCurl:
68
  def __init__(self, rapi):
69
    self._rapi = rapi
70
    self._opts = {}
71
    self._info = {}
72

    
73
  def setopt(self, opt, value):
74
    self._opts[opt] = value
75

    
76
  def getopt(self, opt):
77
    return self._opts.get(opt)
78

    
79
  def unsetopt(self, opt):
80
    self._opts.pop(opt, None)
81

    
82
  def getinfo(self, info):
83
    return self._info[info]
84

    
85
  def perform(self):
86
    method = self._opts[pycurl.CUSTOMREQUEST]
87
    url = self._opts[pycurl.URL]
88
    request_body = self._opts[pycurl.POSTFIELDS]
89
    writefn = self._opts[pycurl.WRITEFUNCTION]
90

    
91
    path = _GetPathFromUri(url)
92
    (code, resp_body) = self._rapi.FetchResponse(path, method, request_body)
93

    
94
    self._info[pycurl.RESPONSE_CODE] = code
95
    if resp_body is not None:
96
      writefn(resp_body)
97

    
98

    
99
class RapiMock(object):
100
  def __init__(self):
101
    self._mapper = connector.Mapper()
102
    self._responses = []
103
    self._last_handler = None
104
    self._last_req_data = None
105

    
106
  def ResetResponses(self):
107
    del self._responses[:]
108

    
109
  def AddResponse(self, response, code=200):
110
    self._responses.insert(0, (code, response))
111

    
112
  def CountPending(self):
113
    return len(self._responses)
114

    
115
  def GetLastHandler(self):
116
    return self._last_handler
117

    
118
  def GetLastRequestData(self):
119
    return self._last_req_data
120

    
121
  def FetchResponse(self, path, method, request_body):
122
    self._last_req_data = request_body
123

    
124
    try:
125
      (handler_cls, items, args) = self._mapper.getController(path)
126

    
127
      # Record handler as used
128
      _used_handlers.add(handler_cls)
129

    
130
      self._last_handler = handler_cls(items, args, None)
131
      if not hasattr(self._last_handler, method.upper()):
132
        raise http.HttpNotImplemented(message="Method not implemented")
133

    
134
    except http.HttpException, ex:
135
      code = ex.code
136
      response = ex.message
137
    else:
138
      if not self._responses:
139
        raise Exception("No responses")
140

    
141
      (code, response) = self._responses.pop()
142

    
143
    return code, response
144

    
145

    
146
class TestConstants(unittest.TestCase):
147
  def test(self):
148
    self.assertEqual(client.GANETI_RAPI_PORT, constants.DEFAULT_RAPI_PORT)
149
    self.assertEqual(client.GANETI_RAPI_VERSION, constants.RAPI_VERSION)
150
    self.assertEqual(client.HTTP_APP_JSON, http.HTTP_APP_JSON)
151
    self.assertEqual(client._REQ_DATA_VERSION_FIELD, rlib2._REQ_DATA_VERSION)
152
    self.assertEqual(client._INST_CREATE_REQV1, rlib2._INST_CREATE_REQV1)
153
    self.assertEqual(client._INST_REINSTALL_REQV1, rlib2._INST_REINSTALL_REQV1)
154
    self.assertEqual(client._NODE_MIGRATE_REQV1, rlib2._NODE_MIGRATE_REQV1)
155
    self.assertEqual(client._NODE_EVAC_RES1, rlib2._NODE_EVAC_RES1)
156
    self.assertEqual(client._INST_NIC_PARAMS, constants.INIC_PARAMS)
157
    self.assertEqual(client.JOB_STATUS_QUEUED, constants.JOB_STATUS_QUEUED)
158
    self.assertEqual(client.JOB_STATUS_WAITING, constants.JOB_STATUS_WAITING)
159
    self.assertEqual(client.JOB_STATUS_CANCELING,
160
                     constants.JOB_STATUS_CANCELING)
161
    self.assertEqual(client.JOB_STATUS_RUNNING, constants.JOB_STATUS_RUNNING)
162
    self.assertEqual(client.JOB_STATUS_CANCELED, constants.JOB_STATUS_CANCELED)
163
    self.assertEqual(client.JOB_STATUS_SUCCESS, constants.JOB_STATUS_SUCCESS)
164
    self.assertEqual(client.JOB_STATUS_ERROR, constants.JOB_STATUS_ERROR)
165
    self.assertEqual(client.JOB_STATUS_FINALIZED, constants.JOBS_FINALIZED)
166
    self.assertEqual(client.JOB_STATUS_ALL, constants.JOB_STATUS_ALL)
167

    
168
    # Legacy name
169
    self.assertEqual(client.JOB_STATUS_WAITLOCK, constants.JOB_STATUS_WAITING)
170

    
171

    
172
class RapiMockTest(unittest.TestCase):
173
  def test(self):
174
    rapi = RapiMock()
175
    path = "/version"
176
    self.assertEqual((404, None), rapi.FetchResponse("/foo", "GET", None))
177
    self.assertEqual((501, "Method not implemented"),
178
                     rapi.FetchResponse("/version", "POST", None))
179
    rapi.AddResponse("2")
180
    code, response = rapi.FetchResponse("/version", "GET", None)
181
    self.assertEqual(200, code)
182
    self.assertEqual("2", response)
183
    self.failUnless(isinstance(rapi.GetLastHandler(), rlib2.R_version))
184

    
185

    
186
def _FakeNoSslPycurlVersion():
187
  # Note: incomplete version tuple
188
  return (3, "7.16.0", 462848, "mysystem", 1581, None, 0)
189

    
190

    
191
def _FakeFancySslPycurlVersion():
192
  # Note: incomplete version tuple
193
  return (3, "7.16.0", 462848, "mysystem", 1581, "FancySSL/1.2.3", 0)
194

    
195

    
196
def _FakeOpenSslPycurlVersion():
197
  # Note: incomplete version tuple
198
  return (2, "7.15.5", 462597, "othersystem", 668, "OpenSSL/0.9.8c", 0)
199

    
200

    
201
def _FakeGnuTlsPycurlVersion():
202
  # Note: incomplete version tuple
203
  return (3, "7.18.0", 463360, "somesystem", 1581, "GnuTLS/2.0.4", 0)
204

    
205

    
206
class TestExtendedConfig(unittest.TestCase):
207
  def testAuth(self):
208
    cl = client.GanetiRapiClient("master.example.com",
209
                                 username="user", password="pw",
210
                                 curl_factory=lambda: FakeCurl(RapiMock()))
211

    
212
    curl = cl._CreateCurl()
213
    self.assertEqual(curl.getopt(pycurl.HTTPAUTH), pycurl.HTTPAUTH_BASIC)
214
    self.assertEqual(curl.getopt(pycurl.USERPWD), "user:pw")
215

    
216
  def testInvalidAuth(self):
217
    # No username
218
    self.assertRaises(client.Error, client.GanetiRapiClient,
219
                      "master-a.example.com", password="pw")
220
    # No password
221
    self.assertRaises(client.Error, client.GanetiRapiClient,
222
                      "master-b.example.com", username="user")
223

    
224
  def testCertVerifyInvalidCombinations(self):
225
    self.assertRaises(client.Error, client.GenericCurlConfig,
226
                      use_curl_cabundle=True, cafile="cert1.pem")
227
    self.assertRaises(client.Error, client.GenericCurlConfig,
228
                      use_curl_cabundle=True, capath="certs/")
229
    self.assertRaises(client.Error, client.GenericCurlConfig,
230
                      use_curl_cabundle=True,
231
                      cafile="cert1.pem", capath="certs/")
232

    
233
  def testProxySignalVerifyHostname(self):
234
    for use_gnutls in [False, True]:
235
      if use_gnutls:
236
        pcverfn = _FakeGnuTlsPycurlVersion
237
      else:
238
        pcverfn = _FakeOpenSslPycurlVersion
239

    
240
      for proxy in ["", "http://127.0.0.1:1234"]:
241
        for use_signal in [False, True]:
242
          for verify_hostname in [False, True]:
243
            cfgfn = client.GenericCurlConfig(proxy=proxy, use_signal=use_signal,
244
                                             verify_hostname=verify_hostname,
245
                                             _pycurl_version_fn=pcverfn)
246

    
247
            curl_factory = lambda: FakeCurl(RapiMock())
248
            cl = client.GanetiRapiClient("master.example.com",
249
                                         curl_config_fn=cfgfn,
250
                                         curl_factory=curl_factory)
251

    
252
            curl = cl._CreateCurl()
253
            self.assertEqual(curl.getopt(pycurl.PROXY), proxy)
254
            self.assertEqual(curl.getopt(pycurl.NOSIGNAL), not use_signal)
255

    
256
            if verify_hostname:
257
              self.assertEqual(curl.getopt(pycurl.SSL_VERIFYHOST), 2)
258
            else:
259
              self.assertEqual(curl.getopt(pycurl.SSL_VERIFYHOST), 0)
260

    
261
  def testNoCertVerify(self):
262
    cfgfn = client.GenericCurlConfig()
263

    
264
    curl_factory = lambda: FakeCurl(RapiMock())
265
    cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
266
                                 curl_factory=curl_factory)
267

    
268
    curl = cl._CreateCurl()
269
    self.assertFalse(curl.getopt(pycurl.SSL_VERIFYPEER))
270
    self.assertFalse(curl.getopt(pycurl.CAINFO))
271
    self.assertFalse(curl.getopt(pycurl.CAPATH))
272

    
273
  def testCertVerifyCurlBundle(self):
274
    cfgfn = client.GenericCurlConfig(use_curl_cabundle=True)
275

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

    
280
    curl = cl._CreateCurl()
281
    self.assert_(curl.getopt(pycurl.SSL_VERIFYPEER))
282
    self.assertFalse(curl.getopt(pycurl.CAINFO))
283
    self.assertFalse(curl.getopt(pycurl.CAPATH))
284

    
285
  def testCertVerifyCafile(self):
286
    mycert = "/tmp/some/UNUSED/cert/file.pem"
287
    cfgfn = client.GenericCurlConfig(cafile=mycert)
288

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

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

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

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

    
308
    curl = cl._CreateCurl()
309
    self.assert_(curl.getopt(pycurl.SSL_VERIFYPEER))
310
    self.assertEqual(curl.getopt(pycurl.CAPATH), certdir)
311
    self.assertFalse(curl.getopt(pycurl.CAINFO))
312

    
313
  def testCertVerifyCapathGnuTls(self):
314
    certdir = "/tmp/some/UNUSED/cert/directory"
315
    pcverfn = _FakeGnuTlsPycurlVersion
316
    cfgfn = client.GenericCurlConfig(capath=certdir,
317
                                     _pycurl_version_fn=pcverfn)
318

    
319
    curl_factory = lambda: FakeCurl(RapiMock())
320
    cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
321
                                 curl_factory=curl_factory)
322

    
323
    self.assertRaises(client.Error, cl._CreateCurl)
324

    
325
  def testCertVerifyNoSsl(self):
326
    certdir = "/tmp/some/UNUSED/cert/directory"
327
    pcverfn = _FakeNoSslPycurlVersion
328
    cfgfn = client.GenericCurlConfig(capath=certdir,
329
                                     _pycurl_version_fn=pcverfn)
330

    
331
    curl_factory = lambda: FakeCurl(RapiMock())
332
    cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
333
                                 curl_factory=curl_factory)
334

    
335
    self.assertRaises(client.Error, cl._CreateCurl)
336

    
337
  def testCertVerifyFancySsl(self):
338
    certdir = "/tmp/some/UNUSED/cert/directory"
339
    pcverfn = _FakeFancySslPycurlVersion
340
    cfgfn = client.GenericCurlConfig(capath=certdir,
341
                                     _pycurl_version_fn=pcverfn)
342

    
343
    curl_factory = lambda: FakeCurl(RapiMock())
344
    cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
345
                                 curl_factory=curl_factory)
346

    
347
    self.assertRaises(NotImplementedError, cl._CreateCurl)
348

    
349
  def testCertVerifyCapath(self):
350
    for connect_timeout in [None, 1, 5, 10, 30, 60, 300]:
351
      for timeout in [None, 1, 30, 60, 3600, 24 * 3600]:
352
        cfgfn = client.GenericCurlConfig(connect_timeout=connect_timeout,
353
                                         timeout=timeout)
354

    
355
        curl_factory = lambda: FakeCurl(RapiMock())
356
        cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
357
                                     curl_factory=curl_factory)
358

    
359
        curl = cl._CreateCurl()
360
        self.assertEqual(curl.getopt(pycurl.CONNECTTIMEOUT), connect_timeout)
361
        self.assertEqual(curl.getopt(pycurl.TIMEOUT), timeout)
362

    
363

    
364
class GanetiRapiClientTests(testutils.GanetiTestCase):
365
  def setUp(self):
366
    testutils.GanetiTestCase.setUp(self)
367

    
368
    self.rapi = RapiMock()
369
    self.curl = FakeCurl(self.rapi)
370
    self.client = client.GanetiRapiClient("master.example.com",
371
                                          curl_factory=lambda: self.curl)
372

    
373
  def assertHandler(self, handler_cls):
374
    self.failUnless(isinstance(self.rapi.GetLastHandler(), handler_cls))
375

    
376
  def assertQuery(self, key, value):
377
    self.assertEqual(value, self.rapi.GetLastHandler().queryargs.get(key, None))
378

    
379
  def assertItems(self, items):
380
    self.assertEqual(items, self.rapi.GetLastHandler().items)
381

    
382
  def assertBulk(self):
383
    self.assertTrue(self.rapi.GetLastHandler().useBulk())
384

    
385
  def assertDryRun(self):
386
    self.assertTrue(self.rapi.GetLastHandler().dryRun())
387

    
388
  def assertUseForce(self):
389
    self.assertTrue(self.rapi.GetLastHandler().useForce())
390

    
391
  def testEncodeQuery(self):
392
    query = [
393
      ("a", None),
394
      ("b", 1),
395
      ("c", 2),
396
      ("d", "Foo"),
397
      ("e", True),
398
      ]
399

    
400
    expected = [
401
      ("a", ""),
402
      ("b", 1),
403
      ("c", 2),
404
      ("d", "Foo"),
405
      ("e", 1),
406
      ]
407

    
408
    self.assertEqualValues(self.client._EncodeQuery(query),
409
                           expected)
410

    
411
    # invalid types
412
    for i in [[1, 2, 3], {"moo": "boo"}, (1, 2, 3)]:
413
      self.assertRaises(ValueError, self.client._EncodeQuery, [("x", i)])
414

    
415
  def testCurlSettings(self):
416
    self.rapi.AddResponse("2")
417
    self.assertEqual(2, self.client.GetVersion())
418
    self.assertHandler(rlib2.R_version)
419

    
420
    # Signals should be disabled by default
421
    self.assert_(self.curl.getopt(pycurl.NOSIGNAL))
422

    
423
    # No auth and no proxy
424
    self.assertFalse(self.curl.getopt(pycurl.USERPWD))
425
    self.assert_(self.curl.getopt(pycurl.PROXY) is None)
426

    
427
    # Content-type is required for requests
428
    headers = self.curl.getopt(pycurl.HTTPHEADER)
429
    self.assert_("Content-type: application/json" in headers)
430

    
431
  def testHttpError(self):
432
    self.rapi.AddResponse(None, code=404)
433
    try:
434
      self.client.GetJobStatus(15140)
435
    except client.GanetiApiError, err:
436
      self.assertEqual(err.code, 404)
437
    else:
438
      self.fail("Didn't raise exception")
439

    
440
  def testGetVersion(self):
441
    self.rapi.AddResponse("2")
442
    self.assertEqual(2, self.client.GetVersion())
443
    self.assertHandler(rlib2.R_version)
444

    
445
  def testGetFeatures(self):
446
    for features in [[], ["foo", "bar", "baz"]]:
447
      self.rapi.AddResponse(serializer.DumpJson(features))
448
      self.assertEqual(features, self.client.GetFeatures())
449
      self.assertHandler(rlib2.R_2_features)
450

    
451
  def testGetFeaturesNotFound(self):
452
    self.rapi.AddResponse(None, code=404)
453
    self.assertEqual([], self.client.GetFeatures())
454

    
455
  def testGetOperatingSystems(self):
456
    self.rapi.AddResponse("[\"beos\"]")
457
    self.assertEqual(["beos"], self.client.GetOperatingSystems())
458
    self.assertHandler(rlib2.R_2_os)
459

    
460
  def testGetClusterTags(self):
461
    self.rapi.AddResponse("[\"tag\"]")
462
    self.assertEqual(["tag"], self.client.GetClusterTags())
463
    self.assertHandler(rlib2.R_2_tags)
464

    
465
  def testAddClusterTags(self):
466
    self.rapi.AddResponse("1234")
467
    self.assertEqual(1234,
468
        self.client.AddClusterTags(["awesome"], dry_run=True))
469
    self.assertHandler(rlib2.R_2_tags)
470
    self.assertDryRun()
471
    self.assertQuery("tag", ["awesome"])
472

    
473
  def testDeleteClusterTags(self):
474
    self.rapi.AddResponse("5107")
475
    self.assertEqual(5107, self.client.DeleteClusterTags(["awesome"],
476
                                                         dry_run=True))
477
    self.assertHandler(rlib2.R_2_tags)
478
    self.assertDryRun()
479
    self.assertQuery("tag", ["awesome"])
480

    
481
  def testGetInfo(self):
482
    self.rapi.AddResponse("{}")
483
    self.assertEqual({}, self.client.GetInfo())
484
    self.assertHandler(rlib2.R_2_info)
485

    
486
  def testGetInstances(self):
487
    self.rapi.AddResponse("[]")
488
    self.assertEqual([], self.client.GetInstances(bulk=True))
489
    self.assertHandler(rlib2.R_2_instances)
490
    self.assertBulk()
491

    
492
  def testGetInstance(self):
493
    self.rapi.AddResponse("[]")
494
    self.assertEqual([], self.client.GetInstance("instance"))
495
    self.assertHandler(rlib2.R_2_instances_name)
496
    self.assertItems(["instance"])
497

    
498
  def testGetInstanceInfo(self):
499
    self.rapi.AddResponse("21291")
500
    self.assertEqual(21291, self.client.GetInstanceInfo("inst3"))
501
    self.assertHandler(rlib2.R_2_instances_name_info)
502
    self.assertItems(["inst3"])
503
    self.assertQuery("static", None)
504

    
505
    self.rapi.AddResponse("3428")
506
    self.assertEqual(3428, self.client.GetInstanceInfo("inst31", static=False))
507
    self.assertHandler(rlib2.R_2_instances_name_info)
508
    self.assertItems(["inst31"])
509
    self.assertQuery("static", ["0"])
510

    
511
    self.rapi.AddResponse("15665")
512
    self.assertEqual(15665, self.client.GetInstanceInfo("inst32", static=True))
513
    self.assertHandler(rlib2.R_2_instances_name_info)
514
    self.assertItems(["inst32"])
515
    self.assertQuery("static", ["1"])
516

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
723
    data = serializer.LoadJson(self.rapi.GetLastRequestData())
724
    self.assertFalse(data)
725

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

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

    
741
  def testRenameInstanceDefaults(self):
742
    new_name = "newnametha7euqu"
743
    self.rapi.AddResponse("8791")
744
    job_id = self.client.RenameInstance("inst18821", new_name)
745
    self.assertEqual(job_id, 8791)
746
    self.assertHandler(rlib2.R_2_instances_name_rename)
747
    self.assertItems(["inst18821"])
748

    
749
    data = serializer.LoadJson(self.rapi.GetLastRequestData())
750
    self.assertEqualValues(data, {"new_name": new_name, })
751

    
752
  def testRenameInstance(self):
753
    new_name = "new-name-yiux1iin"
754
    for ip_check in [False, True]:
755
      for name_check in [False, True]:
756
        self.rapi.AddResponse("24776")
757
        job_id = self.client.RenameInstance("inst20967", new_name,
758
                                             ip_check=ip_check,
759
                                             name_check=name_check)
760
        self.assertEqual(job_id, 24776)
761
        self.assertHandler(rlib2.R_2_instances_name_rename)
762
        self.assertItems(["inst20967"])
763

    
764
        data = serializer.LoadJson(self.rapi.GetLastRequestData())
765
        self.assertEqual(len(data), 3)
766
        self.assertEqual(data["new_name"], new_name)
767
        self.assertEqual(data["ip_check"], ip_check)
768
        self.assertEqual(data["name_check"], name_check)
769

    
770
  def testGetJobs(self):
771
    self.rapi.AddResponse('[ { "id": "123", "uri": "\\/2\\/jobs\\/123" },'
772
                          '  { "id": "124", "uri": "\\/2\\/jobs\\/124" } ]')
773
    self.assertEqual([123, 124], self.client.GetJobs())
774
    self.assertHandler(rlib2.R_2_jobs)
775

    
776
  def testGetJobStatus(self):
777
    self.rapi.AddResponse("{\"foo\": \"bar\"}")
778
    self.assertEqual({"foo": "bar"}, self.client.GetJobStatus(1234))
779
    self.assertHandler(rlib2.R_2_jobs_id)
780
    self.assertItems(["1234"])
781

    
782
  def testWaitForJobChange(self):
783
    fields = ["id", "summary"]
784
    expected = {
785
      "job_info": [123, "something"],
786
      "log_entries": [],
787
      }
788

    
789
    self.rapi.AddResponse(serializer.DumpJson(expected))
790
    result = self.client.WaitForJobChange(123, fields, [], -1)
791
    self.assertEqualValues(expected, result)
792
    self.assertHandler(rlib2.R_2_jobs_id_wait)
793
    self.assertItems(["123"])
794

    
795
  def testCancelJob(self):
796
    self.rapi.AddResponse("[true, \"Job 123 will be canceled\"]")
797
    self.assertEqual([True, "Job 123 will be canceled"],
798
                     self.client.CancelJob(999, dry_run=True))
799
    self.assertHandler(rlib2.R_2_jobs_id)
800
    self.assertItems(["999"])
801
    self.assertDryRun()
802

    
803
  def testGetNodes(self):
804
    self.rapi.AddResponse("[ { \"id\": \"node1\", \"uri\": \"uri1\" },"
805
                          " { \"id\": \"node2\", \"uri\": \"uri2\" } ]")
806
    self.assertEqual(["node1", "node2"], self.client.GetNodes())
807
    self.assertHandler(rlib2.R_2_nodes)
808

    
809
    self.rapi.AddResponse("[ { \"id\": \"node1\", \"uri\": \"uri1\" },"
810
                          " { \"id\": \"node2\", \"uri\": \"uri2\" } ]")
811
    self.assertEqual([{"id": "node1", "uri": "uri1"},
812
                      {"id": "node2", "uri": "uri2"}],
813
                     self.client.GetNodes(bulk=True))
814
    self.assertHandler(rlib2.R_2_nodes)
815
    self.assertBulk()
816

    
817
  def testGetNode(self):
818
    self.rapi.AddResponse("{}")
819
    self.assertEqual({}, self.client.GetNode("node-foo"))
820
    self.assertHandler(rlib2.R_2_nodes_name)
821
    self.assertItems(["node-foo"])
822

    
823
  def testEvacuateNode(self):
824
    self.rapi.AddResponse(serializer.DumpJson([rlib2._NODE_EVAC_RES1]))
825
    self.rapi.AddResponse("9876")
826
    job_id = self.client.EvacuateNode("node-1", remote_node="node-2")
827
    self.assertEqual(9876, job_id)
828
    self.assertHandler(rlib2.R_2_nodes_name_evacuate)
829
    self.assertItems(["node-1"])
830
    self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
831
                     { "remote_node": "node-2", })
832
    self.assertEqual(self.rapi.CountPending(), 0)
833

    
834
    self.rapi.AddResponse(serializer.DumpJson([rlib2._NODE_EVAC_RES1]))
835
    self.rapi.AddResponse("8888")
836
    job_id = self.client.EvacuateNode("node-3", iallocator="hail", dry_run=True)
837
    self.assertEqual(8888, job_id)
838
    self.assertItems(["node-3"])
839
    self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
840
                     { "iallocator": "hail", })
841
    self.assertDryRun()
842

    
843
    self.assertRaises(client.GanetiApiError,
844
                      self.client.EvacuateNode,
845
                      "node-4", iallocator="hail", remote_node="node-5")
846
    self.assertEqual(self.rapi.CountPending(), 0)
847

    
848
  def testEvacuateNodeOldResponse(self):
849
    self.rapi.AddResponse(serializer.DumpJson([]))
850
    self.assertRaises(client.GanetiApiError, self.client.EvacuateNode,
851
                      "node-4", accept_old=False)
852
    self.assertEqual(self.rapi.CountPending(), 0)
853

    
854
    self.rapi.AddResponse(serializer.DumpJson([]))
855
    self.assertRaises(client.GanetiApiError, self.client.EvacuateNode,
856
                      "node-4", accept_old=True)
857
    self.assertEqual(self.rapi.CountPending(), 0)
858

    
859
    self.rapi.AddResponse(serializer.DumpJson([]))
860
    self.assertRaises(client.GanetiApiError, self.client.EvacuateNode,
861
                      "node-4", accept_old=True, primary=True)
862
    self.assertEqual(self.rapi.CountPending(), 0)
863

    
864
    self.rapi.AddResponse(serializer.DumpJson([]))
865
    self.assertRaises(client.GanetiApiError, self.client.EvacuateNode,
866
                      "node-4", accept_old=True, secondary=False)
867
    self.assertEqual(self.rapi.CountPending(), 0)
868

    
869
    for sec in [True, None]:
870
      self.rapi.AddResponse(serializer.DumpJson([]))
871
      self.rapi.AddResponse(serializer.DumpJson([["res", "foo"]]))
872
      result = self.client.EvacuateNode("node-3", iallocator="hail",
873
                                        dry_run=True, accept_old=True,
874
                                        primary=False, secondary=sec)
875
      self.assertEqual(result, [["res", "foo"]])
876
      self.assertItems(["node-3"])
877
      self.assertQuery("iallocator", ["hail"])
878
      self.assertFalse(self.rapi.GetLastRequestData())
879
      self.assertDryRun()
880
      self.assertEqual(self.rapi.CountPending(), 0)
881

    
882
  def testMigrateNode(self):
883
    self.rapi.AddResponse(serializer.DumpJson([]))
884
    self.rapi.AddResponse("1111")
885
    self.assertEqual(1111, self.client.MigrateNode("node-a", dry_run=True))
886
    self.assertHandler(rlib2.R_2_nodes_name_migrate)
887
    self.assertItems(["node-a"])
888
    self.assert_("mode" not in self.rapi.GetLastHandler().queryargs)
889
    self.assertDryRun()
890
    self.assertFalse(self.rapi.GetLastRequestData())
891

    
892
    self.rapi.AddResponse(serializer.DumpJson([]))
893
    self.rapi.AddResponse("1112")
894
    self.assertEqual(1112, self.client.MigrateNode("node-a", dry_run=True,
895
                                                   mode="live"))
896
    self.assertHandler(rlib2.R_2_nodes_name_migrate)
897
    self.assertItems(["node-a"])
898
    self.assertQuery("mode", ["live"])
899
    self.assertDryRun()
900
    self.assertFalse(self.rapi.GetLastRequestData())
901

    
902
    self.rapi.AddResponse(serializer.DumpJson([]))
903
    self.assertRaises(client.GanetiApiError, self.client.MigrateNode,
904
                      "node-c", target_node="foonode")
905
    self.assertEqual(self.rapi.CountPending(), 0)
906

    
907
  def testMigrateNodeBodyData(self):
908
    self.rapi.AddResponse(serializer.DumpJson([rlib2._NODE_MIGRATE_REQV1]))
909
    self.rapi.AddResponse("27539")
910
    self.assertEqual(27539, self.client.MigrateNode("node-a", dry_run=False,
911
                                                    mode="live"))
912
    self.assertHandler(rlib2.R_2_nodes_name_migrate)
913
    self.assertItems(["node-a"])
914
    self.assertFalse(self.rapi.GetLastHandler().queryargs)
915
    self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
916
                     { "mode": "live", })
917

    
918
    self.rapi.AddResponse(serializer.DumpJson([rlib2._NODE_MIGRATE_REQV1]))
919
    self.rapi.AddResponse("14219")
920
    self.assertEqual(14219, self.client.MigrateNode("node-x", dry_run=True,
921
                                                    target_node="node9",
922
                                                    iallocator="ial"))
923
    self.assertHandler(rlib2.R_2_nodes_name_migrate)
924
    self.assertItems(["node-x"])
925
    self.assertDryRun()
926
    self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
927
                     { "target_node": "node9", "iallocator": "ial", })
928

    
929
    self.assertEqual(self.rapi.CountPending(), 0)
930

    
931
  def testGetNodeRole(self):
932
    self.rapi.AddResponse("\"master\"")
933
    self.assertEqual("master", self.client.GetNodeRole("node-a"))
934
    self.assertHandler(rlib2.R_2_nodes_name_role)
935
    self.assertItems(["node-a"])
936

    
937
  def testSetNodeRole(self):
938
    self.rapi.AddResponse("789")
939
    self.assertEqual(789,
940
        self.client.SetNodeRole("node-foo", "master-candidate", force=True))
941
    self.assertHandler(rlib2.R_2_nodes_name_role)
942
    self.assertItems(["node-foo"])
943
    self.assertQuery("force", ["1"])
944
    self.assertEqual("\"master-candidate\"", self.rapi.GetLastRequestData())
945

    
946
  def testGetNodeStorageUnits(self):
947
    self.rapi.AddResponse("42")
948
    self.assertEqual(42,
949
        self.client.GetNodeStorageUnits("node-x", "lvm-pv", "fields"))
950
    self.assertHandler(rlib2.R_2_nodes_name_storage)
951
    self.assertItems(["node-x"])
952
    self.assertQuery("storage_type", ["lvm-pv"])
953
    self.assertQuery("output_fields", ["fields"])
954

    
955
  def testModifyNodeStorageUnits(self):
956
    self.rapi.AddResponse("14")
957
    self.assertEqual(14,
958
        self.client.ModifyNodeStorageUnits("node-z", "lvm-pv", "hda"))
959
    self.assertHandler(rlib2.R_2_nodes_name_storage_modify)
960
    self.assertItems(["node-z"])
961
    self.assertQuery("storage_type", ["lvm-pv"])
962
    self.assertQuery("name", ["hda"])
963
    self.assertQuery("allocatable", None)
964

    
965
    for allocatable, query_allocatable in [(True, "1"), (False, "0")]:
966
      self.rapi.AddResponse("7205")
967
      job_id = self.client.ModifyNodeStorageUnits("node-z", "lvm-pv", "hda",
968
                                                  allocatable=allocatable)
969
      self.assertEqual(7205, job_id)
970
      self.assertHandler(rlib2.R_2_nodes_name_storage_modify)
971
      self.assertItems(["node-z"])
972
      self.assertQuery("storage_type", ["lvm-pv"])
973
      self.assertQuery("name", ["hda"])
974
      self.assertQuery("allocatable", [query_allocatable])
975

    
976
  def testRepairNodeStorageUnits(self):
977
    self.rapi.AddResponse("99")
978
    self.assertEqual(99, self.client.RepairNodeStorageUnits("node-z", "lvm-pv",
979
                                                            "hda"))
980
    self.assertHandler(rlib2.R_2_nodes_name_storage_repair)
981
    self.assertItems(["node-z"])
982
    self.assertQuery("storage_type", ["lvm-pv"])
983
    self.assertQuery("name", ["hda"])
984

    
985
  def testGetNodeTags(self):
986
    self.rapi.AddResponse("[\"fry\", \"bender\"]")
987
    self.assertEqual(["fry", "bender"], self.client.GetNodeTags("node-k"))
988
    self.assertHandler(rlib2.R_2_nodes_name_tags)
989
    self.assertItems(["node-k"])
990

    
991
  def testAddNodeTags(self):
992
    self.rapi.AddResponse("1234")
993
    self.assertEqual(1234,
994
        self.client.AddNodeTags("node-v", ["awesome"], dry_run=True))
995
    self.assertHandler(rlib2.R_2_nodes_name_tags)
996
    self.assertItems(["node-v"])
997
    self.assertDryRun()
998
    self.assertQuery("tag", ["awesome"])
999

    
1000
  def testDeleteNodeTags(self):
1001
    self.rapi.AddResponse("16861")
1002
    self.assertEqual(16861, self.client.DeleteNodeTags("node-w", ["awesome"],
1003
                                                       dry_run=True))
1004
    self.assertHandler(rlib2.R_2_nodes_name_tags)
1005
    self.assertItems(["node-w"])
1006
    self.assertDryRun()
1007
    self.assertQuery("tag", ["awesome"])
1008

    
1009
  def testGetGroups(self):
1010
    groups = [{"name": "group1",
1011
               "uri": "/2/groups/group1",
1012
               },
1013
              {"name": "group2",
1014
               "uri": "/2/groups/group2",
1015
               },
1016
              ]
1017
    self.rapi.AddResponse(serializer.DumpJson(groups))
1018
    self.assertEqual(["group1", "group2"], self.client.GetGroups())
1019
    self.assertHandler(rlib2.R_2_groups)
1020

    
1021
  def testGetGroupsBulk(self):
1022
    groups = [{"name": "group1",
1023
               "uri": "/2/groups/group1",
1024
               "node_cnt": 2,
1025
               "node_list": ["gnt1.test",
1026
                             "gnt2.test",
1027
                             ],
1028
               },
1029
              {"name": "group2",
1030
               "uri": "/2/groups/group2",
1031
               "node_cnt": 1,
1032
               "node_list": ["gnt3.test",
1033
                             ],
1034
               },
1035
              ]
1036
    self.rapi.AddResponse(serializer.DumpJson(groups))
1037

    
1038
    self.assertEqual(groups, self.client.GetGroups(bulk=True))
1039
    self.assertHandler(rlib2.R_2_groups)
1040
    self.assertBulk()
1041

    
1042
  def testGetGroup(self):
1043
    group = {"ctime": None,
1044
             "name": "default",
1045
             }
1046
    self.rapi.AddResponse(serializer.DumpJson(group))
1047
    self.assertEqual({"ctime": None, "name": "default"},
1048
                     self.client.GetGroup("default"))
1049
    self.assertHandler(rlib2.R_2_groups_name)
1050
    self.assertItems(["default"])
1051

    
1052
  def testCreateGroup(self):
1053
    self.rapi.AddResponse("12345")
1054
    job_id = self.client.CreateGroup("newgroup", dry_run=True)
1055
    self.assertEqual(job_id, 12345)
1056
    self.assertHandler(rlib2.R_2_groups)
1057
    self.assertDryRun()
1058

    
1059
  def testDeleteGroup(self):
1060
    self.rapi.AddResponse("12346")
1061
    job_id = self.client.DeleteGroup("newgroup", dry_run=True)
1062
    self.assertEqual(job_id, 12346)
1063
    self.assertHandler(rlib2.R_2_groups_name)
1064
    self.assertDryRun()
1065

    
1066
  def testRenameGroup(self):
1067
    self.rapi.AddResponse("12347")
1068
    job_id = self.client.RenameGroup("oldname", "newname")
1069
    self.assertEqual(job_id, 12347)
1070
    self.assertHandler(rlib2.R_2_groups_name_rename)
1071

    
1072
  def testModifyGroup(self):
1073
    self.rapi.AddResponse("12348")
1074
    job_id = self.client.ModifyGroup("mygroup", alloc_policy="foo")
1075
    self.assertEqual(job_id, 12348)
1076
    self.assertHandler(rlib2.R_2_groups_name_modify)
1077

    
1078
  def testAssignGroupNodes(self):
1079
    self.rapi.AddResponse("12349")
1080
    job_id = self.client.AssignGroupNodes("mygroup", ["node1", "node2"],
1081
                                          force=True, dry_run=True)
1082
    self.assertEqual(job_id, 12349)
1083
    self.assertHandler(rlib2.R_2_groups_name_assign_nodes)
1084
    self.assertDryRun()
1085
    self.assertUseForce()
1086

    
1087
  def testModifyInstance(self):
1088
    self.rapi.AddResponse("23681")
1089
    job_id = self.client.ModifyInstance("inst7210", os_name="linux")
1090
    self.assertEqual(job_id, 23681)
1091
    self.assertItems(["inst7210"])
1092
    self.assertHandler(rlib2.R_2_instances_name_modify)
1093
    self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
1094
                     { "os_name": "linux", })
1095

    
1096
  def testModifyCluster(self):
1097
    for mnh in [None, False, True]:
1098
      self.rapi.AddResponse("14470")
1099
      self.assertEqual(14470,
1100
        self.client.ModifyCluster(maintain_node_health=mnh))
1101
      self.assertHandler(rlib2.R_2_cluster_modify)
1102
      self.assertItems([])
1103
      data = serializer.LoadJson(self.rapi.GetLastRequestData())
1104
      self.assertEqual(len(data), 1)
1105
      self.assertEqual(data["maintain_node_health"], mnh)
1106
      self.assertEqual(self.rapi.CountPending(), 0)
1107

    
1108
  def testRedistributeConfig(self):
1109
    self.rapi.AddResponse("3364")
1110
    job_id = self.client.RedistributeConfig()
1111
    self.assertEqual(job_id, 3364)
1112
    self.assertItems([])
1113
    self.assertHandler(rlib2.R_2_redist_config)
1114

    
1115
  def testActivateInstanceDisks(self):
1116
    self.rapi.AddResponse("23547")
1117
    job_id = self.client.ActivateInstanceDisks("inst28204")
1118
    self.assertEqual(job_id, 23547)
1119
    self.assertItems(["inst28204"])
1120
    self.assertHandler(rlib2.R_2_instances_name_activate_disks)
1121
    self.assertFalse(self.rapi.GetLastHandler().queryargs)
1122

    
1123
  def testActivateInstanceDisksIgnoreSize(self):
1124
    self.rapi.AddResponse("11044")
1125
    job_id = self.client.ActivateInstanceDisks("inst28204", ignore_size=True)
1126
    self.assertEqual(job_id, 11044)
1127
    self.assertItems(["inst28204"])
1128
    self.assertHandler(rlib2.R_2_instances_name_activate_disks)
1129
    self.assertQuery("ignore_size", ["1"])
1130

    
1131
  def testDeactivateInstanceDisks(self):
1132
    self.rapi.AddResponse("14591")
1133
    job_id = self.client.DeactivateInstanceDisks("inst28234")
1134
    self.assertEqual(job_id, 14591)
1135
    self.assertItems(["inst28234"])
1136
    self.assertHandler(rlib2.R_2_instances_name_deactivate_disks)
1137
    self.assertFalse(self.rapi.GetLastHandler().queryargs)
1138

    
1139
  def testGetInstanceConsole(self):
1140
    self.rapi.AddResponse("26876")
1141
    job_id = self.client.GetInstanceConsole("inst21491")
1142
    self.assertEqual(job_id, 26876)
1143
    self.assertItems(["inst21491"])
1144
    self.assertHandler(rlib2.R_2_instances_name_console)
1145
    self.assertFalse(self.rapi.GetLastHandler().queryargs)
1146
    self.assertFalse(self.rapi.GetLastRequestData())
1147

    
1148
  def testGrowInstanceDisk(self):
1149
    for idx, wait_for_sync in enumerate([None, False, True]):
1150
      amount = 128 + (512 * idx)
1151
      self.assertEqual(self.rapi.CountPending(), 0)
1152
      self.rapi.AddResponse("30783")
1153
      self.assertEqual(30783,
1154
        self.client.GrowInstanceDisk("eze8ch", idx, amount,
1155
                                     wait_for_sync=wait_for_sync))
1156
      self.assertHandler(rlib2.R_2_instances_name_disk_grow)
1157
      self.assertItems(["eze8ch", str(idx)])
1158
      data = serializer.LoadJson(self.rapi.GetLastRequestData())
1159
      if wait_for_sync is None:
1160
        self.assertEqual(len(data), 1)
1161
        self.assert_("wait_for_sync" not in data)
1162
      else:
1163
        self.assertEqual(len(data), 2)
1164
        self.assertEqual(data["wait_for_sync"], wait_for_sync)
1165
      self.assertEqual(data["amount"], amount)
1166
      self.assertEqual(self.rapi.CountPending(), 0)
1167

    
1168
  def testGetGroupTags(self):
1169
    self.rapi.AddResponse("[]")
1170
    self.assertEqual([], self.client.GetGroupTags("fooGroup"))
1171
    self.assertHandler(rlib2.R_2_groups_name_tags)
1172
    self.assertItems(["fooGroup"])
1173

    
1174
  def testAddGroupTags(self):
1175
    self.rapi.AddResponse("1234")
1176
    self.assertEqual(1234,
1177
        self.client.AddGroupTags("fooGroup", ["awesome"], dry_run=True))
1178
    self.assertHandler(rlib2.R_2_groups_name_tags)
1179
    self.assertItems(["fooGroup"])
1180
    self.assertDryRun()
1181
    self.assertQuery("tag", ["awesome"])
1182

    
1183
  def testDeleteGroupTags(self):
1184
    self.rapi.AddResponse("25826")
1185
    self.assertEqual(25826, self.client.DeleteGroupTags("foo", ["awesome"],
1186
                                                        dry_run=True))
1187
    self.assertHandler(rlib2.R_2_groups_name_tags)
1188
    self.assertItems(["foo"])
1189
    self.assertDryRun()
1190
    self.assertQuery("tag", ["awesome"])
1191

    
1192
  def testQuery(self):
1193
    for idx, what in enumerate(constants.QR_VIA_RAPI):
1194
      for idx2, filter_ in enumerate([None, ["?", "name"]]):
1195
        job_id = 11010 + (idx << 4) + (idx2 << 16)
1196
        fields = sorted(query.ALL_FIELDS[what].keys())[:10]
1197

    
1198
        self.rapi.AddResponse(str(job_id))
1199
        self.assertEqual(self.client.Query(what, fields, filter_=filter_),
1200
                         job_id)
1201
        self.assertItems([what])
1202
        self.assertHandler(rlib2.R_2_query)
1203
        self.assertFalse(self.rapi.GetLastHandler().queryargs)
1204
        data = serializer.LoadJson(self.rapi.GetLastRequestData())
1205
        self.assertEqual(data["fields"], fields)
1206
        if filter_ is None:
1207
          self.assertTrue("filter" not in data)
1208
        else:
1209
          self.assertEqual(data["filter"], filter_)
1210
        self.assertEqual(self.rapi.CountPending(), 0)
1211

    
1212
  def testQueryFields(self):
1213
    exp_result = objects.QueryFieldsResponse(fields=[
1214
      objects.QueryFieldDefinition(name="pnode", title="PNode",
1215
                                   kind=constants.QFT_NUMBER),
1216
      objects.QueryFieldDefinition(name="other", title="Other",
1217
                                   kind=constants.QFT_BOOL),
1218
      ])
1219

    
1220
    for what in constants.QR_VIA_RAPI:
1221
      for fields in [None, ["name", "_unknown_"], ["&", "?|"]]:
1222
        self.rapi.AddResponse(serializer.DumpJson(exp_result.ToDict()))
1223
        result = self.client.QueryFields(what, fields=fields)
1224
        self.assertItems([what])
1225
        self.assertHandler(rlib2.R_2_query_fields)
1226
        self.assertFalse(self.rapi.GetLastRequestData())
1227

    
1228
        queryargs = self.rapi.GetLastHandler().queryargs
1229
        if fields is None:
1230
          self.assertFalse(queryargs)
1231
        else:
1232
          self.assertEqual(queryargs, {
1233
            "fields": [",".join(fields)],
1234
            })
1235

    
1236
        self.assertEqual(objects.QueryFieldsResponse.FromDict(result).ToDict(),
1237
                         exp_result.ToDict())
1238

    
1239
        self.assertEqual(self.rapi.CountPending(), 0)
1240

    
1241
  def testWaitForJobCompletionNoChange(self):
1242
    resp = serializer.DumpJson({
1243
      "status": constants.JOB_STATUS_WAITING,
1244
      })
1245

    
1246
    for retries in [1, 5, 25]:
1247
      for _ in range(retries):
1248
        self.rapi.AddResponse(resp)
1249

    
1250
      self.assertFalse(self.client.WaitForJobCompletion(22789, period=None,
1251
                                                        retries=retries))
1252
      self.assertHandler(rlib2.R_2_jobs_id)
1253
      self.assertItems(["22789"])
1254

    
1255
      self.assertEqual(self.rapi.CountPending(), 0)
1256

    
1257
  def testWaitForJobCompletionAlreadyFinished(self):
1258
    self.rapi.AddResponse(serializer.DumpJson({
1259
      "status": constants.JOB_STATUS_SUCCESS,
1260
      }))
1261

    
1262
    self.assertTrue(self.client.WaitForJobCompletion(22793, period=None,
1263
                                                     retries=1))
1264
    self.assertHandler(rlib2.R_2_jobs_id)
1265
    self.assertItems(["22793"])
1266

    
1267
    self.assertEqual(self.rapi.CountPending(), 0)
1268

    
1269
  def testWaitForJobCompletionEmptyResponse(self):
1270
    self.rapi.AddResponse("{}")
1271
    self.assertFalse(self.client.WaitForJobCompletion(22793, period=None,
1272
                                                     retries=10))
1273
    self.assertHandler(rlib2.R_2_jobs_id)
1274
    self.assertItems(["22793"])
1275

    
1276
    self.assertEqual(self.rapi.CountPending(), 0)
1277

    
1278
  def testWaitForJobCompletionOutOfRetries(self):
1279
    for retries in [3, 10, 21]:
1280
      for _ in range(retries):
1281
        self.rapi.AddResponse(serializer.DumpJson({
1282
          "status": constants.JOB_STATUS_RUNNING,
1283
          }))
1284

    
1285
      self.assertFalse(self.client.WaitForJobCompletion(30948, period=None,
1286
                                                        retries=retries - 1))
1287
      self.assertHandler(rlib2.R_2_jobs_id)
1288
      self.assertItems(["30948"])
1289

    
1290
      self.assertEqual(self.rapi.CountPending(), 1)
1291
      self.rapi.ResetResponses()
1292

    
1293
  def testWaitForJobCompletionSuccessAndFailure(self):
1294
    for retries in [1, 4, 13]:
1295
      for (success, end_status) in [(False, constants.JOB_STATUS_ERROR),
1296
                                    (True, constants.JOB_STATUS_SUCCESS)]:
1297
        for _ in range(retries):
1298
          self.rapi.AddResponse(serializer.DumpJson({
1299
            "status": constants.JOB_STATUS_RUNNING,
1300
            }))
1301

    
1302
        self.rapi.AddResponse(serializer.DumpJson({
1303
          "status": end_status,
1304
          }))
1305

    
1306
        result = self.client.WaitForJobCompletion(3187, period=None,
1307
                                                  retries=retries + 1)
1308
        self.assertEqual(result, success)
1309
        self.assertHandler(rlib2.R_2_jobs_id)
1310
        self.assertItems(["3187"])
1311

    
1312
        self.assertEqual(self.rapi.CountPending(), 0)
1313

    
1314

    
1315
class RapiTestRunner(unittest.TextTestRunner):
1316
  def run(self, *args):
1317
    global _used_handlers
1318
    assert _used_handlers is None
1319

    
1320
    _used_handlers = set()
1321
    try:
1322
      # Run actual tests
1323
      result = unittest.TextTestRunner.run(self, *args)
1324

    
1325
      diff = (set(connector.CONNECTOR.values()) - _used_handlers -
1326
             _KNOWN_UNUSED)
1327
      if diff:
1328
        raise AssertionError("The following RAPI resources were not used by the"
1329
                             " RAPI client: %r" % utils.CommaJoin(diff))
1330
    finally:
1331
      # Reset global variable
1332
      _used_handlers = None
1333

    
1334
    return result
1335

    
1336

    
1337
if __name__ == '__main__':
1338
  client.UsesRapiClient(testutils.GanetiTestProgram)(testRunner=RapiTestRunner)