Statistics
| Branch: | Tag: | Revision:

root / test / ganeti.rapi.client_unittest.py @ 26d3fd2f

History | View | Annotate | Download (34 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

    
34
from ganeti.rapi import connector
35
from ganeti.rapi import rlib2
36
from ganeti.rapi import client
37

    
38
import testutils
39

    
40

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

    
43

    
44
def _GetPathFromUri(uri):
45
  """Gets the path and query from a URI.
46

47
  """
48
  match = _URI_RE.match(uri)
49
  if match:
50
    return match.groupdict()["path"]
51
  else:
52
    return None
53

    
54

    
55
class FakeCurl:
56
  def __init__(self, rapi):
57
    self._rapi = rapi
58
    self._opts = {}
59
    self._info = {}
60

    
61
  def setopt(self, opt, value):
62
    self._opts[opt] = value
63

    
64
  def getopt(self, opt):
65
    return self._opts.get(opt)
66

    
67
  def unsetopt(self, opt):
68
    self._opts.pop(opt, None)
69

    
70
  def getinfo(self, info):
71
    return self._info[info]
72

    
73
  def perform(self):
74
    method = self._opts[pycurl.CUSTOMREQUEST]
75
    url = self._opts[pycurl.URL]
76
    request_body = self._opts[pycurl.POSTFIELDS]
77
    writefn = self._opts[pycurl.WRITEFUNCTION]
78

    
79
    path = _GetPathFromUri(url)
80
    (code, resp_body) = self._rapi.FetchResponse(path, method, request_body)
81

    
82
    self._info[pycurl.RESPONSE_CODE] = code
83
    if resp_body is not None:
84
      writefn(resp_body)
85

    
86

    
87
class RapiMock(object):
88
  def __init__(self):
89
    self._mapper = connector.Mapper()
90
    self._responses = []
91
    self._last_handler = None
92
    self._last_req_data = None
93

    
94
  def AddResponse(self, response, code=200):
95
    self._responses.insert(0, (code, response))
96

    
97
  def CountPending(self):
98
    return len(self._responses)
99

    
100
  def GetLastHandler(self):
101
    return self._last_handler
102

    
103
  def GetLastRequestData(self):
104
    return self._last_req_data
105

    
106
  def FetchResponse(self, path, method, request_body):
107
    self._last_req_data = request_body
108

    
109
    try:
110
      HandlerClass, items, args = self._mapper.getController(path)
111
      self._last_handler = HandlerClass(items, args, None)
112
      if not hasattr(self._last_handler, method.upper()):
113
        raise http.HttpNotImplemented(message="Method not implemented")
114

    
115
    except http.HttpException, ex:
116
      code = ex.code
117
      response = ex.message
118
    else:
119
      if not self._responses:
120
        raise Exception("No responses")
121

    
122
      (code, response) = self._responses.pop()
123

    
124
    return code, response
125

    
126

    
127
class TestConstants(unittest.TestCase):
128
  def test(self):
129
    self.assertEqual(client.GANETI_RAPI_PORT, constants.DEFAULT_RAPI_PORT)
130
    self.assertEqual(client.GANETI_RAPI_VERSION, constants.RAPI_VERSION)
131
    self.assertEqual(client.HTTP_APP_JSON, http.HTTP_APP_JSON)
132
    self.assertEqual(client._REQ_DATA_VERSION_FIELD, rlib2._REQ_DATA_VERSION)
133
    self.assertEqual(client._INST_CREATE_REQV1, rlib2._INST_CREATE_REQV1)
134
    self.assertEqual(client._INST_NIC_PARAMS, constants.INIC_PARAMS)
135

    
136

    
137
class RapiMockTest(unittest.TestCase):
138
  def test(self):
139
    rapi = RapiMock()
140
    path = "/version"
141
    self.assertEqual((404, None), rapi.FetchResponse("/foo", "GET", None))
142
    self.assertEqual((501, "Method not implemented"),
143
                     rapi.FetchResponse("/version", "POST", None))
144
    rapi.AddResponse("2")
145
    code, response = rapi.FetchResponse("/version", "GET", None)
146
    self.assertEqual(200, code)
147
    self.assertEqual("2", response)
148
    self.failUnless(isinstance(rapi.GetLastHandler(), rlib2.R_version))
149

    
150

    
151
def _FakeNoSslPycurlVersion():
152
  # Note: incomplete version tuple
153
  return (3, "7.16.0", 462848, "mysystem", 1581, None, 0)
154

    
155

    
156
def _FakeFancySslPycurlVersion():
157
  # Note: incomplete version tuple
158
  return (3, "7.16.0", 462848, "mysystem", 1581, "FancySSL/1.2.3", 0)
159

    
160

    
161
def _FakeOpenSslPycurlVersion():
162
  # Note: incomplete version tuple
163
  return (2, "7.15.5", 462597, "othersystem", 668, "OpenSSL/0.9.8c", 0)
164

    
165

    
166
def _FakeGnuTlsPycurlVersion():
167
  # Note: incomplete version tuple
168
  return (3, "7.18.0", 463360, "somesystem", 1581, "GnuTLS/2.0.4", 0)
169

    
170

    
171
class TestExtendedConfig(unittest.TestCase):
172
  def testAuth(self):
173
    cl = client.GanetiRapiClient("master.example.com",
174
                                 username="user", password="pw",
175
                                 curl_factory=lambda: FakeCurl(RapiMock()))
176

    
177
    curl = cl._CreateCurl()
178
    self.assertEqual(curl.getopt(pycurl.HTTPAUTH), pycurl.HTTPAUTH_BASIC)
179
    self.assertEqual(curl.getopt(pycurl.USERPWD), "user:pw")
180

    
181
  def testInvalidAuth(self):
182
    # No username
183
    self.assertRaises(client.Error, client.GanetiRapiClient,
184
                      "master-a.example.com", password="pw")
185
    # No password
186
    self.assertRaises(client.Error, client.GanetiRapiClient,
187
                      "master-b.example.com", username="user")
188

    
189
  def testCertVerifyInvalidCombinations(self):
190
    self.assertRaises(client.Error, client.GenericCurlConfig,
191
                      use_curl_cabundle=True, cafile="cert1.pem")
192
    self.assertRaises(client.Error, client.GenericCurlConfig,
193
                      use_curl_cabundle=True, capath="certs/")
194
    self.assertRaises(client.Error, client.GenericCurlConfig,
195
                      use_curl_cabundle=True,
196
                      cafile="cert1.pem", capath="certs/")
197

    
198
  def testProxySignalVerifyHostname(self):
199
    for use_gnutls in [False, True]:
200
      if use_gnutls:
201
        pcverfn = _FakeGnuTlsPycurlVersion
202
      else:
203
        pcverfn = _FakeOpenSslPycurlVersion
204

    
205
      for proxy in ["", "http://127.0.0.1:1234"]:
206
        for use_signal in [False, True]:
207
          for verify_hostname in [False, True]:
208
            cfgfn = client.GenericCurlConfig(proxy=proxy, use_signal=use_signal,
209
                                             verify_hostname=verify_hostname,
210
                                             _pycurl_version_fn=pcverfn)
211

    
212
            curl_factory = lambda: FakeCurl(RapiMock())
213
            cl = client.GanetiRapiClient("master.example.com",
214
                                         curl_config_fn=cfgfn,
215
                                         curl_factory=curl_factory)
216

    
217
            curl = cl._CreateCurl()
218
            self.assertEqual(curl.getopt(pycurl.PROXY), proxy)
219
            self.assertEqual(curl.getopt(pycurl.NOSIGNAL), not use_signal)
220

    
221
            if verify_hostname:
222
              self.assertEqual(curl.getopt(pycurl.SSL_VERIFYHOST), 2)
223
            else:
224
              self.assertEqual(curl.getopt(pycurl.SSL_VERIFYHOST), 0)
225

    
226
  def testNoCertVerify(self):
227
    cfgfn = client.GenericCurlConfig()
228

    
229
    curl_factory = lambda: FakeCurl(RapiMock())
230
    cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
231
                                 curl_factory=curl_factory)
232

    
233
    curl = cl._CreateCurl()
234
    self.assertFalse(curl.getopt(pycurl.SSL_VERIFYPEER))
235
    self.assertFalse(curl.getopt(pycurl.CAINFO))
236
    self.assertFalse(curl.getopt(pycurl.CAPATH))
237

    
238
  def testCertVerifyCurlBundle(self):
239
    cfgfn = client.GenericCurlConfig(use_curl_cabundle=True)
240

    
241
    curl_factory = lambda: FakeCurl(RapiMock())
242
    cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
243
                                 curl_factory=curl_factory)
244

    
245
    curl = cl._CreateCurl()
246
    self.assert_(curl.getopt(pycurl.SSL_VERIFYPEER))
247
    self.assertFalse(curl.getopt(pycurl.CAINFO))
248
    self.assertFalse(curl.getopt(pycurl.CAPATH))
249

    
250
  def testCertVerifyCafile(self):
251
    mycert = "/tmp/some/UNUSED/cert/file.pem"
252
    cfgfn = client.GenericCurlConfig(cafile=mycert)
253

    
254
    curl_factory = lambda: FakeCurl(RapiMock())
255
    cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
256
                                 curl_factory=curl_factory)
257

    
258
    curl = cl._CreateCurl()
259
    self.assert_(curl.getopt(pycurl.SSL_VERIFYPEER))
260
    self.assertEqual(curl.getopt(pycurl.CAINFO), mycert)
261
    self.assertFalse(curl.getopt(pycurl.CAPATH))
262

    
263
  def testCertVerifyCapath(self):
264
    certdir = "/tmp/some/UNUSED/cert/directory"
265
    pcverfn = _FakeOpenSslPycurlVersion
266
    cfgfn = client.GenericCurlConfig(capath=certdir,
267
                                     _pycurl_version_fn=pcverfn)
268

    
269
    curl_factory = lambda: FakeCurl(RapiMock())
270
    cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
271
                                 curl_factory=curl_factory)
272

    
273
    curl = cl._CreateCurl()
274
    self.assert_(curl.getopt(pycurl.SSL_VERIFYPEER))
275
    self.assertEqual(curl.getopt(pycurl.CAPATH), certdir)
276
    self.assertFalse(curl.getopt(pycurl.CAINFO))
277

    
278
  def testCertVerifyCapathGnuTls(self):
279
    certdir = "/tmp/some/UNUSED/cert/directory"
280
    pcverfn = _FakeGnuTlsPycurlVersion
281
    cfgfn = client.GenericCurlConfig(capath=certdir,
282
                                     _pycurl_version_fn=pcverfn)
283

    
284
    curl_factory = lambda: FakeCurl(RapiMock())
285
    cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
286
                                 curl_factory=curl_factory)
287

    
288
    self.assertRaises(client.Error, cl._CreateCurl)
289

    
290
  def testCertVerifyNoSsl(self):
291
    certdir = "/tmp/some/UNUSED/cert/directory"
292
    pcverfn = _FakeNoSslPycurlVersion
293
    cfgfn = client.GenericCurlConfig(capath=certdir,
294
                                     _pycurl_version_fn=pcverfn)
295

    
296
    curl_factory = lambda: FakeCurl(RapiMock())
297
    cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
298
                                 curl_factory=curl_factory)
299

    
300
    self.assertRaises(client.Error, cl._CreateCurl)
301

    
302
  def testCertVerifyFancySsl(self):
303
    certdir = "/tmp/some/UNUSED/cert/directory"
304
    pcverfn = _FakeFancySslPycurlVersion
305
    cfgfn = client.GenericCurlConfig(capath=certdir,
306
                                     _pycurl_version_fn=pcverfn)
307

    
308
    curl_factory = lambda: FakeCurl(RapiMock())
309
    cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
310
                                 curl_factory=curl_factory)
311

    
312
    self.assertRaises(NotImplementedError, cl._CreateCurl)
313

    
314
  def testCertVerifyCapath(self):
315
    for connect_timeout in [None, 1, 5, 10, 30, 60, 300]:
316
      for timeout in [None, 1, 30, 60, 3600, 24 * 3600]:
317
        cfgfn = client.GenericCurlConfig(connect_timeout=connect_timeout,
318
                                         timeout=timeout)
319

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

    
324
        curl = cl._CreateCurl()
325
        self.assertEqual(curl.getopt(pycurl.CONNECTTIMEOUT), connect_timeout)
326
        self.assertEqual(curl.getopt(pycurl.TIMEOUT), timeout)
327

    
328

    
329
class GanetiRapiClientTests(testutils.GanetiTestCase):
330
  def setUp(self):
331
    testutils.GanetiTestCase.setUp(self)
332

    
333
    self.rapi = RapiMock()
334
    self.curl = FakeCurl(self.rapi)
335
    self.client = client.GanetiRapiClient("master.example.com",
336
                                          curl_factory=lambda: self.curl)
337

    
338
  def assertHandler(self, handler_cls):
339
    self.failUnless(isinstance(self.rapi.GetLastHandler(), handler_cls))
340

    
341
  def assertQuery(self, key, value):
342
    self.assertEqual(value, self.rapi.GetLastHandler().queryargs.get(key, None))
343

    
344
  def assertItems(self, items):
345
    self.assertEqual(items, self.rapi.GetLastHandler().items)
346

    
347
  def assertBulk(self):
348
    self.assertTrue(self.rapi.GetLastHandler().useBulk())
349

    
350
  def assertDryRun(self):
351
    self.assertTrue(self.rapi.GetLastHandler().dryRun())
352

    
353
  def testEncodeQuery(self):
354
    query = [
355
      ("a", None),
356
      ("b", 1),
357
      ("c", 2),
358
      ("d", "Foo"),
359
      ("e", True),
360
      ]
361

    
362
    expected = [
363
      ("a", ""),
364
      ("b", 1),
365
      ("c", 2),
366
      ("d", "Foo"),
367
      ("e", 1),
368
      ]
369

    
370
    self.assertEqualValues(self.client._EncodeQuery(query),
371
                           expected)
372

    
373
    # invalid types
374
    for i in [[1, 2, 3], {"moo": "boo"}, (1, 2, 3)]:
375
      self.assertRaises(ValueError, self.client._EncodeQuery, [("x", i)])
376

    
377
  def testCurlSettings(self):
378
    self.rapi.AddResponse("2")
379
    self.assertEqual(2, self.client.GetVersion())
380
    self.assertHandler(rlib2.R_version)
381

    
382
    # Signals should be disabled by default
383
    self.assert_(self.curl.getopt(pycurl.NOSIGNAL))
384

    
385
    # No auth and no proxy
386
    self.assertFalse(self.curl.getopt(pycurl.USERPWD))
387
    self.assert_(self.curl.getopt(pycurl.PROXY) is None)
388

    
389
    # Content-type is required for requests
390
    headers = self.curl.getopt(pycurl.HTTPHEADER)
391
    self.assert_("Content-type: application/json" in headers)
392

    
393
  def testHttpError(self):
394
    self.rapi.AddResponse(None, code=404)
395
    try:
396
      self.client.GetJobStatus(15140)
397
    except client.GanetiApiError, err:
398
      self.assertEqual(err.code, 404)
399
    else:
400
      self.fail("Didn't raise exception")
401

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

    
407
  def testGetFeatures(self):
408
    for features in [[], ["foo", "bar", "baz"]]:
409
      self.rapi.AddResponse(serializer.DumpJson(features))
410
      self.assertEqual(features, self.client.GetFeatures())
411
      self.assertHandler(rlib2.R_2_features)
412

    
413
  def testGetFeaturesNotFound(self):
414
    self.rapi.AddResponse(None, code=404)
415
    self.assertEqual([], self.client.GetFeatures())
416

    
417
  def testGetOperatingSystems(self):
418
    self.rapi.AddResponse("[\"beos\"]")
419
    self.assertEqual(["beos"], self.client.GetOperatingSystems())
420
    self.assertHandler(rlib2.R_2_os)
421

    
422
  def testGetClusterTags(self):
423
    self.rapi.AddResponse("[\"tag\"]")
424
    self.assertEqual(["tag"], self.client.GetClusterTags())
425
    self.assertHandler(rlib2.R_2_tags)
426

    
427
  def testAddClusterTags(self):
428
    self.rapi.AddResponse("1234")
429
    self.assertEqual(1234,
430
        self.client.AddClusterTags(["awesome"], dry_run=True))
431
    self.assertHandler(rlib2.R_2_tags)
432
    self.assertDryRun()
433
    self.assertQuery("tag", ["awesome"])
434

    
435
  def testDeleteClusterTags(self):
436
    self.rapi.AddResponse("5107")
437
    self.assertEqual(5107, self.client.DeleteClusterTags(["awesome"],
438
                                                         dry_run=True))
439
    self.assertHandler(rlib2.R_2_tags)
440
    self.assertDryRun()
441
    self.assertQuery("tag", ["awesome"])
442

    
443
  def testGetInfo(self):
444
    self.rapi.AddResponse("{}")
445
    self.assertEqual({}, self.client.GetInfo())
446
    self.assertHandler(rlib2.R_2_info)
447

    
448
  def testGetInstances(self):
449
    self.rapi.AddResponse("[]")
450
    self.assertEqual([], self.client.GetInstances(bulk=True))
451
    self.assertHandler(rlib2.R_2_instances)
452
    self.assertBulk()
453

    
454
  def testGetInstance(self):
455
    self.rapi.AddResponse("[]")
456
    self.assertEqual([], self.client.GetInstance("instance"))
457
    self.assertHandler(rlib2.R_2_instances_name)
458
    self.assertItems(["instance"])
459

    
460
  def testGetInstanceInfo(self):
461
    self.rapi.AddResponse("21291")
462
    self.assertEqual(21291, self.client.GetInstanceInfo("inst3"))
463
    self.assertHandler(rlib2.R_2_instances_name_info)
464
    self.assertItems(["inst3"])
465
    self.assertQuery("static", None)
466

    
467
    self.rapi.AddResponse("3428")
468
    self.assertEqual(3428, self.client.GetInstanceInfo("inst31", static=False))
469
    self.assertHandler(rlib2.R_2_instances_name_info)
470
    self.assertItems(["inst31"])
471
    self.assertQuery("static", ["0"])
472

    
473
    self.rapi.AddResponse("15665")
474
    self.assertEqual(15665, self.client.GetInstanceInfo("inst32", static=True))
475
    self.assertHandler(rlib2.R_2_instances_name_info)
476
    self.assertItems(["inst32"])
477
    self.assertQuery("static", ["1"])
478

    
479
  def testCreateInstanceOldVersion(self):
480
    # No NICs
481
    self.rapi.AddResponse(None, code=404)
482
    self.assertRaises(client.GanetiApiError, self.client.CreateInstance,
483
                      "create", "inst1.example.com", "plain", [], [])
484
    self.assertEqual(self.rapi.CountPending(), 0)
485

    
486
    # More than one NIC
487
    self.rapi.AddResponse(None, code=404)
488
    self.assertRaises(client.GanetiApiError, self.client.CreateInstance,
489
                      "create", "inst1.example.com", "plain", [],
490
                      [{}, {}, {}])
491
    self.assertEqual(self.rapi.CountPending(), 0)
492

    
493
    # Unsupported NIC fields
494
    self.rapi.AddResponse(None, code=404)
495
    self.assertRaises(client.GanetiApiError, self.client.CreateInstance,
496
                      "create", "inst1.example.com", "plain", [],
497
                      [{"x": True, "y": False}])
498
    self.assertEqual(self.rapi.CountPending(), 0)
499

    
500
    # Unsupported disk fields
501
    self.rapi.AddResponse(None, code=404)
502
    self.assertRaises(client.GanetiApiError, self.client.CreateInstance,
503
                      "create", "inst1.example.com", "plain",
504
                      [{}, {"moo": "foo",}], [{}])
505
    self.assertEqual(self.rapi.CountPending(), 0)
506

    
507
    # Unsupported fields
508
    self.rapi.AddResponse(None, code=404)
509
    self.assertRaises(client.GanetiApiError, self.client.CreateInstance,
510
                      "create", "inst1.example.com", "plain", [], [{}],
511
                      hello_world=123)
512
    self.assertEqual(self.rapi.CountPending(), 0)
513

    
514
    self.rapi.AddResponse(None, code=404)
515
    self.assertRaises(client.GanetiApiError, self.client.CreateInstance,
516
                      "create", "inst1.example.com", "plain", [], [{}],
517
                      memory=128)
518
    self.assertEqual(self.rapi.CountPending(), 0)
519

    
520
    # Normal creation
521
    testnics = [
522
      [{}],
523
      [{ "mac": constants.VALUE_AUTO, }],
524
      [{ "ip": "192.0.2.99", "mode": constants.NIC_MODE_ROUTED, }],
525
      ]
526

    
527
    testdisks = [
528
      [],
529
      [{ "size": 128, }],
530
      [{ "size": 321, }, { "size": 4096, }],
531
      ]
532

    
533
    for idx, nics in enumerate(testnics):
534
      for disks in testdisks:
535
        beparams = {
536
          constants.BE_MEMORY: 512,
537
          constants.BE_AUTO_BALANCE: False,
538
          }
539
        hvparams = {
540
          constants.HV_MIGRATION_PORT: 9876,
541
          constants.HV_VNC_TLS: True,
542
          }
543

    
544
        self.rapi.AddResponse(None, code=404)
545
        self.rapi.AddResponse(serializer.DumpJson(3122617 + idx))
546
        job_id = self.client.CreateInstance("create", "inst1.example.com",
547
                                            "plain", disks, nics,
548
                                            pnode="node99", dry_run=True,
549
                                            hvparams=hvparams,
550
                                            beparams=beparams)
551
        self.assertEqual(job_id, 3122617 + idx)
552
        self.assertHandler(rlib2.R_2_instances)
553
        self.assertDryRun()
554
        self.assertEqual(self.rapi.CountPending(), 0)
555

    
556
        data = serializer.LoadJson(self.rapi.GetLastRequestData())
557
        self.assertEqual(data["name"], "inst1.example.com")
558
        self.assertEqual(data["disk_template"], "plain")
559
        self.assertEqual(data["pnode"], "node99")
560
        self.assertEqual(data[constants.BE_MEMORY], 512)
561
        self.assertEqual(data[constants.BE_AUTO_BALANCE], False)
562
        self.assertEqual(data[constants.HV_MIGRATION_PORT], 9876)
563
        self.assertEqual(data[constants.HV_VNC_TLS], True)
564
        self.assertEqual(data["disks"], [disk["size"] for disk in disks])
565

    
566
  def testCreateInstance(self):
567
    self.rapi.AddResponse(serializer.DumpJson([rlib2._INST_CREATE_REQV1]))
568
    self.rapi.AddResponse("23030")
569
    job_id = self.client.CreateInstance("create", "inst1.example.com",
570
                                        "plain", [], [], dry_run=True)
571
    self.assertEqual(job_id, 23030)
572
    self.assertHandler(rlib2.R_2_instances)
573
    self.assertDryRun()
574

    
575
    data = serializer.LoadJson(self.rapi.GetLastRequestData())
576

    
577
    for field in ["dry_run", "beparams", "hvparams", "start"]:
578
      self.assertFalse(field in data)
579

    
580
    self.assertEqual(data["name"], "inst1.example.com")
581
    self.assertEqual(data["disk_template"], "plain")
582

    
583
  def testCreateInstance2(self):
584
    self.rapi.AddResponse(serializer.DumpJson([rlib2._INST_CREATE_REQV1]))
585
    self.rapi.AddResponse("24740")
586
    job_id = self.client.CreateInstance("import", "inst2.example.com",
587
                                        "drbd8", [{"size": 100,}],
588
                                        [{}, {"bridge": "br1", }],
589
                                        dry_run=False, start=True,
590
                                        pnode="node1", snode="node9",
591
                                        ip_check=False)
592
    self.assertEqual(job_id, 24740)
593
    self.assertHandler(rlib2.R_2_instances)
594

    
595
    data = serializer.LoadJson(self.rapi.GetLastRequestData())
596
    self.assertEqual(data[rlib2._REQ_DATA_VERSION], 1)
597
    self.assertEqual(data["name"], "inst2.example.com")
598
    self.assertEqual(data["disk_template"], "drbd8")
599
    self.assertEqual(data["start"], True)
600
    self.assertEqual(data["ip_check"], False)
601
    self.assertEqualValues(data["disks"], [{"size": 100,}])
602
    self.assertEqualValues(data["nics"], [{}, {"bridge": "br1", }])
603

    
604
  def testDeleteInstance(self):
605
    self.rapi.AddResponse("1234")
606
    self.assertEqual(1234, self.client.DeleteInstance("instance", dry_run=True))
607
    self.assertHandler(rlib2.R_2_instances_name)
608
    self.assertItems(["instance"])
609
    self.assertDryRun()
610

    
611
  def testGetInstanceTags(self):
612
    self.rapi.AddResponse("[]")
613
    self.assertEqual([], self.client.GetInstanceTags("fooinstance"))
614
    self.assertHandler(rlib2.R_2_instances_name_tags)
615
    self.assertItems(["fooinstance"])
616

    
617
  def testAddInstanceTags(self):
618
    self.rapi.AddResponse("1234")
619
    self.assertEqual(1234,
620
        self.client.AddInstanceTags("fooinstance", ["awesome"], dry_run=True))
621
    self.assertHandler(rlib2.R_2_instances_name_tags)
622
    self.assertItems(["fooinstance"])
623
    self.assertDryRun()
624
    self.assertQuery("tag", ["awesome"])
625

    
626
  def testDeleteInstanceTags(self):
627
    self.rapi.AddResponse("25826")
628
    self.assertEqual(25826, self.client.DeleteInstanceTags("foo", ["awesome"],
629
                                                           dry_run=True))
630
    self.assertHandler(rlib2.R_2_instances_name_tags)
631
    self.assertItems(["foo"])
632
    self.assertDryRun()
633
    self.assertQuery("tag", ["awesome"])
634

    
635
  def testRebootInstance(self):
636
    self.rapi.AddResponse("6146")
637
    job_id = self.client.RebootInstance("i-bar", reboot_type="hard",
638
                                        ignore_secondaries=True, dry_run=True)
639
    self.assertEqual(6146, job_id)
640
    self.assertHandler(rlib2.R_2_instances_name_reboot)
641
    self.assertItems(["i-bar"])
642
    self.assertDryRun()
643
    self.assertQuery("type", ["hard"])
644
    self.assertQuery("ignore_secondaries", ["1"])
645

    
646
  def testShutdownInstance(self):
647
    self.rapi.AddResponse("1487")
648
    self.assertEqual(1487, self.client.ShutdownInstance("foo-instance",
649
                                                        dry_run=True))
650
    self.assertHandler(rlib2.R_2_instances_name_shutdown)
651
    self.assertItems(["foo-instance"])
652
    self.assertDryRun()
653

    
654
  def testStartupInstance(self):
655
    self.rapi.AddResponse("27149")
656
    self.assertEqual(27149, self.client.StartupInstance("bar-instance",
657
                                                        dry_run=True))
658
    self.assertHandler(rlib2.R_2_instances_name_startup)
659
    self.assertItems(["bar-instance"])
660
    self.assertDryRun()
661

    
662
  def testReinstallInstance(self):
663
    self.rapi.AddResponse("19119")
664
    self.assertEqual(19119, self.client.ReinstallInstance("baz-instance",
665
                                                          os="DOS",
666
                                                          no_startup=True))
667
    self.assertHandler(rlib2.R_2_instances_name_reinstall)
668
    self.assertItems(["baz-instance"])
669
    self.assertQuery("os", ["DOS"])
670
    self.assertQuery("nostartup", ["1"])
671

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

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

    
694
    self.rapi.AddResponse("5175")
695
    self.assertEqual(5175, self.client.ReplaceInstanceDisks("instance-moo"))
696
    self.assertItems(["instance-moo"])
697
    self.assertQuery("disks", None)
698

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

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

    
714
    data = serializer.LoadJson(self.rapi.GetLastRequestData())
715
    self.assertEqual(data["mode"], "local")
716
    self.assertEqual(data["destination"], "nodeX")
717
    self.assertEqual(data["shutdown"], True)
718

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

    
726
    data = serializer.LoadJson(self.rapi.GetLastRequestData())
727
    self.assertFalse(data)
728

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

    
739
        data = serializer.LoadJson(self.rapi.GetLastRequestData())
740
        self.assertEqual(len(data), 2)
741
        self.assertEqual(data["mode"], mode)
742
        self.assertEqual(data["cleanup"], cleanup)
743

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

    
752
    data = serializer.LoadJson(self.rapi.GetLastRequestData())
753
    self.assertEqualValues(data, {"new_name": new_name, })
754

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

    
767
        data = serializer.LoadJson(self.rapi.GetLastRequestData())
768
        self.assertEqual(len(data), 3)
769
        self.assertEqual(data["new_name"], new_name)
770
        self.assertEqual(data["ip_check"], ip_check)
771
        self.assertEqual(data["name_check"], name_check)
772

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

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

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

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

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

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

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

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

    
826
  def testEvacuateNode(self):
827
    self.rapi.AddResponse("9876")
828
    job_id = self.client.EvacuateNode("node-1", remote_node="node-2")
829
    self.assertEqual(9876, job_id)
830
    self.assertHandler(rlib2.R_2_nodes_name_evacuate)
831
    self.assertItems(["node-1"])
832
    self.assertQuery("remote_node", ["node-2"])
833

    
834
    self.rapi.AddResponse("8888")
835
    job_id = self.client.EvacuateNode("node-3", iallocator="hail", dry_run=True)
836
    self.assertEqual(8888, job_id)
837
    self.assertItems(["node-3"])
838
    self.assertQuery("iallocator", ["hail"])
839
    self.assertDryRun()
840

    
841
    self.assertRaises(client.GanetiApiError,
842
                      self.client.EvacuateNode,
843
                      "node-4", iallocator="hail", remote_node="node-5")
844

    
845
  def testMigrateNode(self):
846
    self.rapi.AddResponse("1111")
847
    self.assertEqual(1111, self.client.MigrateNode("node-a", dry_run=True))
848
    self.assertHandler(rlib2.R_2_nodes_name_migrate)
849
    self.assertItems(["node-a"])
850
    self.assert_("mode" not in self.rapi.GetLastHandler().queryargs)
851
    self.assertDryRun()
852

    
853
    self.rapi.AddResponse("1112")
854
    self.assertEqual(1112, self.client.MigrateNode("node-a", dry_run=True,
855
                                                   mode="live"))
856
    self.assertHandler(rlib2.R_2_nodes_name_migrate)
857
    self.assertItems(["node-a"])
858
    self.assertQuery("mode", ["live"])
859
    self.assertDryRun()
860

    
861
  def testGetNodeRole(self):
862
    self.rapi.AddResponse("\"master\"")
863
    self.assertEqual("master", self.client.GetNodeRole("node-a"))
864
    self.assertHandler(rlib2.R_2_nodes_name_role)
865
    self.assertItems(["node-a"])
866

    
867
  def testSetNodeRole(self):
868
    self.rapi.AddResponse("789")
869
    self.assertEqual(789,
870
        self.client.SetNodeRole("node-foo", "master-candidate", force=True))
871
    self.assertHandler(rlib2.R_2_nodes_name_role)
872
    self.assertItems(["node-foo"])
873
    self.assertQuery("force", ["1"])
874
    self.assertEqual("\"master-candidate\"", self.rapi.GetLastRequestData())
875

    
876
  def testGetNodeStorageUnits(self):
877
    self.rapi.AddResponse("42")
878
    self.assertEqual(42,
879
        self.client.GetNodeStorageUnits("node-x", "lvm-pv", "fields"))
880
    self.assertHandler(rlib2.R_2_nodes_name_storage)
881
    self.assertItems(["node-x"])
882
    self.assertQuery("storage_type", ["lvm-pv"])
883
    self.assertQuery("output_fields", ["fields"])
884

    
885
  def testModifyNodeStorageUnits(self):
886
    self.rapi.AddResponse("14")
887
    self.assertEqual(14,
888
        self.client.ModifyNodeStorageUnits("node-z", "lvm-pv", "hda"))
889
    self.assertHandler(rlib2.R_2_nodes_name_storage_modify)
890
    self.assertItems(["node-z"])
891
    self.assertQuery("storage_type", ["lvm-pv"])
892
    self.assertQuery("name", ["hda"])
893
    self.assertQuery("allocatable", None)
894

    
895
    for allocatable, query_allocatable in [(True, "1"), (False, "0")]:
896
      self.rapi.AddResponse("7205")
897
      job_id = self.client.ModifyNodeStorageUnits("node-z", "lvm-pv", "hda",
898
                                                  allocatable=allocatable)
899
      self.assertEqual(7205, job_id)
900
      self.assertHandler(rlib2.R_2_nodes_name_storage_modify)
901
      self.assertItems(["node-z"])
902
      self.assertQuery("storage_type", ["lvm-pv"])
903
      self.assertQuery("name", ["hda"])
904
      self.assertQuery("allocatable", [query_allocatable])
905

    
906
  def testRepairNodeStorageUnits(self):
907
    self.rapi.AddResponse("99")
908
    self.assertEqual(99, self.client.RepairNodeStorageUnits("node-z", "lvm-pv",
909
                                                            "hda"))
910
    self.assertHandler(rlib2.R_2_nodes_name_storage_repair)
911
    self.assertItems(["node-z"])
912
    self.assertQuery("storage_type", ["lvm-pv"])
913
    self.assertQuery("name", ["hda"])
914

    
915
  def testGetNodeTags(self):
916
    self.rapi.AddResponse("[\"fry\", \"bender\"]")
917
    self.assertEqual(["fry", "bender"], self.client.GetNodeTags("node-k"))
918
    self.assertHandler(rlib2.R_2_nodes_name_tags)
919
    self.assertItems(["node-k"])
920

    
921
  def testAddNodeTags(self):
922
    self.rapi.AddResponse("1234")
923
    self.assertEqual(1234,
924
        self.client.AddNodeTags("node-v", ["awesome"], dry_run=True))
925
    self.assertHandler(rlib2.R_2_nodes_name_tags)
926
    self.assertItems(["node-v"])
927
    self.assertDryRun()
928
    self.assertQuery("tag", ["awesome"])
929

    
930
  def testDeleteNodeTags(self):
931
    self.rapi.AddResponse("16861")
932
    self.assertEqual(16861, self.client.DeleteNodeTags("node-w", ["awesome"],
933
                                                       dry_run=True))
934
    self.assertHandler(rlib2.R_2_nodes_name_tags)
935
    self.assertItems(["node-w"])
936
    self.assertDryRun()
937
    self.assertQuery("tag", ["awesome"])
938

    
939

    
940
if __name__ == '__main__':
941
  client.UsesRapiClient(testutils.GanetiTestProgram)()