Statistics
| Branch: | Tag: | Revision:

root / test / py / cmdlib / node_unittest.py @ 47cce79a

History | View | Annotate | Download (9.3 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
# pylint: disable=W0613
39
def _TcpPingFailSecondary(cfg, mock_fct, target, port, timeout=None,
40
                          live_port_needed=None, source=None):
41
  # This will return True if target is in 192.0.2.0/24 (primary range)
42
  # and False if not.
43
  return "192.0.2." in target
44

    
45
class TestLUNodeAdd(CmdlibTestCase):
46
  def setUp(self):
47
    super(TestLUNodeAdd, self).setUp()
48

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

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

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

    
66
    self.netutils_mod.TcpPing.return_value = True
67

    
68
    self.mocked_dns_rpc = self.rpc_mod.DnsOnlyRunner.return_value
69

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

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

    
83
  def testOvsParamsButNotEnabled(self):
84
    ndparams = {
85
      constants.ND_OVS: False,
86
      constants.ND_OVS_NAME: "testswitch",
87
    }
88

    
89
    op = self.CopyOpCode(self.op_add,
90
                         ndparams=ndparams)
91

    
92
    self.ExecOpCodeExpectOpPrereqError(op, "OpenvSwitch is not enabled")
93

    
94
  def testOvsNoLink(self):
95
    ndparams = {
96
      constants.ND_OVS: True,
97
      constants.ND_OVS_NAME: "testswitch",
98
      constants.ND_OVS_LINK: None,
99
    }
100

    
101
    op = self.CopyOpCode(self.op_add,
102
                         ndparams=ndparams)
103

    
104
    self.ExecOpCode(op)
105
    self.assertLogContainsRegex(
106
      "No physical interface for OpenvSwitch was given."
107
      " OpenvSwitch will not have an outside connection."
108
      " This might not be what you want")
109

    
110
    created_node = self.cfg.GetNodeInfoByName(op.node_name)
111
    self.assertEqual(ndparams[constants.ND_OVS],
112
                     created_node.ndparams.get(constants.ND_OVS, None))
113
    self.assertEqual(ndparams[constants.ND_OVS_NAME],
114
                     created_node.ndparams.get(constants.ND_OVS_NAME, None))
115
    self.assertEqual(ndparams[constants.ND_OVS_LINK],
116
                     created_node.ndparams.get(constants.ND_OVS_LINK, None))
117

    
118
  def testWithoutOVS(self):
119
    self.ExecOpCode(self.op_add)
120

    
121
    created_node = self.cfg.GetNodeInfoByName(self.op_add.node_name)
122
    self.assertEqual(None,
123
                     created_node.ndparams.get(constants.ND_OVS, None))
124

    
125
  def testWithOVS(self):
126
    ndparams = {
127
      constants.ND_OVS: True,
128
      constants.ND_OVS_LINK: "eth2",
129
    }
130

    
131
    op = self.CopyOpCode(self.op_add,
132
                         ndparams=ndparams)
133

    
134
    self.ExecOpCode(op)
135

    
136
    created_node = self.cfg.GetNodeInfoByName(op.node_name)
137
    self.assertEqual(ndparams[constants.ND_OVS],
138
                     created_node.ndparams.get(constants.ND_OVS, None))
139
    self.assertEqual(ndparams[constants.ND_OVS_LINK],
140
                     created_node.ndparams.get(constants.ND_OVS_LINK, None))
141

    
142
  def testReaddingMaster(self):
143
    op = opcodes.OpNodeAdd(node_name=self.cfg.GetMasterNodeName(),
144
                           readd=True)
145

    
146
    self.ExecOpCodeExpectOpPrereqError(op, "Cannot readd the master node")
147

    
148
  def testReaddNotVmCapableNode(self):
149
    self.cfg.AddNewInstance(primary_node=self.node_readd)
150
    self.netutils_mod.GetHostname.return_value = \
151
      HostnameMock(self.node_readd.name, self.node_readd.primary_ip)
152

    
153
    op = self.CopyOpCode(self.op_readd, vm_capable=False)
154

    
155
    self.ExecOpCodeExpectOpPrereqError(op, "Node .* being re-added with"
156
                                       " vm_capable flag set to false, but it"
157
                                       " already holds instances")
158

    
159
  def testReaddAndPassNodeGroup(self):
160
    op = self.CopyOpCode(self.op_readd,group="groupname")
161

    
162
    self.ExecOpCodeExpectOpPrereqError(op, "Cannot pass a node group when a"
163
                                       " node is being readded")
164

    
165
  def testPrimaryIPv6(self):
166
    self.master.secondary_ip = self.master.primary_ip
167

    
168
    op = self.CopyOpCode(self.op_add, primary_ip="2001:DB8::1",
169
                         secondary_ip=self.REMOVE)
170

    
171
    self.ExecOpCode(op)
172

    
173
  def testInvalidSecondaryIP(self):
174
    op = self.CopyOpCode(self.op_add, secondary_ip="333.444.555.777")
175

    
176
    self.ExecOpCodeExpectOpPrereqError(op, "Secondary IP .* needs to be a valid"
177
                                       " IPv4 address")
178

    
179
  def testNodeAlreadyInCluster(self):
180
    op = self.CopyOpCode(self.op_readd, readd=False)
181

    
182
    self.ExecOpCodeExpectOpPrereqError(op, "Node %s is already in the"
183
                                       " configuration" % self.node_readd.name)
184

    
185
  def testReaddNodeNotInConfiguration(self):
186
    op = self.CopyOpCode(self.op_add, readd=True)
187

    
188
    self.ExecOpCodeExpectOpPrereqError(op, "Node %s is not in the"
189
                                       " configuration" % self.node_add.name)
190

    
191
  def testPrimaryIpConflict(self):
192
    # In LUNodeAdd, DNS will resolve the node name to an IP address, that is
193
    # used to overwrite any given primary_ip value!
194
    # Thus we need to mock this DNS resolver here!
195
    self.netutils_mod.GetHostname.return_value = \
196
      HostnameMock(self.node_add.name, self.node_readd.primary_ip)
197

    
198
    op = self.CopyOpCode(self.op_add)
199

    
200
    self.ExecOpCodeExpectOpPrereqError(op, "New node ip address.* conflict with"
201
                                       " existing node")
202

    
203
  def testSecondaryIpConflict(self):
204
    op = self.CopyOpCode(self.op_add, secondary_ip=self.node_readd.secondary_ip)
205

    
206
    self.ExecOpCodeExpectOpPrereqError(op, "New node ip address.* conflict with"
207
                                       " existing node")
208

    
209
  def testReaddWithDifferentIP(self):
210
    op = self.CopyOpCode(self.op_readd, primary_ip="192.0.2.100",
211
                         secondary_ip="230.0.113.100")
212

    
213
    self.ExecOpCodeExpectOpPrereqError(op, "Readded node doesn't have the same"
214
                                       " IP address configuration as before")
215

    
216

    
217
  def testNodeHasSecondaryIpButNotMaster(self):
218
    self.master.secondary_ip = self.master.primary_ip
219

    
220
    self.ExecOpCodeExpectOpPrereqError(self.op_add, "The master has no"
221
                                       " secondary ip but the new node has one")
222

    
223
  def testMasterHasSecondaryIpButNotNode(self):
224
    op = self.CopyOpCode(self.op_add, secondary_ip=None)
225

    
226
    self.ExecOpCodeExpectOpPrereqError(op, "The master has a secondary ip but"
227
                                       " the new node doesn't have one")
228

    
229
  def testNodeNotReachableByPing(self):
230
    self.netutils_mod.TcpPing.return_value = False
231

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

    
234
    self.ExecOpCodeExpectOpPrereqError(op, "Node not reachable by ping")
235

    
236
  def testNodeNotReachableByPingOnSecondary(self):
237
    self.netutils_mod.GetHostname.return_value = \
238
      HostnameMock(self.node_add.name, self.node_add.primary_ip)
239
    self.netutils_mod.TcpPing.side_effect = \
240
      compat.partial(_TcpPingFailSecondary, self.cfg, self.netutils_mod.TcpPing)
241

    
242
    op = self.CopyOpCode(self.op_add)
243

    
244
    self.ExecOpCodeExpectOpPrereqError(op, "Node secondary ip not reachable by"
245
                                       " TCP based ping to node daemon port")
246

    
247
  def testCantGetVersion(self):
248
    self.mocked_dns_rpc.call_version.return_value = \
249
      self.RpcResultsBuilder(use_node_names=True) \
250
        .AddErrorNode(self.node_add) \
251
        .Build()
252

    
253
    op = self.CopyOpCode(self.op_add)
254
    self.ExecOpCodeExpectOpExecError(op, "Can't get version information from"
255
                                     " node %s" % self.node_add.name)
256

    
257
if __name__ == "__main__":
258
  testutils.GanetiTestProgram()