Statistics
| Branch: | Tag: | Revision:

root / test / py / cmdlib / node_unittest.py @ 07e68848

History | View | Annotate | Download (9 kB)

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

    
4
# Copyright (C) 2013 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
"""Tests for LUNode*
23

24
"""
25

    
26
from collections import defaultdict
27

    
28
from ganeti import compat
29
from ganeti import constants
30
from ganeti import objects
31
from ganeti import opcodes
32
from ganeti import errors
33

    
34
from testsupport import *
35

    
36
import testutils
37

    
38

    
39
# pylint: disable=W0613
40
def _TcpPingFailSecondary(cfg, mock_fct, target, port, timeout=None,
41
                          live_port_needed=None, source=None):
42
  # This will return True if target is in 192.0.2.0/24 (primary range)
43
  # and False if not.
44
  return "192.0.2." in target
45

    
46

    
47
class TestLUNodeAdd(CmdlibTestCase):
48
  def setUp(self):
49
    super(TestLUNodeAdd, self).setUp()
50

    
51
    # One node for testing readding:
52
    self.node_readd = self.cfg.AddNewNode()
53
    self.op_readd = opcodes.OpNodeAdd(node_name=self.node_readd.name,
54
                                      readd=True,
55
                                      primary_ip=self.node_readd.primary_ip,
56
                                      secondary_ip=self.node_readd.secondary_ip)
57

    
58
    # One node for testing adding:
59
    # don't add to configuration now!
60
    self.node_add = objects.Node(name="node_add",
61
                                 primary_ip="192.0.2.200",
62
                                 secondary_ip="203.0.113.200")
63

    
64
    self.op_add = opcodes.OpNodeAdd(node_name=self.node_add.name,
65
                                    primary_ip=self.node_add.primary_ip,
66
                                    secondary_ip=self.node_add.secondary_ip)
67

    
68
    self.netutils_mod.TcpPing.return_value = True
69

    
70
    self.mocked_dns_rpc = self.rpc_mod.DnsOnlyRunner.return_value
71

    
72
    self.mocked_dns_rpc.call_version.return_value = \
73
      self.RpcResultsBuilder(use_node_names=True) \
74
        .AddSuccessfulNode(self.node_add, constants.CONFIG_VERSION) \
75
        .AddSuccessfulNode(self.node_readd, constants.CONFIG_VERSION) \
76
        .Build()
77

    
78
    node_verify_result = \
79
      self.RpcResultsBuilder() \
80
        .CreateSuccessfulNodeResult(self.node_add, {constants.NV_NODELIST: []})
81
    # we can't know the node's UUID in advance, so use defaultdict here
82
    self.rpc.call_node_verify.return_value = \
83
      defaultdict(lambda: node_verify_result, {})
84

    
85
  def testOvsNoLink(self):
86
    ndparams = {
87
      constants.ND_OVS: True,
88
      constants.ND_OVS_NAME: "testswitch",
89
      constants.ND_OVS_LINK: None,
90
    }
91

    
92
    op = self.CopyOpCode(self.op_add,
93
                         ndparams=ndparams)
94

    
95
    self.ExecOpCode(op)
96
    self.assertLogContainsRegex(
97
      "No physical interface for OpenvSwitch was given."
98
      " OpenvSwitch will not have an outside connection."
99
      " This might not be what you want")
100

    
101
    created_node = self.cfg.GetNodeInfoByName(op.node_name)
102
    self.assertEqual(ndparams[constants.ND_OVS],
103
                     created_node.ndparams.get(constants.ND_OVS, None))
104
    self.assertEqual(ndparams[constants.ND_OVS_NAME],
105
                     created_node.ndparams.get(constants.ND_OVS_NAME, None))
106
    self.assertEqual(ndparams[constants.ND_OVS_LINK],
107
                     created_node.ndparams.get(constants.ND_OVS_LINK, None))
108

    
109
  def testWithoutOVS(self):
110
    self.ExecOpCode(self.op_add)
111

    
112
    created_node = self.cfg.GetNodeInfoByName(self.op_add.node_name)
113
    self.assertEqual(None,
114
                     created_node.ndparams.get(constants.ND_OVS, None))
115

    
116
  def testWithOVS(self):
117
    ndparams = {
118
      constants.ND_OVS: True,
119
      constants.ND_OVS_LINK: "eth2",
120
    }
121

    
122
    op = self.CopyOpCode(self.op_add,
123
                         ndparams=ndparams)
124

    
125
    self.ExecOpCode(op)
126

    
127
    created_node = self.cfg.GetNodeInfoByName(op.node_name)
128
    self.assertEqual(ndparams[constants.ND_OVS],
129
                     created_node.ndparams.get(constants.ND_OVS, None))
130
    self.assertEqual(ndparams[constants.ND_OVS_LINK],
131
                     created_node.ndparams.get(constants.ND_OVS_LINK, None))
132

    
133
  def testReaddingMaster(self):
134
    op = opcodes.OpNodeAdd(node_name=self.cfg.GetMasterNodeName(),
135
                           readd=True)
136

    
137
    self.ExecOpCodeExpectOpPrereqError(op, "Cannot readd the master node")
138

    
139
  def testReaddNotVmCapableNode(self):
140
    self.cfg.AddNewInstance(primary_node=self.node_readd)
141
    self.netutils_mod.GetHostname.return_value = \
142
      HostnameMock(self.node_readd.name, self.node_readd.primary_ip)
143

    
144
    op = self.CopyOpCode(self.op_readd, vm_capable=False)
145

    
146
    self.ExecOpCodeExpectOpPrereqError(op, "Node .* being re-added with"
147
                                       " vm_capable flag set to false, but it"
148
                                       " already holds instances")
149

    
150
  def testReaddAndPassNodeGroup(self):
151
    op = self.CopyOpCode(self.op_readd,group="groupname")
152

    
153
    self.ExecOpCodeExpectOpPrereqError(op, "Cannot pass a node group when a"
154
                                       " node is being readded")
155

    
156
  def testPrimaryIPv6(self):
157
    self.master.secondary_ip = self.master.primary_ip
158

    
159
    op = self.CopyOpCode(self.op_add, primary_ip="2001:DB8::1",
160
                         secondary_ip=self.REMOVE)
161

    
162
    self.ExecOpCode(op)
163

    
164
  def testInvalidSecondaryIP(self):
165
    op = self.CopyOpCode(self.op_add, secondary_ip="333.444.555.777")
166

    
167
    self.ExecOpCodeExpectOpPrereqError(op, "Secondary IP .* needs to be a valid"
168
                                       " IPv4 address")
169

    
170
  def testNodeAlreadyInCluster(self):
171
    op = self.CopyOpCode(self.op_readd, readd=False)
172

    
173
    self.ExecOpCodeExpectOpPrereqError(op, "Node %s is already in the"
174
                                       " configuration" % self.node_readd.name)
175

    
176
  def testReaddNodeNotInConfiguration(self):
177
    op = self.CopyOpCode(self.op_add, readd=True)
178

    
179
    self.ExecOpCodeExpectOpPrereqError(op, "Node %s is not in the"
180
                                       " configuration" % self.node_add.name)
181

    
182
  def testPrimaryIpConflict(self):
183
    # In LUNodeAdd, DNS will resolve the node name to an IP address, that is
184
    # used to overwrite any given primary_ip value!
185
    # Thus we need to mock this DNS resolver here!
186
    self.netutils_mod.GetHostname.return_value = \
187
      HostnameMock(self.node_add.name, self.node_readd.primary_ip)
188

    
189
    op = self.CopyOpCode(self.op_add)
190

    
191
    self.ExecOpCodeExpectOpPrereqError(op, "New node ip address.* conflict with"
192
                                       " existing node")
193

    
194
  def testSecondaryIpConflict(self):
195
    op = self.CopyOpCode(self.op_add, secondary_ip=self.node_readd.secondary_ip)
196

    
197
    self.ExecOpCodeExpectOpPrereqError(op, "New node ip address.* conflict with"
198
                                       " existing node")
199

    
200
  def testReaddWithDifferentIP(self):
201
    op = self.CopyOpCode(self.op_readd, primary_ip="192.0.2.100",
202
                         secondary_ip="230.0.113.100")
203

    
204
    self.ExecOpCodeExpectOpPrereqError(op, "Readded node doesn't have the same"
205
                                       " IP address configuration as before")
206

    
207

    
208
  def testNodeHasSecondaryIpButNotMaster(self):
209
    self.master.secondary_ip = self.master.primary_ip
210

    
211
    self.ExecOpCodeExpectOpPrereqError(self.op_add, "The master has no"
212
                                       " secondary ip but the new node has one")
213

    
214
  def testMasterHasSecondaryIpButNotNode(self):
215
    op = self.CopyOpCode(self.op_add, secondary_ip=None)
216

    
217
    self.ExecOpCodeExpectOpPrereqError(op, "The master has a secondary ip but"
218
                                       " the new node doesn't have one")
219

    
220
  def testNodeNotReachableByPing(self):
221
    self.netutils_mod.TcpPing.return_value = False
222

    
223
    op = self.CopyOpCode(self.op_add)
224

    
225
    self.ExecOpCodeExpectOpPrereqError(op, "Node not reachable by ping")
226

    
227
  def testNodeNotReachableByPingOnSecondary(self):
228
    self.netutils_mod.GetHostname.return_value = \
229
      HostnameMock(self.node_add.name, self.node_add.primary_ip)
230
    self.netutils_mod.TcpPing.side_effect = \
231
      compat.partial(_TcpPingFailSecondary, self.cfg, self.netutils_mod.TcpPing)
232

    
233
    op = self.CopyOpCode(self.op_add)
234

    
235
    self.ExecOpCodeExpectOpPrereqError(op, "Node secondary ip not reachable by"
236
                                       " TCP based ping to node daemon port")
237

    
238
  def testCantGetVersion(self):
239
    self.mocked_dns_rpc.call_version.return_value = \
240
      self.RpcResultsBuilder(use_node_names=True) \
241
        .AddErrorNode(self.node_add) \
242
        .Build()
243

    
244
    op = self.CopyOpCode(self.op_add)
245
    self.ExecOpCodeExpectOpExecError(op, "Can't get version information from"
246
                                     " node %s" % self.node_add.name)
247

    
248
if __name__ == "__main__":
249
  testutils.GanetiTestProgram()