Statistics
| Branch: | Tag: | Revision:

root / test / py / cmdlib / node_unittest.py @ 560ef132

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

    
33
from testsupport import *
34

    
35
import testutils
36

    
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

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

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

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

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

    
67
    self.netutils_mod.TcpPing.return_value = True
68

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

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

    
77
    node_verify_result = \
78
      self.RpcResultsBuilder() \
79
        .CreateSuccessfulNodeResult(self.node_add, {constants.NV_NODELIST: []})
80
    # we can't know the node's UUID in advance, so use defaultdict here
81
    self.rpc.call_node_verify.return_value = \
82
      defaultdict(lambda: node_verify_result, {})
83
    self.rpc.call_node_crypto_tokens.return_value = \
84
      self.RpcResultsBuilder() \
85
        .CreateSuccessfulNodeResult(self.node_add,
86
            [(constants.CRYPTO_TYPE_SSL_DIGEST, "IA:MA:FA:KE:DI:GE:ST")])
87

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

    
95
    op = self.CopyOpCode(self.op_add,
96
                         ndparams=ndparams)
97

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

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

    
112
  def testAddCandidateCert(self):
113
    self.ExecOpCode(self.op_add)
114

    
115
    created_node = self.cfg.GetNodeInfoByName(self.op_add.node_name)
116
    cluster = self.cfg.GetClusterInfo()
117
    self.assertTrue(created_node.uuid in cluster.candidate_certs)
118

    
119
  def testReAddCandidateCert(self):
120
    cluster = self.cfg.GetClusterInfo()
121
    self.ExecOpCode(self.op_readd)
122
    created_node = self.cfg.GetNodeInfoByName(self.op_readd.node_name)
123
    self.assertTrue(created_node.uuid in cluster.candidate_certs)
124

    
125
  def testAddNoCandidateCert(self):
126
    op = self.CopyOpCode(self.op_add,
127
                         master_capable=False)
128
    self.ExecOpCode(op)
129

    
130
    created_node = self.cfg.GetNodeInfoByName(self.op_add.node_name)
131
    cluster = self.cfg.GetClusterInfo()
132
    self.assertFalse(created_node.uuid in cluster.candidate_certs)
133

    
134
  def testWithoutOVS(self):
135
    self.ExecOpCode(self.op_add)
136

    
137
    created_node = self.cfg.GetNodeInfoByName(self.op_add.node_name)
138
    self.assertEqual(None,
139
                     created_node.ndparams.get(constants.ND_OVS, None))
140

    
141
  def testWithOVS(self):
142
    ndparams = {
143
      constants.ND_OVS: True,
144
      constants.ND_OVS_LINK: "eth2",
145
    }
146

    
147
    op = self.CopyOpCode(self.op_add,
148
                         ndparams=ndparams)
149

    
150
    self.ExecOpCode(op)
151

    
152
    created_node = self.cfg.GetNodeInfoByName(op.node_name)
153
    self.assertEqual(ndparams[constants.ND_OVS],
154
                     created_node.ndparams.get(constants.ND_OVS, None))
155
    self.assertEqual(ndparams[constants.ND_OVS_LINK],
156
                     created_node.ndparams.get(constants.ND_OVS_LINK, None))
157

    
158
  def testReaddingMaster(self):
159
    op = opcodes.OpNodeAdd(node_name=self.cfg.GetMasterNodeName(),
160
                           readd=True)
161

    
162
    self.ExecOpCodeExpectOpPrereqError(op, "Cannot readd the master node")
163

    
164
  def testReaddNotVmCapableNode(self):
165
    self.cfg.AddNewInstance(primary_node=self.node_readd)
166
    self.netutils_mod.GetHostname.return_value = \
167
      HostnameMock(self.node_readd.name, self.node_readd.primary_ip)
168

    
169
    op = self.CopyOpCode(self.op_readd, vm_capable=False)
170

    
171
    self.ExecOpCodeExpectOpPrereqError(op, "Node .* being re-added with"
172
                                       " vm_capable flag set to false, but it"
173
                                       " already holds instances")
174

    
175
  def testReaddAndPassNodeGroup(self):
176
    op = self.CopyOpCode(self.op_readd,group="groupname")
177

    
178
    self.ExecOpCodeExpectOpPrereqError(op, "Cannot pass a node group when a"
179
                                       " node is being readded")
180

    
181
  def testPrimaryIPv6(self):
182
    self.master.secondary_ip = self.master.primary_ip
183

    
184
    op = self.CopyOpCode(self.op_add, primary_ip="2001:DB8::1",
185
                         secondary_ip=self.REMOVE)
186

    
187
    self.ExecOpCode(op)
188

    
189
  def testInvalidSecondaryIP(self):
190
    op = self.CopyOpCode(self.op_add, secondary_ip="333.444.555.777")
191

    
192
    self.ExecOpCodeExpectOpPrereqError(op, "Secondary IP .* needs to be a valid"
193
                                       " IPv4 address")
194

    
195
  def testNodeAlreadyInCluster(self):
196
    op = self.CopyOpCode(self.op_readd, readd=False)
197

    
198
    self.ExecOpCodeExpectOpPrereqError(op, "Node %s is already in the"
199
                                       " configuration" % self.node_readd.name)
200

    
201
  def testReaddNodeNotInConfiguration(self):
202
    op = self.CopyOpCode(self.op_add, readd=True)
203

    
204
    self.ExecOpCodeExpectOpPrereqError(op, "Node %s is not in the"
205
                                       " configuration" % self.node_add.name)
206

    
207
  def testPrimaryIpConflict(self):
208
    # In LUNodeAdd, DNS will resolve the node name to an IP address, that is
209
    # used to overwrite any given primary_ip value!
210
    # Thus we need to mock this DNS resolver here!
211
    self.netutils_mod.GetHostname.return_value = \
212
      HostnameMock(self.node_add.name, self.node_readd.primary_ip)
213

    
214
    op = self.CopyOpCode(self.op_add)
215

    
216
    self.ExecOpCodeExpectOpPrereqError(op, "New node ip address.* conflict with"
217
                                       " existing node")
218

    
219
  def testSecondaryIpConflict(self):
220
    op = self.CopyOpCode(self.op_add, secondary_ip=self.node_readd.secondary_ip)
221

    
222
    self.ExecOpCodeExpectOpPrereqError(op, "New node ip address.* conflict with"
223
                                       " existing node")
224

    
225
  def testReaddWithDifferentIP(self):
226
    op = self.CopyOpCode(self.op_readd, primary_ip="192.0.2.100",
227
                         secondary_ip="230.0.113.100")
228

    
229
    self.ExecOpCodeExpectOpPrereqError(op, "Readded node doesn't have the same"
230
                                       " IP address configuration as before")
231

    
232
  def testNodeHasSecondaryIpButNotMaster(self):
233
    self.master.secondary_ip = self.master.primary_ip
234

    
235
    self.ExecOpCodeExpectOpPrereqError(self.op_add, "The master has no"
236
                                       " secondary ip but the new node has one")
237

    
238
  def testMasterHasSecondaryIpButNotNode(self):
239
    op = self.CopyOpCode(self.op_add, secondary_ip=None)
240

    
241
    self.ExecOpCodeExpectOpPrereqError(op, "The master has a secondary ip but"
242
                                       " the new node doesn't have one")
243

    
244
  def testNodeNotReachableByPing(self):
245
    self.netutils_mod.TcpPing.return_value = False
246

    
247
    op = self.CopyOpCode(self.op_add)
248

    
249
    self.ExecOpCodeExpectOpPrereqError(op, "Node not reachable by ping")
250

    
251
  def testNodeNotReachableByPingOnSecondary(self):
252
    self.netutils_mod.GetHostname.return_value = \
253
      HostnameMock(self.node_add.name, self.node_add.primary_ip)
254
    self.netutils_mod.TcpPing.side_effect = \
255
      compat.partial(_TcpPingFailSecondary, self.cfg, self.netutils_mod.TcpPing)
256

    
257
    op = self.CopyOpCode(self.op_add)
258

    
259
    self.ExecOpCodeExpectOpPrereqError(op, "Node secondary ip not reachable by"
260
                                       " TCP based ping to node daemon port")
261

    
262
  def testCantGetVersion(self):
263
    self.mocked_dns_rpc.call_version.return_value = \
264
      self.RpcResultsBuilder(use_node_names=True) \
265
        .AddErrorNode(self.node_add) \
266
        .Build()
267

    
268
    op = self.CopyOpCode(self.op_add)
269
    self.ExecOpCodeExpectOpExecError(op, "Can't get version information from"
270
                                     " node %s" % self.node_add.name)
271

    
272
if __name__ == "__main__":
273
  testutils.GanetiTestProgram()