blob: 8dcad784432b13072d6a1205e7a847dd1748d33d [file] [log] [blame]
#!/usr/bin/python
#
# Copyright (C) 2013 Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""Tests for LUNode*
"""
from collections import defaultdict
import mock
from ganeti import compat
from ganeti import constants
from ganeti import objects
from ganeti import opcodes
from ganeti.cmdlib import node
from testsupport import *
import testutils
# pylint: disable=W0613
def _TcpPingFailSecondary(cfg, mock_fct, target, port, timeout=None,
live_port_needed=None, source=None):
# This will return True if target is in 192.0.2.0/24 (primary range)
# and False if not.
return "192.0.2." in target
class TestLUNodeAdd(CmdlibTestCase):
def setUp(self):
super(TestLUNodeAdd, self).setUp()
# One node for testing readding:
self.node_readd = self.cfg.AddNewNode()
self.op_readd = opcodes.OpNodeAdd(node_name=self.node_readd.name,
readd=True,
primary_ip=self.node_readd.primary_ip,
secondary_ip=self.node_readd.secondary_ip)
# One node for testing adding:
# don't add to configuration now!
self.node_add = objects.Node(name="node_add",
primary_ip="192.0.2.200",
secondary_ip="203.0.113.200")
self.op_add = opcodes.OpNodeAdd(node_name=self.node_add.name,
primary_ip=self.node_add.primary_ip,
secondary_ip=self.node_add.secondary_ip)
self.netutils_mod.TcpPing.return_value = True
self.mocked_dns_rpc = self.rpc_mod.DnsOnlyRunner.return_value
self.mocked_dns_rpc.call_version.return_value = \
self.RpcResultsBuilder(use_node_names=True) \
.AddSuccessfulNode(self.node_add, constants.CONFIG_VERSION) \
.AddSuccessfulNode(self.node_readd, constants.CONFIG_VERSION) \
.Build()
node_verify_result = \
self.RpcResultsBuilder() \
.CreateSuccessfulNodeResult(self.node_add, {constants.NV_NODELIST: []})
# we can't know the node's UUID in advance, so use defaultdict here
self.rpc.call_node_verify.return_value = \
defaultdict(lambda: node_verify_result, {})
self.rpc.call_node_crypto_tokens.return_value = \
self.RpcResultsBuilder() \
.CreateSuccessfulNodeResult(self.node_add,
[(constants.CRYPTO_TYPE_SSL_DIGEST, "IA:MA:FA:KE:DI:GE:ST")])
def testOvsNoLink(self):
ndparams = {
constants.ND_OVS: True,
constants.ND_OVS_NAME: "testswitch",
constants.ND_OVS_LINK: None,
}
op = self.CopyOpCode(self.op_add,
ndparams=ndparams)
self.ExecOpCode(op)
self.assertLogContainsRegex(
"No physical interface for OpenvSwitch was given."
" OpenvSwitch will not have an outside connection."
" This might not be what you want")
created_node = self.cfg.GetNodeInfoByName(op.node_name)
self.assertEqual(ndparams[constants.ND_OVS],
created_node.ndparams.get(constants.ND_OVS, None))
self.assertEqual(ndparams[constants.ND_OVS_NAME],
created_node.ndparams.get(constants.ND_OVS_NAME, None))
self.assertEqual(ndparams[constants.ND_OVS_LINK],
created_node.ndparams.get(constants.ND_OVS_LINK, None))
def testAddCandidateCert(self):
self.ExecOpCode(self.op_add)
created_node = self.cfg.GetNodeInfoByName(self.op_add.node_name)
cluster = self.cfg.GetClusterInfo()
self.assertTrue(created_node.uuid in cluster.candidate_certs)
def testReAddCandidateCert(self):
cluster = self.cfg.GetClusterInfo()
self.ExecOpCode(self.op_readd)
created_node = self.cfg.GetNodeInfoByName(self.op_readd.node_name)
self.assertTrue(created_node.uuid in cluster.candidate_certs)
def testAddNoCandidateCert(self):
op = self.CopyOpCode(self.op_add,
master_capable=False)
self.ExecOpCode(op)
created_node = self.cfg.GetNodeInfoByName(self.op_add.node_name)
cluster = self.cfg.GetClusterInfo()
self.assertFalse(created_node.uuid in cluster.candidate_certs)
def testWithoutOVS(self):
self.ExecOpCode(self.op_add)
created_node = self.cfg.GetNodeInfoByName(self.op_add.node_name)
self.assertEqual(None,
created_node.ndparams.get(constants.ND_OVS, None))
def testWithOVS(self):
ndparams = {
constants.ND_OVS: True,
constants.ND_OVS_LINK: "eth2",
}
op = self.CopyOpCode(self.op_add,
ndparams=ndparams)
self.ExecOpCode(op)
created_node = self.cfg.GetNodeInfoByName(op.node_name)
self.assertEqual(ndparams[constants.ND_OVS],
created_node.ndparams.get(constants.ND_OVS, None))
self.assertEqual(ndparams[constants.ND_OVS_LINK],
created_node.ndparams.get(constants.ND_OVS_LINK, None))
def testReaddingMaster(self):
op = opcodes.OpNodeAdd(node_name=self.cfg.GetMasterNodeName(),
readd=True)
self.ExecOpCodeExpectOpPrereqError(op, "Cannot readd the master node")
def testReaddNotVmCapableNode(self):
self.cfg.AddNewInstance(primary_node=self.node_readd)
self.netutils_mod.GetHostname.return_value = \
HostnameMock(self.node_readd.name, self.node_readd.primary_ip)
op = self.CopyOpCode(self.op_readd, vm_capable=False)
self.ExecOpCodeExpectOpPrereqError(op, "Node .* being re-added with"
" vm_capable flag set to false, but it"
" already holds instances")
def testReaddAndPassNodeGroup(self):
op = self.CopyOpCode(self.op_readd,group="groupname")
self.ExecOpCodeExpectOpPrereqError(op, "Cannot pass a node group when a"
" node is being readded")
def testPrimaryIPv6(self):
self.master.secondary_ip = self.master.primary_ip
op = self.CopyOpCode(self.op_add, primary_ip="2001:DB8::1",
secondary_ip=self.REMOVE)
self.ExecOpCode(op)
def testInvalidSecondaryIP(self):
op = self.CopyOpCode(self.op_add, secondary_ip="333.444.555.777")
self.ExecOpCodeExpectOpPrereqError(op, "Secondary IP .* needs to be a valid"
" IPv4 address")
def testNodeAlreadyInCluster(self):
op = self.CopyOpCode(self.op_readd, readd=False)
self.ExecOpCodeExpectOpPrereqError(op, "Node %s is already in the"
" configuration" % self.node_readd.name)
def testReaddNodeNotInConfiguration(self):
op = self.CopyOpCode(self.op_add, readd=True)
self.ExecOpCodeExpectOpPrereqError(op, "Node %s is not in the"
" configuration" % self.node_add.name)
def testPrimaryIpConflict(self):
# In LUNodeAdd, DNS will resolve the node name to an IP address, that is
# used to overwrite any given primary_ip value!
# Thus we need to mock this DNS resolver here!
self.netutils_mod.GetHostname.return_value = \
HostnameMock(self.node_add.name, self.node_readd.primary_ip)
op = self.CopyOpCode(self.op_add)
self.ExecOpCodeExpectOpPrereqError(op, "New node ip address.* conflict with"
" existing node")
def testSecondaryIpConflict(self):
op = self.CopyOpCode(self.op_add, secondary_ip=self.node_readd.secondary_ip)
self.ExecOpCodeExpectOpPrereqError(op, "New node ip address.* conflict with"
" existing node")
def testReaddWithDifferentIP(self):
op = self.CopyOpCode(self.op_readd, primary_ip="192.0.2.100",
secondary_ip="230.0.113.100")
self.ExecOpCodeExpectOpPrereqError(op, "Readded node doesn't have the same"
" IP address configuration as before")
def testNodeHasSecondaryIpButNotMaster(self):
self.master.secondary_ip = self.master.primary_ip
self.ExecOpCodeExpectOpPrereqError(self.op_add, "The master has no"
" secondary ip but the new node has one")
def testMasterHasSecondaryIpButNotNode(self):
op = self.CopyOpCode(self.op_add, secondary_ip=None)
self.ExecOpCodeExpectOpPrereqError(op, "The master has a secondary ip but"
" the new node doesn't have one")
def testNodeNotReachableByPing(self):
self.netutils_mod.TcpPing.return_value = False
op = self.CopyOpCode(self.op_add)
self.ExecOpCodeExpectOpPrereqError(op, "Node not reachable by ping")
def testNodeNotReachableByPingOnSecondary(self):
self.netutils_mod.GetHostname.return_value = \
HostnameMock(self.node_add.name, self.node_add.primary_ip)
self.netutils_mod.TcpPing.side_effect = \
compat.partial(_TcpPingFailSecondary, self.cfg, self.netutils_mod.TcpPing)
op = self.CopyOpCode(self.op_add)
self.ExecOpCodeExpectOpPrereqError(op, "Node secondary ip not reachable by"
" TCP based ping to node daemon port")
def testCantGetVersion(self):
self.mocked_dns_rpc.call_version.return_value = \
self.RpcResultsBuilder(use_node_names=True) \
.AddErrorNode(self.node_add) \
.Build()
op = self.CopyOpCode(self.op_add)
self.ExecOpCodeExpectOpPrereqError(op, "Can't get version information from"
" node %s" % self.node_add.name)
class TestLUNodeSetParams(CmdlibTestCase):
def setUp(self):
super(TestLUNodeSetParams, self).setUp()
self.MockOut(node, 'netutils', self.netutils_mod)
node.netutils.TcpPing.return_value = True
self.node = self.cfg.AddNewNode(
primary_ip='192.168.168.191',
secondary_ip='192.168.168.192',
master_candidate=True, uuid='blue_bunny')
self.snode = self.cfg.AddNewNode(
primary_ip='192.168.168.193',
secondary_ip='192.168.168.194',
master_candidate=True, uuid='pink_bunny')
def testSetSecondaryIp(self):
self.instance = self.cfg.AddNewInstance(primary_node=self.node,
secondary_node=self.snode,
disk_template='drbd')
op = opcodes.OpNodeSetParams(node_name=self.node.name,
secondary_ip='254.254.254.254')
self.ExecOpCode(op)
self.assertEqual('254.254.254.254', self.node.secondary_ip)
self.assertEqual(sorted(self.wconfd.all_locks.items()), [
('cluster/BGL', 'shared'),
('instance/mock_inst_1.example.com', 'shared'),
('node-res/blue_bunny', 'exclusive'),
('node/blue_bunny', 'exclusive')])
def testSetSecondaryIpNoLock(self):
self.instance = self.cfg.AddNewInstance(primary_node=self.node,
secondary_node=self.snode,
disk_template='file')
op = opcodes.OpNodeSetParams(node_name=self.node.name,
secondary_ip='254.254.254.254')
self.ExecOpCode(op)
self.assertEqual('254.254.254.254', self.node.secondary_ip)
self.assertEqual(sorted(self.wconfd.all_locks.items()), [
('cluster/BGL', 'shared'),
('node-res/blue_bunny', 'exclusive'),
('node/blue_bunny', 'exclusive')])
if __name__ == "__main__":
testutils.GanetiTestProgram()