#!/usr/bin/python
#
-# Copyright (C) 2010 Google Inc.
+# Copyright (C) 2010, 2012 Google Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
from ganeti import query
from ganeti import luxi
from ganeti import errors
+from ganeti import rapi
from ganeti.rapi import rlib2
+from ganeti.rapi import baserlib
+from ganeti.rapi import connector
import testutils
class _FakeClient:
- def __init__(self):
+ def __init__(self, address=None):
self._jobs = []
def GetNextSubmittedJob(self):
def GetNextClient(self):
return self._clients.pop(0)
- def __call__(self):
- cl = self._client_cls()
+ def __call__(self, address=None):
+ cl = self._client_cls(address=address)
self._clients.append(cl)
return cl
class TestClientConnectError(unittest.TestCase):
@staticmethod
- def _FailingClient():
+ def _FailingClient(address=None):
raise luxi.NoMasterError("test")
def test(self):
class TestJobSubmitError(unittest.TestCase):
class _SubmitErrorClient:
+ def __init__(self, address=None):
+ pass
+
@staticmethod
def SubmitJob(ops):
raise errors.JobQueueFull("test")
self.assertRaises(IndexError, cl.GetNextSubmittedJob)
+class TestNodePowercycle(unittest.TestCase):
+ def test(self):
+ clfactory = _FakeClientFactory(_FakeClient)
+ handler = _CreateHandler(rlib2.R_2_nodes_name_powercycle, ["node20744"], {
+ "force": ["1"],
+ }, None, clfactory)
+ job_id = handler.POST()
+
+ cl = clfactory.GetNextClient()
+ self.assertRaises(IndexError, clfactory.GetNextClient)
+
+ (exp_job_id, (op, )) = cl.GetNextSubmittedJob()
+ self.assertEqual(job_id, exp_job_id)
+ self.assertTrue(isinstance(op, opcodes.OpNodePowercycle))
+ self.assertEqual(op.node_name, "node20744")
+ self.assertTrue(op.force)
+
+ self.assertRaises(IndexError, cl.GetNextSubmittedJob)
+
+
class TestGroupAssignNodes(unittest.TestCase):
def test(self):
clfactory = _FakeClientFactory(_FakeClient)
self.assertRaises(IndexError, cl.GetNextSubmittedJob)
+class TestInstanceRecreateDisks(unittest.TestCase):
+ def test(self):
+ clfactory = _FakeClientFactory(_FakeClient)
+ handler = _CreateHandler(rlib2.R_2_instances_name_recreate_disks,
+ ["inst22357"], {}, {}, clfactory)
+ job_id = handler.POST()
+
+ cl = clfactory.GetNextClient()
+ self.assertRaises(IndexError, clfactory.GetNextClient)
+
+ (exp_job_id, (op, )) = cl.GetNextSubmittedJob()
+ self.assertEqual(job_id, exp_job_id)
+ self.assertTrue(isinstance(op, opcodes.OpInstanceRecreateDisks))
+ self.assertEqual(op.instance_name, "inst22357")
+ self.assertFalse(hasattr(op, "dry_run"))
+ self.assertFalse(hasattr(op, "force"))
+
+ self.assertRaises(IndexError, cl.GetNextSubmittedJob)
+
+
class TestInstanceFailover(unittest.TestCase):
def test(self):
clfactory = _FakeClientFactory(_FakeClient)
self.assertRaises(http.HttpBadRequest, handler.GET)
-class TestParseInstanceCreateRequestVersion1(testutils.GanetiTestCase):
- def setUp(self):
- testutils.GanetiTestCase.setUp(self)
+class TestStorageModify(unittest.TestCase):
+ def test(self):
+ clfactory = _FakeClientFactory(_FakeClient)
+
+ for allocatable in [None, "1", "0"]:
+ queryargs = {
+ "storage_type": constants.ST_LVM_VG,
+ "name": "pv-a",
+ }
+
+ if allocatable is not None:
+ queryargs["allocatable"] = allocatable
+
+ handler = _CreateHandler(rlib2.R_2_nodes_name_storage_modify,
+ ["node9292"], queryargs, {}, clfactory)
+ job_id = handler.PUT()
+
+ cl = clfactory.GetNextClient()
+ self.assertRaises(IndexError, clfactory.GetNextClient)
+
+ (exp_job_id, (op, )) = cl.GetNextSubmittedJob()
+ self.assertEqual(job_id, exp_job_id)
+ self.assertTrue(isinstance(op, opcodes.OpNodeModifyStorage))
+ self.assertEqual(op.node_name, "node9292")
+ self.assertEqual(op.storage_type, constants.ST_LVM_VG)
+ self.assertEqual(op.name, "pv-a")
+ if allocatable is None:
+ self.assertFalse(op.changes)
+ else:
+ assert allocatable in ("0", "1")
+ self.assertEqual(op.changes, {
+ constants.SF_ALLOCATABLE: (allocatable == "1"),
+ })
+ self.assertFalse(hasattr(op, "dry_run"))
+ self.assertFalse(hasattr(op, "force"))
+
+ self.assertRaises(IndexError, cl.GetNextSubmittedJob)
+
+ def testErrors(self):
+ clfactory = _FakeClientFactory(_FakeClient)
+
+ # No storage type
+ queryargs = {
+ "name": "xyz",
+ }
+ handler = _CreateHandler(rlib2.R_2_nodes_name_storage_modify,
+ ["node26016"], queryargs, {}, clfactory)
+ self.assertRaises(http.HttpBadRequest, handler.PUT)
+
+ # No name
+ queryargs = {
+ "storage_type": constants.ST_LVM_VG,
+ }
+ handler = _CreateHandler(rlib2.R_2_nodes_name_storage_modify,
+ ["node21218"], queryargs, {}, clfactory)
+ self.assertRaises(http.HttpBadRequest, handler.PUT)
+
+ # Invalid value
+ queryargs = {
+ "storage_type": constants.ST_LVM_VG,
+ "name": "pv-b",
+ "allocatable": "noint",
+ }
+ handler = _CreateHandler(rlib2.R_2_nodes_name_storage_modify,
+ ["node30685"], queryargs, {}, clfactory)
+ self.assertRaises(http.HttpBadRequest, handler.PUT)
- self.Parse = rlib2._ParseInstanceCreateRequestVersion1
+class TestStorageRepair(unittest.TestCase):
def test(self):
+ clfactory = _FakeClientFactory(_FakeClient)
+ queryargs = {
+ "storage_type": constants.ST_LVM_PV,
+ "name": "pv16611",
+ }
+ handler = _CreateHandler(rlib2.R_2_nodes_name_storage_repair,
+ ["node19265"], queryargs, {}, clfactory)
+ job_id = handler.PUT()
+
+ cl = clfactory.GetNextClient()
+ self.assertRaises(IndexError, clfactory.GetNextClient)
+
+ (exp_job_id, (op, )) = cl.GetNextSubmittedJob()
+ self.assertEqual(job_id, exp_job_id)
+ self.assertTrue(isinstance(op, opcodes.OpRepairNodeStorage))
+ self.assertEqual(op.node_name, "node19265")
+ self.assertEqual(op.storage_type, constants.ST_LVM_PV)
+ self.assertEqual(op.name, "pv16611")
+ self.assertFalse(hasattr(op, "dry_run"))
+ self.assertFalse(hasattr(op, "force"))
+
+ self.assertRaises(IndexError, cl.GetNextSubmittedJob)
+
+ def testErrors(self):
+ clfactory = _FakeClientFactory(_FakeClient)
+
+ # No storage type
+ queryargs = {
+ "name": "xyz",
+ }
+ handler = _CreateHandler(rlib2.R_2_nodes_name_storage_repair,
+ ["node11275"], queryargs, {}, clfactory)
+ self.assertRaises(http.HttpBadRequest, handler.PUT)
+
+ # No name
+ queryargs = {
+ "storage_type": constants.ST_LVM_VG,
+ }
+ handler = _CreateHandler(rlib2.R_2_nodes_name_storage_repair,
+ ["node21218"], queryargs, {}, clfactory)
+ self.assertRaises(http.HttpBadRequest, handler.PUT)
+
+
+class TestTags(unittest.TestCase):
+ TAG_HANDLERS = [
+ rlib2.R_2_instances_name_tags,
+ rlib2.R_2_nodes_name_tags,
+ rlib2.R_2_groups_name_tags,
+ rlib2.R_2_tags,
+ ]
+
+ def testSetAndDelete(self):
+ clfactory = _FakeClientFactory(_FakeClient)
+
+ for method, opcls in [("PUT", opcodes.OpTagsSet),
+ ("DELETE", opcodes.OpTagsDel)]:
+ for idx, handler in enumerate(self.TAG_HANDLERS):
+ dry_run = bool(idx % 2)
+ name = "test%s" % idx
+ queryargs = {
+ "tag": ["foo", "bar", "baz"],
+ "dry-run": str(int(dry_run)),
+ }
+
+ handler = _CreateHandler(handler, [name], queryargs, {}, clfactory)
+ job_id = getattr(handler, method)()
+
+ cl = clfactory.GetNextClient()
+ self.assertRaises(IndexError, clfactory.GetNextClient)
+
+ (exp_job_id, (op, )) = cl.GetNextSubmittedJob()
+ self.assertEqual(job_id, exp_job_id)
+ self.assertTrue(isinstance(op, opcls))
+ self.assertEqual(op.kind, handler.TAG_LEVEL)
+ if handler.TAG_LEVEL == constants.TAG_CLUSTER:
+ self.assertTrue(op.name is None)
+ else:
+ self.assertEqual(op.name, name)
+ self.assertEqual(op.tags, ["foo", "bar", "baz"])
+ self.assertEqual(op.dry_run, dry_run)
+ self.assertFalse(hasattr(op, "force"))
+
+ self.assertRaises(IndexError, cl.GetNextSubmittedJob)
+
+
+class TestInstanceCreation(testutils.GanetiTestCase):
+ def test(self):
+ clfactory = _FakeClientFactory(_FakeClient)
+
+ name = "inst863.example.com"
+
disk_variants = [
# No disks
[],
None,
{},
{ constants.BE_VCPUS: 2, },
- { constants.BE_MEMORY: 123, },
+ { constants.BE_MAXMEM: 200, },
+ { constants.BE_MEMORY: 256, },
{ constants.BE_VCPUS: 2,
- constants.BE_MEMORY: 1024,
- constants.BE_AUTO_BALANCE: True, }
+ constants.BE_MAXMEM: 1024,
+ constants.BE_MINMEM: 1024,
+ constants.BE_AUTO_BALANCE: True,
+ constants.BE_ALWAYS_FAILOVER: True, }
]
hvparam_variants = [
for disks in disk_variants:
for beparams in beparam_variants:
for hvparams in hvparam_variants:
- data = {
- "name": "inst1.example.com",
- "hypervisor": constants.HT_FAKE,
- "disks": disks,
- "nics": nics,
- "mode": mode,
- "disk_template": disk_template,
- "os": "debootstrap",
- }
-
- if beparams is not None:
- data["beparams"] = beparams
-
- if hvparams is not None:
- data["hvparams"] = hvparams
-
for dry_run in [False, True]:
- op = self.Parse(data, dry_run)
- self.assert_(isinstance(op, opcodes.OpInstanceCreate))
+ queryargs = {
+ "dry-run": str(int(dry_run)),
+ }
+
+ data = {
+ rlib2._REQ_DATA_VERSION: 1,
+ "name": name,
+ "hypervisor": constants.HT_FAKE,
+ "disks": disks,
+ "nics": nics,
+ "mode": mode,
+ "disk_template": disk_template,
+ "os": "debootstrap",
+ }
+
+ if beparams is not None:
+ data["beparams"] = beparams
+
+ if hvparams is not None:
+ data["hvparams"] = hvparams
+
+ handler = _CreateHandler(rlib2.R_2_instances, [],
+ queryargs, data, clfactory)
+ job_id = handler.POST()
+
+ cl = clfactory.GetNextClient()
+ self.assertRaises(IndexError, clfactory.GetNextClient)
+
+ (exp_job_id, (op, )) = cl.GetNextSubmittedJob()
+ self.assertEqual(job_id, exp_job_id)
+ self.assertRaises(IndexError, cl.GetNextSubmittedJob)
+
+ self.assertTrue(isinstance(op, opcodes.OpInstanceCreate))
+ self.assertEqual(op.instance_name, name)
self.assertEqual(op.mode, mode)
self.assertEqual(op.disk_template, disk_template)
self.assertEqual(op.dry_run, dry_run)
self.assertEqualValues(op.hvparams, hvparams)
def testLegacyName(self):
+ clfactory = _FakeClientFactory(_FakeClient)
+
name = "inst29128.example.com"
data = {
+ rlib2._REQ_DATA_VERSION: 1,
"name": name,
"disks": [],
"nics": [],
"mode": constants.INSTANCE_CREATE,
"disk_template": constants.DT_PLAIN,
}
- op = self.Parse(data, False)
- self.assert_(isinstance(op, opcodes.OpInstanceCreate))
+
+ handler = _CreateHandler(rlib2.R_2_instances, [], {}, data, clfactory)
+ job_id = handler.POST()
+
+ cl = clfactory.GetNextClient()
+ self.assertRaises(IndexError, clfactory.GetNextClient)
+
+ (exp_job_id, (op, )) = cl.GetNextSubmittedJob()
+ self.assertEqual(job_id, exp_job_id)
+ self.assertTrue(isinstance(op, opcodes.OpInstanceCreate))
self.assertEqual(op.instance_name, name)
self.assertFalse(hasattr(op, "name"))
+ self.assertFalse(op.dry_run)
+
+ self.assertRaises(IndexError, cl.GetNextSubmittedJob)
# Define both
- data = {
- "name": name,
- "instance_name": "other.example.com",
- "disks": [],
- "nics": [],
- "mode": constants.INSTANCE_CREATE,
- "disk_template": constants.DT_PLAIN,
- }
- self.assertRaises(http.HttpBadRequest, self.Parse, data, False)
+ data["instance_name"] = "other.example.com"
+ assert "name" in data and "instance_name" in data
+ handler = _CreateHandler(rlib2.R_2_instances, [], {}, data, clfactory)
+ self.assertRaises(http.HttpBadRequest, handler.POST)
+ self.assertRaises(IndexError, clfactory.GetNextClient)
def testLegacyOs(self):
+ clfactory = _FakeClientFactory(_FakeClient)
+
name = "inst4673.example.com"
os = "linux29206"
data = {
+ rlib2._REQ_DATA_VERSION: 1,
"name": name,
"os_type": os,
"disks": [],
"mode": constants.INSTANCE_CREATE,
"disk_template": constants.DT_PLAIN,
}
- op = self.Parse(data, False)
- self.assert_(isinstance(op, opcodes.OpInstanceCreate))
+
+ handler = _CreateHandler(rlib2.R_2_instances, [], {}, data, clfactory)
+ job_id = handler.POST()
+
+ cl = clfactory.GetNextClient()
+ self.assertRaises(IndexError, clfactory.GetNextClient)
+
+ (exp_job_id, (op, )) = cl.GetNextSubmittedJob()
+ self.assertEqual(job_id, exp_job_id)
+ self.assertTrue(isinstance(op, opcodes.OpInstanceCreate))
self.assertEqual(op.instance_name, name)
self.assertEqual(op.os_type, os)
self.assertFalse(hasattr(op, "os"))
+ self.assertFalse(op.dry_run)
+
+ self.assertRaises(IndexError, cl.GetNextSubmittedJob)
# Define both
- data = {
- "instance_name": name,
- "os": os,
- "os_type": "linux9584",
- "disks": [],
- "nics": [],
- "mode": constants.INSTANCE_CREATE,
- "disk_template": constants.DT_PLAIN,
- }
- self.assertRaises(http.HttpBadRequest, self.Parse, data, False)
+ data["os"] = "linux9584"
+ assert "os" in data and "os_type" in data
+ handler = _CreateHandler(rlib2.R_2_instances, [], {}, data, clfactory)
+ self.assertRaises(http.HttpBadRequest, handler.POST)
def testErrors(self):
+ clfactory = _FakeClientFactory(_FakeClient)
+
# Test all required fields
reqfields = {
+ rlib2._REQ_DATA_VERSION: 1,
"name": "inst1.example.com",
"disks": [],
"nics": [],
}
for name in reqfields.keys():
- self.assertRaises(http.HttpBadRequest, self.Parse,
- dict(i for i in reqfields.iteritems() if i[0] != name),
- False)
+ data = dict(i for i in reqfields.iteritems() if i[0] != name)
+
+ handler = _CreateHandler(rlib2.R_2_instances, [], {}, data, clfactory)
+ self.assertRaises(http.HttpBadRequest, handler.POST)
+ self.assertRaises(IndexError, clfactory.GetNextClient)
# Invalid disks and nics
for field in ["disks", "nics"]:
for invvalue in invalid_values:
data = reqfields.copy()
data[field] = invvalue
- self.assertRaises(http.HttpBadRequest, self.Parse, data, False)
+ handler = _CreateHandler(rlib2.R_2_instances, [], {}, data, clfactory)
+ self.assertRaises(http.HttpBadRequest, handler.POST)
+ self.assertRaises(IndexError, clfactory.GetNextClient)
+
+ def testVersion(self):
+ clfactory = _FakeClientFactory(_FakeClient)
+
+ # No version field
+ data = {
+ "name": "inst1.example.com",
+ "disks": [],
+ "nics": [],
+ "mode": constants.INSTANCE_CREATE,
+ "disk_template": constants.DT_PLAIN,
+ }
+
+ handler = _CreateHandler(rlib2.R_2_instances, [], {}, data, clfactory)
+ self.assertRaises(http.HttpBadRequest, handler.POST)
+
+ # Old and incorrect versions
+ for version in [0, -1, 10483, "Hello World"]:
+ data[rlib2._REQ_DATA_VERSION] = version
+
+ handler = _CreateHandler(rlib2.R_2_instances, [], {}, data, clfactory)
+ self.assertRaises(http.HttpBadRequest, handler.POST)
+
+ self.assertRaises(IndexError, clfactory.GetNextClient)
+
+ # Correct version
+ data[rlib2._REQ_DATA_VERSION] = 1
+ handler = _CreateHandler(rlib2.R_2_instances, [], {}, data, clfactory)
+ job_id = handler.POST()
+
+ cl = clfactory.GetNextClient()
+ self.assertRaises(IndexError, clfactory.GetNextClient)
+
+ (exp_job_id, (op, )) = cl.GetNextSubmittedJob()
+ self.assertEqual(job_id, exp_job_id)
+ self.assertTrue(isinstance(op, opcodes.OpInstanceCreate))
+ self.assertRaises(IndexError, cl.GetNextSubmittedJob)
class TestBackupExport(unittest.TestCase):
for osparams in [{}, { "some": "value", "other": "Hello World", }]:
for hvparams in [{}, { constants.HV_KERNEL_PATH: "/some/kernel", }]:
- for beparams in [{}, { constants.BE_MEMORY: 128, }]:
+ for beparams in [{}, { constants.BE_MAXMEM: 128, }]:
for force in [False, True]:
for nics in [[], [(0, { constants.INIC_IP: "192.0.2.1", })]]:
for disks in test_disks:
self.assertEqual(ops[1].os_type, "linux1")
self.assertFalse(ops[1].osparams)
+ def testErrors(self):
+ self.assertRaises(http.HttpBadRequest, self.Parse,
+ "foo", "not a dictionary")
+
class TestGroupRename(unittest.TestCase):
def test(self):
self.assertFalse(hasattr(op, "disks"))
self.assertRaises(IndexError, cl.GetNextSubmittedJob)
+ def testNoDisks(self):
+ clfactory = _FakeClientFactory(_FakeClient)
+
+ handler = _CreateHandler(rlib2.R_2_instances_name_replace_disks,
+ ["inst20661"], {}, {}, clfactory)
+ self.assertRaises(http.HttpBadRequest, handler.POST)
+
+ for disks in [None, "", {}]:
+ handler = _CreateHandler(rlib2.R_2_instances_name_replace_disks,
+ ["inst20661"], {}, {
+ "disks": disks,
+ }, clfactory)
+ self.assertRaises(http.HttpBadRequest, handler.POST)
+
def testWrong(self):
clfactory = _FakeClientFactory(_FakeClient)
self.assertRaises(IndexError, cl.GetNextSubmittedJob)
-if __name__ == '__main__':
+class TestSimpleResources(unittest.TestCase):
+ def setUp(self):
+ self.clfactory = _FakeClientFactory(_FakeClient)
+
+ def tearDown(self):
+ self.assertRaises(IndexError, self.clfactory.GetNextClient)
+
+ def testFeatures(self):
+ handler = _CreateHandler(rlib2.R_2_features, [], {}, None, self.clfactory)
+ self.assertEqual(set(handler.GET()), rlib2.ALL_FEATURES)
+
+ def testEmpty(self):
+ for cls in [rlib2.R_root, rlib2.R_2]:
+ handler = _CreateHandler(cls, [], {}, None, self.clfactory)
+ self.assertTrue(handler.GET() is None)
+
+ def testVersion(self):
+ handler = _CreateHandler(rlib2.R_version, [], {}, None, self.clfactory)
+ self.assertEqual(handler.GET(), constants.RAPI_VERSION)
+
+
+class TestClusterInfo(unittest.TestCase):
+ class _ClusterInfoClient:
+ def __init__(self, address=None):
+ self.cluster_info = None
+
+ def QueryClusterInfo(self):
+ assert self.cluster_info is None
+ self.cluster_info = object()
+ return self.cluster_info
+
+ def test(self):
+ clfactory = _FakeClientFactory(self._ClusterInfoClient)
+ handler = _CreateHandler(rlib2.R_2_info, [], {}, None, clfactory)
+ result = handler.GET()
+ cl = clfactory.GetNextClient()
+ self.assertRaises(IndexError, clfactory.GetNextClient)
+ self.assertEqual(result, cl.cluster_info)
+
+
+class TestInstancesMultiAlloc(unittest.TestCase):
+ def testInstanceUpdate(self):
+ clfactory = _FakeClientFactory(_FakeClient)
+ data = {
+ "instances": [{
+ "instance_name": "bar",
+ "mode": "create",
+ }, {
+ "instance_name": "foo",
+ "mode": "create",
+ }],
+ }
+ handler = _CreateHandler(rlib2.R_2_instances_multi_alloc, [], {}, data,
+ clfactory)
+ (body, _) = handler.GetPostOpInput()
+ self.assertTrue(compat.all([inst["OP_ID"] == handler.POST_OPCODE.OP_ID
+ for inst in body["instances"]]))
+
+
+class TestPermissions(unittest.TestCase):
+ def testEquality(self):
+ self.assertEqual(rlib2.R_2_query.GET_ACCESS, rlib2.R_2_query.PUT_ACCESS)
+ self.assertEqual(rlib2.R_2_query.GET_ACCESS,
+ rlib2.R_2_instances_name_console.GET_ACCESS)
+
+ def testMethodAccess(self):
+ for handler in connector.CONNECTOR.values():
+ for method in baserlib._SUPPORTED_METHODS:
+ access = getattr(handler, "%s_ACCESS" % method)
+ self.assertFalse(set(access) - rapi.RAPI_ACCESS_ALL,
+ msg=("Handler '%s' uses unknown access options for"
+ " method %s" % (handler, method)))
+ self.assertTrue(rapi.RAPI_ACCESS_READ not in access or
+ rapi.RAPI_ACCESS_WRITE in access,
+ msg=("Handler '%s' gives query, but not write access"
+ " for method %s (the latter includes query and"
+ " should therefore be given as well)" %
+ (handler, method)))
+
+
+if __name__ == "__main__":
testutils.GanetiTestProgram()