Statistics
| Branch: | Tag: | Revision:

root / qa / qa_node.py @ a1de4b18

History | View | Annotate | Download (11.4 kB)

1
#
2
#
3

    
4
# Copyright (C) 2007 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
from ganeti import utils
23
from ganeti import constants
24
from ganeti import query
25
from ganeti import serializer
26

    
27
import qa_config
28
import qa_error
29
import qa_utils
30

    
31
from qa_utils import AssertCommand
32

    
33

    
34
def _NodeAdd(node, readd=False):
35
  if not readd and node.get('_added', False):
36
    raise qa_error.Error("Node %s already in cluster" % node['primary'])
37
  elif readd and not node.get('_added', False):
38
    raise qa_error.Error("Node %s not yet in cluster" % node['primary'])
39

    
40
  cmd = ['gnt-node', 'add', "--no-ssh-key-check"]
41
  if node.get('secondary', None):
42
    cmd.append('--secondary-ip=%s' % node['secondary'])
43
  if readd:
44
    cmd.append('--readd')
45
  cmd.append(node['primary'])
46

    
47
  AssertCommand(cmd)
48

    
49
  node['_added'] = True
50

    
51

    
52
def _NodeRemove(node):
53
  AssertCommand(["gnt-node", "remove", node["primary"]])
54
  node['_added'] = False
55

    
56

    
57
def TestNodeAddAll():
58
  """Adding all nodes to cluster."""
59
  master = qa_config.GetMasterNode()
60
  for node in qa_config.get('nodes'):
61
    if node != master:
62
      _NodeAdd(node, readd=False)
63

    
64

    
65
def MarkNodeAddedAll():
66
  """Mark all nodes as added.
67

68
  This is useful if we don't create the cluster ourselves (in qa).
69

70
  """
71
  master = qa_config.GetMasterNode()
72
  for node in qa_config.get('nodes'):
73
    if node != master:
74
      node['_added'] = True
75

    
76

    
77
def TestNodeRemoveAll():
78
  """Removing all nodes from cluster."""
79
  master = qa_config.GetMasterNode()
80
  for node in qa_config.get('nodes'):
81
    if node != master:
82
      _NodeRemove(node)
83

    
84

    
85
def TestNodeReadd(node):
86
  """gnt-node add --readd"""
87
  _NodeAdd(node, readd=True)
88

    
89

    
90
def TestNodeInfo():
91
  """gnt-node info"""
92
  AssertCommand(["gnt-node", "info"])
93

    
94

    
95
def TestNodeVolumes():
96
  """gnt-node volumes"""
97
  AssertCommand(["gnt-node", "volumes"])
98

    
99

    
100
def TestNodeStorage():
101
  """gnt-node storage"""
102
  master = qa_config.GetMasterNode()
103

    
104
  for storage_type in constants.VALID_STORAGE_TYPES:
105
    # Test simple list
106
    AssertCommand(["gnt-node", "list-storage", "--storage-type", storage_type])
107

    
108
    # Test all storage fields
109
    cmd = ["gnt-node", "list-storage", "--storage-type", storage_type,
110
           "--output=%s" % ",".join(list(constants.VALID_STORAGE_FIELDS) +
111
                                    [constants.SF_NODE, constants.SF_TYPE])]
112
    AssertCommand(cmd)
113

    
114
    # Get list of valid storage devices
115
    cmd = ["gnt-node", "list-storage", "--storage-type", storage_type,
116
           "--output=node,name,allocatable", "--separator=|",
117
           "--no-headers"]
118
    output = qa_utils.GetCommandOutput(master["primary"],
119
                                       utils.ShellQuoteArgs(cmd))
120

    
121
    # Test with up to two devices
122
    testdevcount = 2
123

    
124
    for line in output.splitlines()[:testdevcount]:
125
      (node_name, st_name, st_allocatable) = line.split("|")
126

    
127
      # Dummy modification without any changes
128
      cmd = ["gnt-node", "modify-storage", node_name, storage_type, st_name]
129
      AssertCommand(cmd)
130

    
131
      # Make sure we end up with the same value as before
132
      if st_allocatable.lower() == "y":
133
        test_allocatable = ["no", "yes"]
134
      else:
135
        test_allocatable = ["yes", "no"]
136

    
137
      fail = (constants.SF_ALLOCATABLE not in
138
              constants.MODIFIABLE_STORAGE_FIELDS.get(storage_type, []))
139

    
140
      for i in test_allocatable:
141
        AssertCommand(["gnt-node", "modify-storage", "--allocatable", i,
142
                       node_name, storage_type, st_name], fail=fail)
143

    
144
      # Test repair functionality
145
      fail = (constants.SO_FIX_CONSISTENCY not in
146
              constants.VALID_STORAGE_OPERATIONS.get(storage_type, []))
147
      AssertCommand(["gnt-node", "repair-storage", node_name,
148
                     storage_type, st_name], fail=fail)
149

    
150

    
151
def TestNodeFailover(node, node2):
152
  """gnt-node failover"""
153
  if qa_utils.GetNodeInstances(node2, secondaries=False):
154
    raise qa_error.UnusableNodeError("Secondary node has at least one"
155
                                     " primary instance. This test requires"
156
                                     " it to have no primary instances.")
157

    
158
  # Fail over to secondary node
159
  AssertCommand(["gnt-node", "failover", "-f", node["primary"]])
160

    
161
  # ... and back again.
162
  AssertCommand(["gnt-node", "failover", "-f", node2["primary"]])
163

    
164

    
165
def TestNodeEvacuate(node, node2):
166
  """gnt-node evacuate"""
167
  node3 = qa_config.AcquireNode(exclude=[node, node2])
168
  try:
169
    if qa_utils.GetNodeInstances(node3, secondaries=True):
170
      raise qa_error.UnusableNodeError("Evacuation node has at least one"
171
                                       " secondary instance. This test requires"
172
                                       " it to have no secondary instances.")
173

    
174
    # Evacuate all secondary instances
175
    AssertCommand(["gnt-node", "evacuate", "-f",
176
                   "--new-secondary=%s" % node3["primary"], node2["primary"]])
177

    
178
    # ... and back again.
179
    AssertCommand(["gnt-node", "evacuate", "-f",
180
                   "--new-secondary=%s" % node2["primary"], node3["primary"]])
181
  finally:
182
    qa_config.ReleaseNode(node3)
183

    
184

    
185
def TestNodeModify(node):
186
  """gnt-node modify"""
187
  for flag in ["master-candidate", "drained", "offline"]:
188
    for value in ["yes", "no"]:
189
      AssertCommand(["gnt-node", "modify", "--force",
190
                     "--%s=%s" % (flag, value), node["primary"]])
191

    
192
  AssertCommand(["gnt-node", "modify", "--master-candidate=yes",
193
                 "--auto-promote", node["primary"]])
194

    
195

    
196
def _CreateOobScriptStructure():
197
  """Create a simple OOB handling script and its structure."""
198
  master = qa_config.GetMasterNode()
199

    
200
  data_path = qa_utils.UploadData(master["primary"], "")
201
  verify_path = qa_utils.UploadData(master["primary"], "")
202
  exit_code_path = qa_utils.UploadData(master["primary"], "")
203

    
204
  oob_script = (("#!/bin/bash\n"
205
                 "echo \"$@\" > %s\n"
206
                 "cat %s\n"
207
                 "exit $(< %s)\n") %
208
                (utils.ShellQuote(verify_path), utils.ShellQuote(data_path),
209
                 utils.ShellQuote(exit_code_path)))
210
  oob_path = qa_utils.UploadData(master["primary"], oob_script, mode=0700)
211

    
212
  return [oob_path, verify_path, data_path, exit_code_path]
213

    
214

    
215
def _UpdateOobFile(path, data):
216
  """Updates the data file with data."""
217
  master = qa_config.GetMasterNode()
218
  qa_utils.UploadData(master["primary"], data, filename=path)
219

    
220

    
221
def _AssertOobCall(verify_path, expected_args):
222
  """Assert the OOB call was performed with expetected args."""
223
  master = qa_config.GetMasterNode()
224

    
225
  verify_output_cmd = utils.ShellQuoteArgs(["cat", verify_path])
226
  output = qa_utils.GetCommandOutput(master["primary"], verify_output_cmd)
227

    
228
  qa_utils.AssertEqual(expected_args, output.strip())
229

    
230

    
231
def TestOutOfBand():
232
  """gnt-node power"""
233
  master = qa_config.GetMasterNode()
234

    
235
  (oob_path, verify_path,
236
   data_path, exit_code_path) = _CreateOobScriptStructure()
237

    
238
  try:
239
    AssertCommand(["gnt-cluster", "modify", "--node-parameters",
240
                   "oob_program=%s" % oob_path])
241

    
242
    # No data, exit 0
243
    _UpdateOobFile(exit_code_path, "0")
244

    
245
    AssertCommand(["gnt-node", "power", "on", master["primary"]])
246
    _AssertOobCall(verify_path, "power-on %s" % master["primary"])
247

    
248
    AssertCommand(["gnt-node", "power", "off", master["primary"]])
249
    _AssertOobCall(verify_path, "power-off %s" % master["primary"])
250

    
251
    AssertCommand(["gnt-node", "power", "cycle", master["primary"]])
252
    _AssertOobCall(verify_path, "power-cycle %s" % master["primary"])
253

    
254
    # This command should fail as it expects output which isn't provided yet
255
    # But it should have called the oob helper nevermind
256
    AssertCommand(["gnt-node", "power", "status", master["primary"]],
257
                  fail=True)
258
    _AssertOobCall(verify_path, "power-status %s" % master["primary"])
259

    
260
    # Data, exit 0
261
    _UpdateOobFile(data_path, serializer.DumpJson({ "powered": True }))
262

    
263
    AssertCommand(["gnt-node", "power", "status", master["primary"]])
264
    _AssertOobCall(verify_path, "power-status %s" % master["primary"])
265

    
266
    AssertCommand(["gnt-node", "power", "on", master["primary"]], fail=True)
267
    _AssertOobCall(verify_path, "power-on %s" % master["primary"])
268

    
269
    AssertCommand(["gnt-node", "power", "off", master["primary"]], fail=True)
270
    _AssertOobCall(verify_path, "power-off %s" % master["primary"])
271

    
272
    AssertCommand(["gnt-node", "power", "cycle", master["primary"]], fail=True)
273
    _AssertOobCall(verify_path, "power-cycle %s" % master["primary"])
274

    
275
    # Data, exit 1 (all should fail)
276
    _UpdateOobFile(exit_code_path, "1")
277

    
278
    AssertCommand(["gnt-node", "power", "on", master["primary"]], fail=True)
279
    _AssertOobCall(verify_path, "power-on %s" % master["primary"])
280

    
281
    AssertCommand(["gnt-node", "power", "off", master["primary"]], fail=True)
282
    _AssertOobCall(verify_path, "power-off %s" % master["primary"])
283

    
284
    AssertCommand(["gnt-node", "power", "cycle", master["primary"]], fail=True)
285
    _AssertOobCall(verify_path, "power-cycle %s" % master["primary"])
286

    
287
    AssertCommand(["gnt-node", "power", "status", master["primary"]],
288
                  fail=True)
289
    _AssertOobCall(verify_path, "power-status %s" % master["primary"])
290

    
291
    # No data, exit 1 (all should fail)
292
    _UpdateOobFile(data_path, "")
293
    AssertCommand(["gnt-node", "power", "on", master["primary"]], fail=True)
294
    _AssertOobCall(verify_path, "power-on %s" % master["primary"])
295

    
296
    AssertCommand(["gnt-node", "power", "off", master["primary"]], fail=True)
297
    _AssertOobCall(verify_path, "power-off %s" % master["primary"])
298

    
299
    AssertCommand(["gnt-node", "power", "cycle", master["primary"]], fail=True)
300
    _AssertOobCall(verify_path, "power-cycle %s" % master["primary"])
301

    
302
    AssertCommand(["gnt-node", "power", "status", master["primary"]],
303
                  fail=True)
304
    _AssertOobCall(verify_path, "power-status %s" % master["primary"])
305

    
306
    # Different OOB script for node
307
    verify_path2 = qa_utils.UploadData(master["primary"], "")
308
    oob_script = ("#!/bin/sh\n"
309
                  "echo \"$@\" > %s\n") % verify_path2
310
    oob_path2 = qa_utils.UploadData(master["primary"], oob_script, mode=0700)
311

    
312
    try:
313
      AssertCommand(["gnt-node", "modify", "--node-parameters",
314
                     "oob_program=%s" % oob_path2, master["primary"]])
315
      AssertCommand(["gnt-node", "power", "on", master["primary"]])
316
      _AssertOobCall(verify_path2, "power-on %s" % master["primary"])
317
    finally:
318
      AssertCommand(["gnt-node", "modify", "--node-parameters",
319
                     "oob_program=default", master["primary"]])
320
      AssertCommand(["rm", "-f", oob_path2, verify_path2])
321
  finally:
322
    AssertCommand(["gnt-cluster", "modify", "--node-parameters",
323
                   "oob_program=default"])
324
    AssertCommand(["rm", "-f", oob_path, verify_path, data_path,
325
                   exit_code_path])
326

    
327

    
328
def TestNodeList():
329
  """gnt-node list"""
330
  qa_utils.GenericQueryTest("gnt-node", query.NODE_FIELDS.keys())
331

    
332

    
333
def TestNodeListFields():
334
  """gnt-node list-fields"""
335
  qa_utils.GenericQueryFieldsTest("gnt-node", query.NODE_FIELDS.keys())