Statistics
| Branch: | Tag: | Revision:

root / test / py / ganeti.rapi.client_unittest.py @ 5470b894

History | View | Annotate | Download (58.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
    # Error codes
141
    self.assertEqual(client.ECODE_RESOLVER, errors.ECODE_RESOLVER)
142
    self.assertEqual(client.ECODE_NORES, errors.ECODE_NORES)
143
    self.assertEqual(client.ECODE_TEMP_NORES, errors.ECODE_TEMP_NORES)
144
    self.assertEqual(client.ECODE_INVAL, errors.ECODE_INVAL)
145
    self.assertEqual(client.ECODE_STATE, errors.ECODE_STATE)
146
    self.assertEqual(client.ECODE_NOENT, errors.ECODE_NOENT)
147
    self.assertEqual(client.ECODE_EXISTS, errors.ECODE_EXISTS)
148
    self.assertEqual(client.ECODE_NOTUNIQUE, errors.ECODE_NOTUNIQUE)
149
    self.assertEqual(client.ECODE_FAULT, errors.ECODE_FAULT)
150
    self.assertEqual(client.ECODE_ENVIRON, errors.ECODE_ENVIRON)
151

    
152
  def testErrors(self):
153
    self.assertEqual(client.ECODE_ALL, errors.ECODE_ALL)
154

    
155
    # Make sure all error codes are in both RAPI client and errors module
156
    for name in filter(lambda s: (s.startswith("ECODE_") and s != "ECODE_ALL"),
157
                       dir(client)):
158
      value = getattr(client, name)
159
      self.assertEqual(value, getattr(errors, name))
160
      self.assertTrue(value in client.ECODE_ALL)
161
      self.assertTrue(value in errors.ECODE_ALL)
162

    
163

    
164
class RapiMockTest(unittest.TestCase):
165
  def test404(self):
166
    (code, _, body) = RapiMock().FetchResponse("/foo", "GET", None, None)
167
    self.assertEqual(code, 404)
168
    self.assertTrue(body is None)
169

    
170
  def test501(self):
171
    (code, _, body) = RapiMock().FetchResponse("/version", "POST", None, None)
172
    self.assertEqual(code, 501)
173
    self.assertEqual(body, "Method not implemented")
174

    
175
  def test200(self):
176
    rapi = RapiMock()
177
    rapi.AddResponse("2")
178
    (code, _, response) = rapi.FetchResponse("/version", "GET", None, None)
179
    self.assertEqual(200, code)
180
    self.assertEqual("2", response)
181
    self.failUnless(isinstance(rapi.GetLastHandler(), rlib2.R_version))
182

    
183

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

    
188

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

    
193

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

    
198

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

    
203

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

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

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

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

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

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

    
245
            curl_factory = lambda: rapi.testutils.FakeCurl(RapiMock())
246
            cl = client.GanetiRapiClient("master.example.com",
247
                                         curl_config_fn=cfgfn,
248
                                         curl_factory=curl_factory)
249

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

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

    
259
  def testNoCertVerify(self):
260
    cfgfn = client.GenericCurlConfig()
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.assertFalse(curl.getopt(pycurl.SSL_VERIFYPEER))
268
    self.assertFalse(curl.getopt(pycurl.CAINFO))
269
    self.assertFalse(curl.getopt(pycurl.CAPATH))
270

    
271
  def testCertVerifyCurlBundle(self):
272
    cfgfn = client.GenericCurlConfig(use_curl_cabundle=True)
273

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

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

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

    
287
    curl_factory = lambda: rapi.testutils.FakeCurl(RapiMock())
288
    cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
289
                                 curl_factory=curl_factory)
290

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

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

    
302
    curl_factory = lambda: rapi.testutils.FakeCurl(RapiMock())
303
    cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
304
                                 curl_factory=curl_factory)
305

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

    
311
  def testCertVerifyCapathGnuTls(self):
312
    certdir = "/tmp/some/UNUSED/cert/directory"
313
    pcverfn = _FakeGnuTlsPycurlVersion
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 testCertVerifyNoSsl(self):
324
    certdir = "/tmp/some/UNUSED/cert/directory"
325
    pcverfn = _FakeNoSslPycurlVersion
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(client.Error, cl._CreateCurl)
334

    
335
  def testCertVerifyFancySsl(self):
336
    certdir = "/tmp/some/UNUSED/cert/directory"
337
    pcverfn = _FakeFancySslPycurlVersion
338
    cfgfn = client.GenericCurlConfig(capath=certdir,
339
                                     _pycurl_version_fn=pcverfn)
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
    self.assertRaises(NotImplementedError, cl._CreateCurl)
346

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

    
353
        curl_factory = lambda: rapi.testutils.FakeCurl(RapiMock())
354
        cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
355
                                     curl_factory=curl_factory)
356

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

    
361

    
362
class GanetiRapiClientTests(testutils.GanetiTestCase):
363
  def setUp(self):
364
    testutils.GanetiTestCase.setUp(self)
365

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

    
371
  def assertHandler(self, handler_cls):
372
    self.failUnless(isinstance(self.rapi.GetLastHandler(), handler_cls))
373

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

    
377
  def assertItems(self, items):
378
    self.assertEqual(items, self.rapi.GetLastHandler().items)
379

    
380
  def assertBulk(self):
381
    self.assertTrue(self.rapi.GetLastHandler().useBulk())
382

    
383
  def assertDryRun(self):
384
    self.assertTrue(self.rapi.GetLastHandler().dryRun())
385

    
386
  def assertUseForce(self):
387
    self.assertTrue(self.rapi.GetLastHandler().useForce())
388

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

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

    
406
    self.assertEqualValues(self.client._EncodeQuery(query),
407
                           expected)
408

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
515
  def testInstancesMultiAlloc(self):
516
    response = {
517
      constants.JOB_IDS_KEY: ["23423"],
518
      constants.ALLOCATABLE_KEY: ["foobar"],
519
      constants.FAILED_KEY: ["foobar2"],
520
      }
521
    self.rapi.AddResponse(serializer.DumpJson(response))
522
    insts = [self.client.InstanceAllocation("create", "foobar",
523
                                            "plain", [], []),
524
             self.client.InstanceAllocation("create", "foobar2",
525
                                            "drbd8", [{"size": 100}], [])]
526
    resp = self.client.InstancesMultiAlloc(insts)
527
    self.assertEqual(resp, response)
528
    self.assertHandler(rlib2.R_2_instances_multi_alloc)
529

    
530
  def testCreateInstanceOldVersion(self):
531
    # The old request format, version 0, is no longer supported
532
    self.rapi.AddResponse(None, code=404)
533
    self.assertRaises(client.GanetiApiError, self.client.CreateInstance,
534
                      "create", "inst1.example.com", "plain", [], [])
535
    self.assertEqual(self.rapi.CountPending(), 0)
536

    
537
  def testCreateInstance(self):
538
    self.rapi.AddResponse(serializer.DumpJson([rlib2._INST_CREATE_REQV1]))
539
    self.rapi.AddResponse("23030")
540
    job_id = self.client.CreateInstance("create", "inst1.example.com",
541
                                        "plain", [], [], dry_run=True)
542
    self.assertEqual(job_id, 23030)
543
    self.assertHandler(rlib2.R_2_instances)
544
    self.assertDryRun()
545

    
546
    data = serializer.LoadJson(self.rapi.GetLastRequestData())
547

    
548
    for field in ["dry_run", "beparams", "hvparams", "start"]:
549
      self.assertFalse(field in data)
550

    
551
    self.assertEqual(data["name"], "inst1.example.com")
552
    self.assertEqual(data["disk_template"], "plain")
553

    
554
  def testCreateInstance2(self):
555
    self.rapi.AddResponse(serializer.DumpJson([rlib2._INST_CREATE_REQV1]))
556
    self.rapi.AddResponse("24740")
557
    job_id = self.client.CreateInstance("import", "inst2.example.com",
558
                                        "drbd8", [{"size": 100,}],
559
                                        [{}, {"bridge": "br1", }],
560
                                        dry_run=False, start=True,
561
                                        pnode="node1", snode="node9",
562
                                        ip_check=False)
563
    self.assertEqual(job_id, 24740)
564
    self.assertHandler(rlib2.R_2_instances)
565

    
566
    data = serializer.LoadJson(self.rapi.GetLastRequestData())
567
    self.assertEqual(data[rlib2._REQ_DATA_VERSION], 1)
568
    self.assertEqual(data["name"], "inst2.example.com")
569
    self.assertEqual(data["disk_template"], "drbd8")
570
    self.assertEqual(data["start"], True)
571
    self.assertEqual(data["ip_check"], False)
572
    self.assertEqualValues(data["disks"], [{"size": 100,}])
573
    self.assertEqualValues(data["nics"], [{}, {"bridge": "br1", }])
574

    
575
  def testDeleteInstance(self):
576
    self.rapi.AddResponse("1234")
577
    self.assertEqual(1234, self.client.DeleteInstance("instance", dry_run=True))
578
    self.assertHandler(rlib2.R_2_instances_name)
579
    self.assertItems(["instance"])
580
    self.assertDryRun()
581

    
582
  def testGetInstanceTags(self):
583
    self.rapi.AddResponse("[]")
584
    self.assertEqual([], self.client.GetInstanceTags("fooinstance"))
585
    self.assertHandler(rlib2.R_2_instances_name_tags)
586
    self.assertItems(["fooinstance"])
587

    
588
  def testAddInstanceTags(self):
589
    self.rapi.AddResponse("1234")
590
    self.assertEqual(1234,
591
        self.client.AddInstanceTags("fooinstance", ["awesome"], dry_run=True))
592
    self.assertHandler(rlib2.R_2_instances_name_tags)
593
    self.assertItems(["fooinstance"])
594
    self.assertDryRun()
595
    self.assertQuery("tag", ["awesome"])
596

    
597
  def testDeleteInstanceTags(self):
598
    self.rapi.AddResponse("25826")
599
    self.assertEqual(25826, self.client.DeleteInstanceTags("foo", ["awesome"],
600
                                                           dry_run=True))
601
    self.assertHandler(rlib2.R_2_instances_name_tags)
602
    self.assertItems(["foo"])
603
    self.assertDryRun()
604
    self.assertQuery("tag", ["awesome"])
605

    
606
  def testRebootInstance(self):
607
    self.rapi.AddResponse("6146")
608
    job_id = self.client.RebootInstance("i-bar", reboot_type="hard",
609
                                        ignore_secondaries=True, dry_run=True,
610
                                        reason="Updates")
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", ["Updates"])
618

    
619
  def testRebootInstanceDefaultReason(self):
620
    self.rapi.AddResponse("6146")
621
    job_id = self.client.RebootInstance("i-bar", reboot_type="hard",
622
                                        ignore_secondaries=True, dry_run=True)
623
    self.assertEqual(6146, job_id)
624
    self.assertHandler(rlib2.R_2_instances_name_reboot)
625
    self.assertItems(["i-bar"])
626
    self.assertDryRun()
627
    self.assertQuery("type", ["hard"])
628
    self.assertQuery("ignore_secondaries", ["1"])
629
    self.assertQuery("reason", None)
630

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

    
641
  def testShutdownInstanceDefaultReason(self):
642
    self.rapi.AddResponse("1487")
643
    self.assertEqual(1487, self.client.ShutdownInstance("foo-instance",
644
                                                        dry_run=True))
645
    self.assertHandler(rlib2.R_2_instances_name_shutdown)
646
    self.assertItems(["foo-instance"])
647
    self.assertDryRun()
648
    self.assertQuery("reason", None)
649

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

    
660
  def testStartupInstanceDefaultReason(self):
661
    self.rapi.AddResponse("27149")
662
    self.assertEqual(27149, self.client.StartupInstance("bar-instance",
663
                                                        dry_run=True))
664
    self.assertHandler(rlib2.R_2_instances_name_startup)
665
    self.assertItems(["bar-instance"])
666
    self.assertDryRun()
667
    self.assertQuery("reason", None)
668

    
669
  def testReinstallInstance(self):
670
    self.rapi.AddResponse(serializer.DumpJson([]))
671
    self.rapi.AddResponse("19119")
672
    self.assertEqual(19119, self.client.ReinstallInstance("baz-instance",
673
                                                          os="DOS",
674
                                                          no_startup=True))
675
    self.assertHandler(rlib2.R_2_instances_name_reinstall)
676
    self.assertItems(["baz-instance"])
677
    self.assertQuery("os", ["DOS"])
678
    self.assertQuery("nostartup", ["1"])
679
    self.assertEqual(self.rapi.CountPending(), 0)
680

    
681
  def testReinstallInstanceNew(self):
682
    self.rapi.AddResponse(serializer.DumpJson([rlib2._INST_REINSTALL_REQV1]))
683
    self.rapi.AddResponse("25689")
684
    self.assertEqual(25689, self.client.ReinstallInstance("moo-instance",
685
                                                          os="Debian",
686
                                                          no_startup=True))
687
    self.assertHandler(rlib2.R_2_instances_name_reinstall)
688
    self.assertItems(["moo-instance"])
689
    data = serializer.LoadJson(self.rapi.GetLastRequestData())
690
    self.assertEqual(len(data), 2)
691
    self.assertEqual(data["os"], "Debian")
692
    self.assertEqual(data["start"], False)
693
    self.assertEqual(self.rapi.CountPending(), 0)
694

    
695
  def testReinstallInstanceWithOsparams1(self):
696
    self.rapi.AddResponse(serializer.DumpJson([]))
697
    self.assertRaises(client.GanetiApiError, self.client.ReinstallInstance,
698
                      "doo-instance", osparams={"x": "y"})
699
    self.assertEqual(self.rapi.CountPending(), 0)
700

    
701
  def testReinstallInstanceWithOsparams2(self):
702
    osparams = {
703
      "Hello": "World",
704
      "foo": "bar",
705
      }
706
    self.rapi.AddResponse(serializer.DumpJson([rlib2._INST_REINSTALL_REQV1]))
707
    self.rapi.AddResponse("1717")
708
    self.assertEqual(1717, self.client.ReinstallInstance("zoo-instance",
709
                                                         osparams=osparams))
710
    self.assertHandler(rlib2.R_2_instances_name_reinstall)
711
    self.assertItems(["zoo-instance"])
712
    data = serializer.LoadJson(self.rapi.GetLastRequestData())
713
    self.assertEqual(len(data), 2)
714
    self.assertEqual(data["osparams"], osparams)
715
    self.assertEqual(data["start"], True)
716
    self.assertEqual(self.rapi.CountPending(), 0)
717

    
718
  def testReplaceInstanceDisks(self):
719
    self.rapi.AddResponse("999")
720
    job_id = self.client.ReplaceInstanceDisks("instance-name",
721
        disks=[0, 1], iallocator="hail")
722
    self.assertEqual(999, job_id)
723
    self.assertHandler(rlib2.R_2_instances_name_replace_disks)
724
    self.assertItems(["instance-name"])
725
    self.assertQuery("disks", ["0,1"])
726
    self.assertQuery("mode", ["replace_auto"])
727
    self.assertQuery("iallocator", ["hail"])
728

    
729
    self.rapi.AddResponse("1000")
730
    job_id = self.client.ReplaceInstanceDisks("instance-bar",
731
        disks=[1], mode="replace_on_secondary", remote_node="foo-node")
732
    self.assertEqual(1000, job_id)
733
    self.assertItems(["instance-bar"])
734
    self.assertQuery("disks", ["1"])
735
    self.assertQuery("remote_node", ["foo-node"])
736

    
737
    self.rapi.AddResponse("5175")
738
    self.assertEqual(5175, self.client.ReplaceInstanceDisks("instance-moo"))
739
    self.assertItems(["instance-moo"])
740
    self.assertQuery("disks", None)
741

    
742
  def testPrepareExport(self):
743
    self.rapi.AddResponse("8326")
744
    self.assertEqual(8326, self.client.PrepareExport("inst1", "local"))
745
    self.assertHandler(rlib2.R_2_instances_name_prepare_export)
746
    self.assertItems(["inst1"])
747
    self.assertQuery("mode", ["local"])
748

    
749
  def testExportInstance(self):
750
    self.rapi.AddResponse("19695")
751
    job_id = self.client.ExportInstance("inst2", "local", "nodeX",
752
                                        shutdown=True)
753
    self.assertEqual(job_id, 19695)
754
    self.assertHandler(rlib2.R_2_instances_name_export)
755
    self.assertItems(["inst2"])
756

    
757
    data = serializer.LoadJson(self.rapi.GetLastRequestData())
758
    self.assertEqual(data["mode"], "local")
759
    self.assertEqual(data["destination"], "nodeX")
760
    self.assertEqual(data["shutdown"], True)
761

    
762
  def testMigrateInstanceDefaults(self):
763
    self.rapi.AddResponse("24873")
764
    job_id = self.client.MigrateInstance("inst91")
765
    self.assertEqual(job_id, 24873)
766
    self.assertHandler(rlib2.R_2_instances_name_migrate)
767
    self.assertItems(["inst91"])
768

    
769
    data = serializer.LoadJson(self.rapi.GetLastRequestData())
770
    self.assertFalse(data)
771

    
772
  def testMigrateInstance(self):
773
    for mode in constants.HT_MIGRATION_MODES:
774
      for cleanup in [False, True]:
775
        self.rapi.AddResponse("31910")
776
        job_id = self.client.MigrateInstance("inst289", mode=mode,
777
                                             cleanup=cleanup)
778
        self.assertEqual(job_id, 31910)
779
        self.assertHandler(rlib2.R_2_instances_name_migrate)
780
        self.assertItems(["inst289"])
781

    
782
        data = serializer.LoadJson(self.rapi.GetLastRequestData())
783
        self.assertEqual(len(data), 2)
784
        self.assertEqual(data["mode"], mode)
785
        self.assertEqual(data["cleanup"], cleanup)
786

    
787
  def testFailoverInstanceDefaults(self):
788
    self.rapi.AddResponse("7639")
789
    job_id = self.client.FailoverInstance("inst13579")
790
    self.assertEqual(job_id, 7639)
791
    self.assertHandler(rlib2.R_2_instances_name_failover)
792
    self.assertItems(["inst13579"])
793

    
794
    data = serializer.LoadJson(self.rapi.GetLastRequestData())
795
    self.assertFalse(data)
796

    
797
  def testFailoverInstance(self):
798
    for iallocator in ["dumb", "hail"]:
799
      for ignore_consistency in [False, True]:
800
        for target_node in ["node-a", "node2"]:
801
          self.rapi.AddResponse("19161")
802
          job_id = \
803
            self.client.FailoverInstance("inst251", iallocator=iallocator,
804
                                         ignore_consistency=ignore_consistency,
805
                                         target_node=target_node)
806
          self.assertEqual(job_id, 19161)
807
          self.assertHandler(rlib2.R_2_instances_name_failover)
808
          self.assertItems(["inst251"])
809

    
810
          data = serializer.LoadJson(self.rapi.GetLastRequestData())
811
          self.assertEqual(len(data), 3)
812
          self.assertEqual(data["iallocator"], iallocator)
813
          self.assertEqual(data["ignore_consistency"], ignore_consistency)
814
          self.assertEqual(data["target_node"], target_node)
815
          self.assertEqual(self.rapi.CountPending(), 0)
816

    
817
  def testRenameInstanceDefaults(self):
818
    new_name = "newnametha7euqu"
819
    self.rapi.AddResponse("8791")
820
    job_id = self.client.RenameInstance("inst18821", new_name)
821
    self.assertEqual(job_id, 8791)
822
    self.assertHandler(rlib2.R_2_instances_name_rename)
823
    self.assertItems(["inst18821"])
824

    
825
    data = serializer.LoadJson(self.rapi.GetLastRequestData())
826
    self.assertEqualValues(data, {"new_name": new_name, })
827

    
828
  def testRenameInstance(self):
829
    new_name = "new-name-yiux1iin"
830
    for ip_check in [False, True]:
831
      for name_check in [False, True]:
832
        self.rapi.AddResponse("24776")
833
        job_id = self.client.RenameInstance("inst20967", new_name,
834
                                             ip_check=ip_check,
835
                                             name_check=name_check)
836
        self.assertEqual(job_id, 24776)
837
        self.assertHandler(rlib2.R_2_instances_name_rename)
838
        self.assertItems(["inst20967"])
839

    
840
        data = serializer.LoadJson(self.rapi.GetLastRequestData())
841
        self.assertEqual(len(data), 3)
842
        self.assertEqual(data["new_name"], new_name)
843
        self.assertEqual(data["ip_check"], ip_check)
844
        self.assertEqual(data["name_check"], name_check)
845

    
846
  def testGetJobs(self):
847
    self.rapi.AddResponse('[ { "id": "123", "uri": "\\/2\\/jobs\\/123" },'
848
                          '  { "id": "124", "uri": "\\/2\\/jobs\\/124" } ]')
849
    self.assertEqual([123, 124], self.client.GetJobs())
850
    self.assertHandler(rlib2.R_2_jobs)
851

    
852
    self.rapi.AddResponse('[ { "id": "123", "uri": "\\/2\\/jobs\\/123" },'
853
                          '  { "id": "124", "uri": "\\/2\\/jobs\\/124" } ]')
854
    self.assertEqual([{"id": "123", "uri": "/2/jobs/123"},
855
                      {"id": "124", "uri": "/2/jobs/124"}],
856
                      self.client.GetJobs(bulk=True))
857
    self.assertHandler(rlib2.R_2_jobs)
858
    self.assertBulk()
859

    
860
  def testGetJobStatus(self):
861
    self.rapi.AddResponse("{\"foo\": \"bar\"}")
862
    self.assertEqual({"foo": "bar"}, self.client.GetJobStatus(1234))
863
    self.assertHandler(rlib2.R_2_jobs_id)
864
    self.assertItems(["1234"])
865

    
866
  def testWaitForJobChange(self):
867
    fields = ["id", "summary"]
868
    expected = {
869
      "job_info": [123, "something"],
870
      "log_entries": [],
871
      }
872

    
873
    self.rapi.AddResponse(serializer.DumpJson(expected))
874
    result = self.client.WaitForJobChange(123, fields, [], -1)
875
    self.assertEqualValues(expected, result)
876
    self.assertHandler(rlib2.R_2_jobs_id_wait)
877
    self.assertItems(["123"])
878

    
879
  def testCancelJob(self):
880
    self.rapi.AddResponse("[true, \"Job 123 will be canceled\"]")
881
    self.assertEqual([True, "Job 123 will be canceled"],
882
                     self.client.CancelJob(999, dry_run=True))
883
    self.assertHandler(rlib2.R_2_jobs_id)
884
    self.assertItems(["999"])
885
    self.assertDryRun()
886

    
887
  def testGetNodes(self):
888
    self.rapi.AddResponse("[ { \"id\": \"node1\", \"uri\": \"uri1\" },"
889
                          " { \"id\": \"node2\", \"uri\": \"uri2\" } ]")
890
    self.assertEqual(["node1", "node2"], self.client.GetNodes())
891
    self.assertHandler(rlib2.R_2_nodes)
892

    
893
    self.rapi.AddResponse("[ { \"id\": \"node1\", \"uri\": \"uri1\" },"
894
                          " { \"id\": \"node2\", \"uri\": \"uri2\" } ]")
895
    self.assertEqual([{"id": "node1", "uri": "uri1"},
896
                      {"id": "node2", "uri": "uri2"}],
897
                     self.client.GetNodes(bulk=True))
898
    self.assertHandler(rlib2.R_2_nodes)
899
    self.assertBulk()
900

    
901
  def testGetNode(self):
902
    self.rapi.AddResponse("{}")
903
    self.assertEqual({}, self.client.GetNode("node-foo"))
904
    self.assertHandler(rlib2.R_2_nodes_name)
905
    self.assertItems(["node-foo"])
906

    
907
  def testEvacuateNode(self):
908
    self.rapi.AddResponse(serializer.DumpJson([rlib2._NODE_EVAC_RES1]))
909
    self.rapi.AddResponse("9876")
910
    job_id = self.client.EvacuateNode("node-1", remote_node="node-2")
911
    self.assertEqual(9876, job_id)
912
    self.assertHandler(rlib2.R_2_nodes_name_evacuate)
913
    self.assertItems(["node-1"])
914
    self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
915
                     { "remote_node": "node-2", })
916
    self.assertEqual(self.rapi.CountPending(), 0)
917

    
918
    self.rapi.AddResponse(serializer.DumpJson([rlib2._NODE_EVAC_RES1]))
919
    self.rapi.AddResponse("8888")
920
    job_id = self.client.EvacuateNode("node-3", iallocator="hail", dry_run=True,
921
                                      mode=constants.NODE_EVAC_ALL,
922
                                      early_release=True)
923
    self.assertEqual(8888, job_id)
924
    self.assertItems(["node-3"])
925
    self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()), {
926
      "iallocator": "hail",
927
      "mode": "all",
928
      "early_release": True,
929
      })
930
    self.assertDryRun()
931

    
932
    self.assertRaises(client.GanetiApiError,
933
                      self.client.EvacuateNode,
934
                      "node-4", iallocator="hail", remote_node="node-5")
935
    self.assertEqual(self.rapi.CountPending(), 0)
936

    
937
  def testEvacuateNodeOldResponse(self):
938
    self.rapi.AddResponse(serializer.DumpJson([]))
939
    self.assertRaises(client.GanetiApiError, self.client.EvacuateNode,
940
                      "node-4", accept_old=False)
941
    self.assertEqual(self.rapi.CountPending(), 0)
942

    
943
    for mode in [client.NODE_EVAC_PRI, client.NODE_EVAC_ALL]:
944
      self.rapi.AddResponse(serializer.DumpJson([]))
945
      self.assertRaises(client.GanetiApiError, self.client.EvacuateNode,
946
                        "node-4", accept_old=True, mode=mode)
947
      self.assertEqual(self.rapi.CountPending(), 0)
948

    
949
    self.rapi.AddResponse(serializer.DumpJson([]))
950
    self.rapi.AddResponse(serializer.DumpJson("21533"))
951
    result = self.client.EvacuateNode("node-3", iallocator="hail",
952
                                      dry_run=True, accept_old=True,
953
                                      mode=client.NODE_EVAC_SEC,
954
                                      early_release=True)
955
    self.assertEqual(result, "21533")
956
    self.assertItems(["node-3"])
957
    self.assertQuery("iallocator", ["hail"])
958
    self.assertQuery("early_release", ["1"])
959
    self.assertFalse(self.rapi.GetLastRequestData())
960
    self.assertDryRun()
961
    self.assertEqual(self.rapi.CountPending(), 0)
962

    
963
  def testMigrateNode(self):
964
    self.rapi.AddResponse(serializer.DumpJson([]))
965
    self.rapi.AddResponse("1111")
966
    self.assertEqual(1111, self.client.MigrateNode("node-a", dry_run=True))
967
    self.assertHandler(rlib2.R_2_nodes_name_migrate)
968
    self.assertItems(["node-a"])
969
    self.assert_("mode" not in self.rapi.GetLastHandler().queryargs)
970
    self.assertDryRun()
971
    self.assertFalse(self.rapi.GetLastRequestData())
972

    
973
    self.rapi.AddResponse(serializer.DumpJson([]))
974
    self.rapi.AddResponse("1112")
975
    self.assertEqual(1112, self.client.MigrateNode("node-a", dry_run=True,
976
                                                   mode="live"))
977
    self.assertHandler(rlib2.R_2_nodes_name_migrate)
978
    self.assertItems(["node-a"])
979
    self.assertQuery("mode", ["live"])
980
    self.assertDryRun()
981
    self.assertFalse(self.rapi.GetLastRequestData())
982

    
983
    self.rapi.AddResponse(serializer.DumpJson([]))
984
    self.assertRaises(client.GanetiApiError, self.client.MigrateNode,
985
                      "node-c", target_node="foonode")
986
    self.assertEqual(self.rapi.CountPending(), 0)
987

    
988
  def testMigrateNodeBodyData(self):
989
    self.rapi.AddResponse(serializer.DumpJson([rlib2._NODE_MIGRATE_REQV1]))
990
    self.rapi.AddResponse("27539")
991
    self.assertEqual(27539, self.client.MigrateNode("node-a", dry_run=False,
992
                                                    mode="live"))
993
    self.assertHandler(rlib2.R_2_nodes_name_migrate)
994
    self.assertItems(["node-a"])
995
    self.assertFalse(self.rapi.GetLastHandler().queryargs)
996
    self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
997
                     { "mode": "live", })
998

    
999
    self.rapi.AddResponse(serializer.DumpJson([rlib2._NODE_MIGRATE_REQV1]))
1000
    self.rapi.AddResponse("14219")
1001
    self.assertEqual(14219, self.client.MigrateNode("node-x", dry_run=True,
1002
                                                    target_node="node9",
1003
                                                    iallocator="ial"))
1004
    self.assertHandler(rlib2.R_2_nodes_name_migrate)
1005
    self.assertItems(["node-x"])
1006
    self.assertDryRun()
1007
    self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
1008
                     { "target_node": "node9", "iallocator": "ial", })
1009

    
1010
    self.assertEqual(self.rapi.CountPending(), 0)
1011

    
1012
  def testGetNodeRole(self):
1013
    self.rapi.AddResponse("\"master\"")
1014
    self.assertEqual("master", self.client.GetNodeRole("node-a"))
1015
    self.assertHandler(rlib2.R_2_nodes_name_role)
1016
    self.assertItems(["node-a"])
1017

    
1018
  def testSetNodeRole(self):
1019
    self.rapi.AddResponse("789")
1020
    self.assertEqual(789,
1021
        self.client.SetNodeRole("node-foo", "master-candidate", force=True))
1022
    self.assertHandler(rlib2.R_2_nodes_name_role)
1023
    self.assertItems(["node-foo"])
1024
    self.assertQuery("force", ["1"])
1025
    self.assertEqual("\"master-candidate\"", self.rapi.GetLastRequestData())
1026

    
1027
  def testPowercycleNode(self):
1028
    self.rapi.AddResponse("23051")
1029
    self.assertEqual(23051,
1030
        self.client.PowercycleNode("node5468", force=True))
1031
    self.assertHandler(rlib2.R_2_nodes_name_powercycle)
1032
    self.assertItems(["node5468"])
1033
    self.assertQuery("force", ["1"])
1034
    self.assertFalse(self.rapi.GetLastRequestData())
1035
    self.assertEqual(self.rapi.CountPending(), 0)
1036

    
1037
  def testModifyNode(self):
1038
    self.rapi.AddResponse("3783")
1039
    job_id = self.client.ModifyNode("node16979.example.com", drained=True)
1040
    self.assertEqual(job_id, 3783)
1041
    self.assertHandler(rlib2.R_2_nodes_name_modify)
1042
    self.assertItems(["node16979.example.com"])
1043
    self.assertEqual(self.rapi.CountPending(), 0)
1044

    
1045
  def testGetNodeStorageUnits(self):
1046
    self.rapi.AddResponse("42")
1047
    self.assertEqual(42,
1048
        self.client.GetNodeStorageUnits("node-x", "lvm-pv", "fields"))
1049
    self.assertHandler(rlib2.R_2_nodes_name_storage)
1050
    self.assertItems(["node-x"])
1051
    self.assertQuery("storage_type", ["lvm-pv"])
1052
    self.assertQuery("output_fields", ["fields"])
1053

    
1054
  def testModifyNodeStorageUnits(self):
1055
    self.rapi.AddResponse("14")
1056
    self.assertEqual(14,
1057
        self.client.ModifyNodeStorageUnits("node-z", "lvm-pv", "hda"))
1058
    self.assertHandler(rlib2.R_2_nodes_name_storage_modify)
1059
    self.assertItems(["node-z"])
1060
    self.assertQuery("storage_type", ["lvm-pv"])
1061
    self.assertQuery("name", ["hda"])
1062
    self.assertQuery("allocatable", None)
1063

    
1064
    for allocatable, query_allocatable in [(True, "1"), (False, "0")]:
1065
      self.rapi.AddResponse("7205")
1066
      job_id = self.client.ModifyNodeStorageUnits("node-z", "lvm-pv", "hda",
1067
                                                  allocatable=allocatable)
1068
      self.assertEqual(7205, job_id)
1069
      self.assertHandler(rlib2.R_2_nodes_name_storage_modify)
1070
      self.assertItems(["node-z"])
1071
      self.assertQuery("storage_type", ["lvm-pv"])
1072
      self.assertQuery("name", ["hda"])
1073
      self.assertQuery("allocatable", [query_allocatable])
1074

    
1075
  def testRepairNodeStorageUnits(self):
1076
    self.rapi.AddResponse("99")
1077
    self.assertEqual(99, self.client.RepairNodeStorageUnits("node-z", "lvm-pv",
1078
                                                            "hda"))
1079
    self.assertHandler(rlib2.R_2_nodes_name_storage_repair)
1080
    self.assertItems(["node-z"])
1081
    self.assertQuery("storage_type", ["lvm-pv"])
1082
    self.assertQuery("name", ["hda"])
1083

    
1084
  def testGetNodeTags(self):
1085
    self.rapi.AddResponse("[\"fry\", \"bender\"]")
1086
    self.assertEqual(["fry", "bender"], self.client.GetNodeTags("node-k"))
1087
    self.assertHandler(rlib2.R_2_nodes_name_tags)
1088
    self.assertItems(["node-k"])
1089

    
1090
  def testAddNodeTags(self):
1091
    self.rapi.AddResponse("1234")
1092
    self.assertEqual(1234,
1093
        self.client.AddNodeTags("node-v", ["awesome"], dry_run=True))
1094
    self.assertHandler(rlib2.R_2_nodes_name_tags)
1095
    self.assertItems(["node-v"])
1096
    self.assertDryRun()
1097
    self.assertQuery("tag", ["awesome"])
1098

    
1099
  def testDeleteNodeTags(self):
1100
    self.rapi.AddResponse("16861")
1101
    self.assertEqual(16861, self.client.DeleteNodeTags("node-w", ["awesome"],
1102
                                                       dry_run=True))
1103
    self.assertHandler(rlib2.R_2_nodes_name_tags)
1104
    self.assertItems(["node-w"])
1105
    self.assertDryRun()
1106
    self.assertQuery("tag", ["awesome"])
1107

    
1108
  def testGetGroups(self):
1109
    groups = [{"name": "group1",
1110
               "uri": "/2/groups/group1",
1111
               },
1112
              {"name": "group2",
1113
               "uri": "/2/groups/group2",
1114
               },
1115
              ]
1116
    self.rapi.AddResponse(serializer.DumpJson(groups))
1117
    self.assertEqual(["group1", "group2"], self.client.GetGroups())
1118
    self.assertHandler(rlib2.R_2_groups)
1119

    
1120
  def testGetGroupsBulk(self):
1121
    groups = [{"name": "group1",
1122
               "uri": "/2/groups/group1",
1123
               "node_cnt": 2,
1124
               "node_list": ["gnt1.test",
1125
                             "gnt2.test",
1126
                             ],
1127
               },
1128
              {"name": "group2",
1129
               "uri": "/2/groups/group2",
1130
               "node_cnt": 1,
1131
               "node_list": ["gnt3.test",
1132
                             ],
1133
               },
1134
              ]
1135
    self.rapi.AddResponse(serializer.DumpJson(groups))
1136

    
1137
    self.assertEqual(groups, self.client.GetGroups(bulk=True))
1138
    self.assertHandler(rlib2.R_2_groups)
1139
    self.assertBulk()
1140

    
1141
  def testGetGroup(self):
1142
    group = {"ctime": None,
1143
             "name": "default",
1144
             }
1145
    self.rapi.AddResponse(serializer.DumpJson(group))
1146
    self.assertEqual({"ctime": None, "name": "default"},
1147
                     self.client.GetGroup("default"))
1148
    self.assertHandler(rlib2.R_2_groups_name)
1149
    self.assertItems(["default"])
1150

    
1151
  def testCreateGroup(self):
1152
    self.rapi.AddResponse("12345")
1153
    job_id = self.client.CreateGroup("newgroup", dry_run=True)
1154
    self.assertEqual(job_id, 12345)
1155
    self.assertHandler(rlib2.R_2_groups)
1156
    self.assertDryRun()
1157

    
1158
  def testDeleteGroup(self):
1159
    self.rapi.AddResponse("12346")
1160
    job_id = self.client.DeleteGroup("newgroup", dry_run=True)
1161
    self.assertEqual(job_id, 12346)
1162
    self.assertHandler(rlib2.R_2_groups_name)
1163
    self.assertDryRun()
1164

    
1165
  def testRenameGroup(self):
1166
    self.rapi.AddResponse("12347")
1167
    job_id = self.client.RenameGroup("oldname", "newname")
1168
    self.assertEqual(job_id, 12347)
1169
    self.assertHandler(rlib2.R_2_groups_name_rename)
1170

    
1171
  def testModifyGroup(self):
1172
    self.rapi.AddResponse("12348")
1173
    job_id = self.client.ModifyGroup("mygroup", alloc_policy="foo")
1174
    self.assertEqual(job_id, 12348)
1175
    self.assertHandler(rlib2.R_2_groups_name_modify)
1176

    
1177
  def testAssignGroupNodes(self):
1178
    self.rapi.AddResponse("12349")
1179
    job_id = self.client.AssignGroupNodes("mygroup", ["node1", "node2"],
1180
                                          force=True, dry_run=True)
1181
    self.assertEqual(job_id, 12349)
1182
    self.assertHandler(rlib2.R_2_groups_name_assign_nodes)
1183
    self.assertDryRun()
1184
    self.assertUseForce()
1185

    
1186
  def testGetNetworksBulk(self):
1187
    networks = [{"name": "network1",
1188
               "uri": "/2/networks/network1",
1189
               "network": "192.168.0.0/24",
1190
               },
1191
              {"name": "network2",
1192
               "uri": "/2/networks/network2",
1193
               "network": "192.168.0.0/24",
1194
               },
1195
              ]
1196
    self.rapi.AddResponse(serializer.DumpJson(networks))
1197

    
1198
    self.assertEqual(networks, self.client.GetNetworks(bulk=True))
1199
    self.assertHandler(rlib2.R_2_networks)
1200
    self.assertBulk()
1201

    
1202
  def testGetNetwork(self):
1203
    network = {"ctime": None,
1204
               "name": "network1",
1205
               }
1206
    self.rapi.AddResponse(serializer.DumpJson(network))
1207
    self.assertEqual({"ctime": None, "name": "network1"},
1208
                     self.client.GetNetwork("network1"))
1209
    self.assertHandler(rlib2.R_2_networks_name)
1210
    self.assertItems(["network1"])
1211

    
1212
  def testCreateNetwork(self):
1213
    self.rapi.AddResponse("12345")
1214
    job_id = self.client.CreateNetwork("newnetwork", network="192.168.0.0/24",
1215
                                       dry_run=True)
1216
    self.assertEqual(job_id, 12345)
1217
    self.assertHandler(rlib2.R_2_networks)
1218
    self.assertDryRun()
1219

    
1220
  def testModifyNetwork(self):
1221
    self.rapi.AddResponse("12346")
1222
    job_id = self.client.ModifyNetwork("mynetwork", gateway="192.168.0.10",
1223
                                     dry_run=True)
1224
    self.assertEqual(job_id, 12346)
1225
    self.assertHandler(rlib2.R_2_networks_name_modify)
1226

    
1227
  def testDeleteNetwork(self):
1228
    self.rapi.AddResponse("12347")
1229
    job_id = self.client.DeleteNetwork("newnetwork", dry_run=True)
1230
    self.assertEqual(job_id, 12347)
1231
    self.assertHandler(rlib2.R_2_networks_name)
1232
    self.assertDryRun()
1233

    
1234
  def testConnectNetwork(self):
1235
    self.rapi.AddResponse("12348")
1236
    job_id = self.client.ConnectNetwork("mynetwork", "default",
1237
                                        "bridged", "br0", dry_run=True)
1238
    self.assertEqual(job_id, 12348)
1239
    self.assertHandler(rlib2.R_2_networks_name_connect)
1240
    self.assertDryRun()
1241

    
1242
  def testDisconnectNetwork(self):
1243
    self.rapi.AddResponse("12349")
1244
    job_id = self.client.DisconnectNetwork("mynetwork", "default", dry_run=True)
1245
    self.assertEqual(job_id, 12349)
1246
    self.assertHandler(rlib2.R_2_networks_name_disconnect)
1247
    self.assertDryRun()
1248

    
1249
  def testGetNetworkTags(self):
1250
    self.rapi.AddResponse("[]")
1251
    self.assertEqual([], self.client.GetNetworkTags("fooNetwork"))
1252
    self.assertHandler(rlib2.R_2_networks_name_tags)
1253
    self.assertItems(["fooNetwork"])
1254

    
1255
  def testAddNetworkTags(self):
1256
    self.rapi.AddResponse("1234")
1257
    self.assertEqual(1234,
1258
        self.client.AddNetworkTags("fooNetwork", ["awesome"], dry_run=True))
1259
    self.assertHandler(rlib2.R_2_networks_name_tags)
1260
    self.assertItems(["fooNetwork"])
1261
    self.assertDryRun()
1262
    self.assertQuery("tag", ["awesome"])
1263

    
1264
  def testDeleteNetworkTags(self):
1265
    self.rapi.AddResponse("25826")
1266
    self.assertEqual(25826, self.client.DeleteNetworkTags("foo", ["awesome"],
1267
                                                          dry_run=True))
1268
    self.assertHandler(rlib2.R_2_networks_name_tags)
1269
    self.assertItems(["foo"])
1270
    self.assertDryRun()
1271
    self.assertQuery("tag", ["awesome"])
1272

    
1273
  def testModifyInstance(self):
1274
    self.rapi.AddResponse("23681")
1275
    job_id = self.client.ModifyInstance("inst7210", os_name="linux")
1276
    self.assertEqual(job_id, 23681)
1277
    self.assertItems(["inst7210"])
1278
    self.assertHandler(rlib2.R_2_instances_name_modify)
1279
    self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
1280
                     { "os_name": "linux", })
1281

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1430
        self.assertEqual(objects.QueryFieldsResponse.FromDict(result).ToDict(),
1431
                         exp_result.ToDict())
1432

    
1433
        self.assertEqual(self.rapi.CountPending(), 0)
1434

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

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

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

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

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

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

    
1461
    self.assertEqual(self.rapi.CountPending(), 0)
1462

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

    
1470
    self.assertEqual(self.rapi.CountPending(), 0)
1471

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

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

    
1484
      self.assertEqual(self.rapi.CountPending(), 1)
1485
      self.rapi.ResetResponses()
1486

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

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

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

    
1506
        self.assertEqual(self.rapi.CountPending(), 0)
1507

    
1508

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

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

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

    
1528
    return result
1529

    
1530

    
1531
if __name__ == "__main__":
1532
  client.UsesRapiClient(testutils.GanetiTestProgram)(testRunner=RapiTestRunner)