Revision 8fada090

b/Makefile.am
776 776
	qa/qa_error.py \
777 777
	qa/qa_group.py \
778 778
	qa/qa_instance.py \
779
	qa/qa_instance_utils.py \
779 780
	qa/qa_job.py \
780 781
	qa/qa_node.py \
781 782
	qa/qa_os.py \
b/qa/qa_instance.py
23 23

  
24 24
"""
25 25

  
26
import operator
27 26
import os
28 27
import re
29 28

  
......
36 35
import qa_utils
37 36
import qa_error
38 37

  
39
from qa_utils import AssertIn, AssertCommand, AssertEqual
38
from qa_utils import AssertCommand, AssertEqual
40 39
from qa_utils import InstanceCheck, INST_DOWN, INST_UP, FIRST_ARG, RETURN_VALUE
40
from qa_instance_utils import CheckSsconfInstanceList, \
41
                              CreateInstanceDrbd8, \
42
                              CreateInstanceByDiskTemplate, \
43
                              CreateInstanceByDiskTemplateOneNode, \
44
                              GetGenericAddParameters
41 45

  
42 46

  
43 47
def _GetDiskStatePath(disk):
44 48
  return "/sys/block/%s/device/state" % disk
45 49

  
46 50

  
47
def _GetGenericAddParameters(inst, disk_template, force_mac=None):
48
  params = ["-B"]
49
  params.append("%s=%s,%s=%s" % (constants.BE_MINMEM,
50
                                 qa_config.get(constants.BE_MINMEM),
51
                                 constants.BE_MAXMEM,
52
                                 qa_config.get(constants.BE_MAXMEM)))
53

  
54
  if disk_template != constants.DT_DISKLESS:
55
    for idx, disk in enumerate(qa_config.GetDiskOptions()):
56
      size = disk.get("size")
57
      name = disk.get("name")
58
      diskparams = "%s:size=%s" % (idx, size)
59
      if name:
60
        diskparams += ",name=%s" % name
61
      params.extend(["--disk", diskparams])
62

  
63
  # Set static MAC address if configured
64
  if force_mac:
65
    nic0_mac = force_mac
66
  else:
67
    nic0_mac = inst.GetNicMacAddr(0, None)
68

  
69
  if nic0_mac:
70
    params.extend(["--net", "0:mac=%s" % nic0_mac])
71

  
72
  return params
73

  
74

  
75
def _CreateInstanceByDiskTemplateRaw(nodes_spec, disk_template, fail=False):
76
  """Creates an instance with the given disk template on the given nodes(s).
77
     Note that this function does not check if enough nodes are given for
78
     the respective disk template.
79

  
80
  @type nodes_spec: string
81
  @param nodes_spec: string specification of one node (by node name) or several
82
                     nodes according to the requirements of the disk template
83
  @type disk_template: string
84
  @param disk_template: the disk template to be used by the instance
85
  @return: the created instance
86

  
87
  """
88
  instance = qa_config.AcquireInstance()
89
  try:
90
    cmd = (["gnt-instance", "add",
91
            "--os-type=%s" % qa_config.get("os"),
92
            "--disk-template=%s" % disk_template,
93
            "--node=%s" % nodes_spec] +
94
           _GetGenericAddParameters(instance, disk_template))
95
    cmd.append(instance.name)
96

  
97
    AssertCommand(cmd, fail=fail)
98

  
99
    if not fail:
100
      _CheckSsconfInstanceList(instance.name)
101
      instance.SetDiskTemplate(disk_template)
102

  
103
      return instance
104
  except:
105
    instance.Release()
106
    raise
107

  
108
  # Handle the case where creation is expected to fail
109
  assert fail
110
  instance.Release()
111
  return None
112

  
113

  
114
def _CreateInstanceByDiskTemplateOneNode(nodes, disk_template, fail=False):
115
  """Creates an instance using the given disk template for disk templates
116
     for which one given node is sufficient. These templates are for example:
117
     plain, diskless, file, sharedfile, blockdev, rados.
118

  
119
  @type nodes: list of nodes
120
  @param nodes: a list of nodes, whose first element is used to create the
121
                instance
122
  @type disk_template: string
123
  @param disk_template: the disk template to be used by the instance
124
  @return: the created instance
125

  
126
  """
127
  assert len(nodes) > 0
128
  return _CreateInstanceByDiskTemplateRaw(nodes[0].primary, disk_template,
129
                                          fail=fail)
130

  
131

  
132
def _CreateInstanceDrbd8(nodes, fail=False):
133
  """Creates an instance using disk template 'drbd' on the given nodes.
134

  
135
  @type nodes: list of nodes
136
  @param nodes: nodes to be used by the instance
137
  @return: the created instance
138

  
139
  """
140
  assert len(nodes) > 1
141
  return _CreateInstanceByDiskTemplateRaw(
142
    ":".join(map(operator.attrgetter("primary"), nodes)),
143
    constants.DT_DRBD8, fail=fail)
144

  
145

  
146
def CreateInstanceByDiskTemplate(nodes, disk_template, fail=False):
147
  """Given a disk template, this function creates an instance using
148
     the template. It uses the required number of nodes depending on
149
     the disk template. This function is intended to be used by tests
150
     that don't care about the specifics of the instance other than
151
     that it uses the given disk template.
152

  
153
     Note: If you use this function, make sure to call
154
     'TestInstanceRemove' at the end of your tests to avoid orphaned
155
     instances hanging around and interfering with the following tests.
156

  
157
  @type nodes: list of nodes
158
  @param nodes: the list of the nodes on which the instance will be placed;
159
                it needs to have sufficiently many elements for the given
160
                disk template
161
  @type disk_template: string
162
  @param disk_template: the disk template to be used by the instance
163
  @return: the created instance
164

  
165
  """
166
  if disk_template == constants.DT_DRBD8:
167
    return _CreateInstanceDrbd8(nodes, fail=fail)
168
  elif disk_template in [constants.DT_DISKLESS, constants.DT_PLAIN,
169
                         constants.DT_FILE]:
170
    return _CreateInstanceByDiskTemplateOneNode(nodes, disk_template, fail=fail)
171
  else:
172
    # FIXME: This assumes that for all other disk templates, we only need one
173
    # node and no disk template specific parameters. This else-branch is
174
    # currently only used in cases where we expect failure. Extend it when
175
    # QA needs for these templates change.
176
    return _CreateInstanceByDiskTemplateOneNode(nodes, disk_template, fail=fail)
177

  
178

  
179 51
def _GetInstanceInfo(instance):
180 52
  """Return information about the actual state of an instance.
181 53

  
......
378 250
def TestInstanceAddWithPlainDisk(nodes, fail=False):
379 251
  """gnt-instance add -t plain"""
380 252
  if constants.DT_PLAIN in qa_config.GetEnabledDiskTemplates():
381
    instance = _CreateInstanceByDiskTemplateOneNode(nodes, constants.DT_PLAIN,
253
    instance = CreateInstanceByDiskTemplateOneNode(nodes, constants.DT_PLAIN,
382 254
                                                    fail=fail)
383 255
    if not fail:
384 256
      qa_utils.RunInstanceCheck(instance, True)
......
389 261
def TestInstanceAddWithDrbdDisk(nodes):
390 262
  """gnt-instance add -t drbd"""
391 263
  if constants.DT_DRBD8 in qa_config.GetEnabledDiskTemplates():
392
    return _CreateInstanceDrbd8(nodes)
264
    return CreateInstanceDrbd8(nodes)
393 265

  
394 266

  
395 267
@InstanceCheck(None, INST_UP, RETURN_VALUE)
......
397 269
  """gnt-instance add -t file"""
398 270
  assert len(nodes) == 1
399 271
  if constants.DT_FILE in qa_config.GetEnabledDiskTemplates():
400
    return _CreateInstanceByDiskTemplateOneNode(nodes, constants.DT_FILE)
272
    return CreateInstanceByDiskTemplateOneNode(nodes, constants.DT_FILE)
401 273

  
402 274

  
403 275
@InstanceCheck(None, INST_UP, RETURN_VALUE)
......
405 277
  """gnt-instance add -t diskless"""
406 278
  assert len(nodes) == 1
407 279
  if constants.DT_FILE in qa_config.GetEnabledDiskTemplates():
408
    return _CreateInstanceByDiskTemplateOneNode(nodes, constants.DT_DISKLESS)
280
    return CreateInstanceByDiskTemplateOneNode(nodes, constants.DT_DISKLESS)
409 281

  
410 282

  
411 283
@InstanceCheck(None, INST_DOWN, FIRST_ARG)
......
462 334
                fail=True)
463 335

  
464 336

  
465
def _ReadSsconfInstanceList():
466
  """Reads ssconf_instance_list from the master node.
467

  
468
  """
469
  master = qa_config.GetMasterNode()
470

  
471
  ssconf_path = utils.PathJoin(pathutils.DATA_DIR,
472
                               "ssconf_%s" % constants.SS_INSTANCE_LIST)
473

  
474
  cmd = ["cat", qa_utils.MakeNodePath(master, ssconf_path)]
475

  
476
  return qa_utils.GetCommandOutput(master.primary,
477
                                   utils.ShellQuoteArgs(cmd)).splitlines()
478

  
479

  
480
def _CheckSsconfInstanceList(instance):
481
  """Checks if a certain instance is in the ssconf instance list.
482

  
483
  @type instance: string
484
  @param instance: Instance name
485

  
486
  """
487
  AssertIn(qa_utils.ResolveInstanceName(instance),
488
           _ReadSsconfInstanceList())
489

  
490

  
491 337
@InstanceCheck(INST_DOWN, INST_DOWN, FIRST_ARG)
492 338
def TestInstanceRenameAndBack(rename_source, rename_target):
493 339
  """gnt-instance rename
......
496 342
  name.
497 343

  
498 344
  """
499
  _CheckSsconfInstanceList(rename_source)
345
  CheckSsconfInstanceList(rename_source)
500 346

  
501 347
  # first do a rename to a different actual name, expecting it to fail
502 348
  qa_utils.AddToEtcHosts(["meeeeh-not-exists", rename_target])
503 349
  try:
504 350
    AssertCommand(["gnt-instance", "rename", rename_source, rename_target],
505 351
                  fail=True)
506
    _CheckSsconfInstanceList(rename_source)
352
    CheckSsconfInstanceList(rename_source)
507 353
  finally:
508 354
    qa_utils.RemoveFromEtcHosts(["meeeeh-not-exists", rename_target])
509 355

  
......
526 372

  
527 373
  # and now rename instance to rename_target...
528 374
  AssertCommand(["gnt-instance", "rename", rename_source, rename_target])
529
  _CheckSsconfInstanceList(rename_target)
375
  CheckSsconfInstanceList(rename_target)
530 376
  qa_utils.RunInstanceCheck(rename_source, False)
531 377
  qa_utils.RunInstanceCheck(rename_target, False)
532 378

  
......
540 386

  
541 387
  # and back
542 388
  AssertCommand(["gnt-instance", "rename", rename_target, rename_source])
543
  _CheckSsconfInstanceList(rename_source)
389
  CheckSsconfInstanceList(rename_source)
544 390
  qa_utils.RunInstanceCheck(rename_target, False)
545 391

  
546 392
  if (rename_source != rename_target and
......
1012 858
          "--src-node=%s" % expnode.primary,
1013 859
          "--src-dir=%s/%s" % (pathutils.EXPORT_DIR, name),
1014 860
          "--node=%s" % node.primary] +
1015
         _GetGenericAddParameters(newinst, templ,
861
         GetGenericAddParameters(newinst, templ,
1016 862
                                  force_mac=constants.VALUE_GENERATE))
1017 863
  cmd.append(newinst.name)
1018 864
  AssertCommand(cmd)
b/qa/qa_instance_utils.py
1
#
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
"""QA utility functions for managing instances
23

  
24
"""
25

  
26
import operator
27

  
28
from ganeti import utils
29
from ganeti import constants
30
from ganeti import pathutils
31

  
32
import qa_config
33
import qa_utils
34

  
35
from qa_utils import AssertIn, AssertCommand
36

  
37

  
38
def RemoveInstance(instance):
39
  AssertCommand(["gnt-instance", "remove", "-f", instance.name])
40

  
41

  
42
def GetGenericAddParameters(inst, disk_template, force_mac=None):
43
  params = ["-B"]
44
  params.append("%s=%s,%s=%s" % (constants.BE_MINMEM,
45
                                 qa_config.get(constants.BE_MINMEM),
46
                                 constants.BE_MAXMEM,
47
                                 qa_config.get(constants.BE_MAXMEM)))
48

  
49
  if disk_template != constants.DT_DISKLESS:
50
    for idx, disk in enumerate(qa_config.GetDiskOptions()):
51
      size = disk.get("size")
52
      name = disk.get("name")
53
      diskparams = "%s:size=%s" % (idx, size)
54
      if name:
55
        diskparams += ",name=%s" % name
56
      params.extend(["--disk", diskparams])
57

  
58
  # Set static MAC address if configured
59
  if force_mac:
60
    nic0_mac = force_mac
61
  else:
62
    nic0_mac = inst.GetNicMacAddr(0, None)
63

  
64
  if nic0_mac:
65
    params.extend(["--net", "0:mac=%s" % nic0_mac])
66

  
67
  return params
68

  
69

  
70
def _CreateInstanceByDiskTemplateRaw(nodes_spec, disk_template, fail=False):
71
  """Creates an instance with the given disk template on the given nodes(s).
72
     Note that this function does not check if enough nodes are given for
73
     the respective disk template.
74

  
75
  @type nodes_spec: string
76
  @param nodes_spec: string specification of one node (by node name) or several
77
                     nodes according to the requirements of the disk template
78
  @type disk_template: string
79
  @param disk_template: the disk template to be used by the instance
80
  @return: the created instance
81

  
82
  """
83
  instance = qa_config.AcquireInstance()
84
  try:
85
    cmd = (["gnt-instance", "add",
86
            "--os-type=%s" % qa_config.get("os"),
87
            "--disk-template=%s" % disk_template,
88
            "--node=%s" % nodes_spec] +
89
           GetGenericAddParameters(instance, disk_template))
90
    cmd.append(instance.name)
91

  
92
    AssertCommand(cmd, fail=fail)
93

  
94
    if not fail:
95
      CheckSsconfInstanceList(instance.name)
96
      instance.SetDiskTemplate(disk_template)
97

  
98
      return instance
99
  except:
100
    instance.Release()
101
    raise
102

  
103
  # Handle the case where creation is expected to fail
104
  assert fail
105
  instance.Release()
106
  return None
107

  
108

  
109
def CreateInstanceDrbd8(nodes, fail=False):
110
  """Creates an instance using disk template 'drbd' on the given nodes.
111

  
112
  @type nodes: list of nodes
113
  @param nodes: nodes to be used by the instance
114
  @return: the created instance
115

  
116
  """
117
  assert len(nodes) > 1
118
  return _CreateInstanceByDiskTemplateRaw(
119
    ":".join(map(operator.attrgetter("primary"), nodes)),
120
    constants.DT_DRBD8, fail=fail)
121

  
122

  
123
def CreateInstanceByDiskTemplateOneNode(nodes, disk_template, fail=False):
124
  """Creates an instance using the given disk template for disk templates
125
     for which one given node is sufficient. These templates are for example:
126
     plain, diskless, file, sharedfile, blockdev, rados.
127

  
128
  @type nodes: list of nodes
129
  @param nodes: a list of nodes, whose first element is used to create the
130
                instance
131
  @type disk_template: string
132
  @param disk_template: the disk template to be used by the instance
133
  @return: the created instance
134

  
135
  """
136
  assert len(nodes) > 0
137
  return _CreateInstanceByDiskTemplateRaw(nodes[0].primary, disk_template,
138
                                          fail=fail)
139

  
140

  
141
def CreateInstanceByDiskTemplate(nodes, disk_template, fail=False):
142
  """Given a disk template, this function creates an instance using
143
     the template. It uses the required number of nodes depending on
144
     the disk template. This function is intended to be used by tests
145
     that don't care about the specifics of the instance other than
146
     that it uses the given disk template.
147

  
148
     Note: If you use this function, make sure to call
149
     'TestInstanceRemove' at the end of your tests to avoid orphaned
150
     instances hanging around and interfering with the following tests.
151

  
152
  @type nodes: list of nodes
153
  @param nodes: the list of the nodes on which the instance will be placed;
154
                it needs to have sufficiently many elements for the given
155
                disk template
156
  @type disk_template: string
157
  @param disk_template: the disk template to be used by the instance
158
  @return: the created instance
159

  
160
  """
161
  if disk_template == constants.DT_DRBD8:
162
    return CreateInstanceDrbd8(nodes, fail=fail)
163
  elif disk_template in [constants.DT_DISKLESS, constants.DT_PLAIN,
164
                         constants.DT_FILE]:
165
    return CreateInstanceByDiskTemplateOneNode(nodes, disk_template, fail=fail)
166
  else:
167
    # FIXME: This assumes that for all other disk templates, we only need one
168
    # node and no disk template specific parameters. This else-branch is
169
    # currently only used in cases where we expect failure. Extend it when
170
    # QA needs for these templates change.
171
    return CreateInstanceByDiskTemplateOneNode(nodes, disk_template, fail=fail)
172

  
173

  
174
def _ReadSsconfInstanceList():
175
  """Reads ssconf_instance_list from the master node.
176

  
177
  """
178
  master = qa_config.GetMasterNode()
179

  
180
  ssconf_path = utils.PathJoin(pathutils.DATA_DIR,
181
                               "ssconf_%s" % constants.SS_INSTANCE_LIST)
182

  
183
  cmd = ["cat", qa_utils.MakeNodePath(master, ssconf_path)]
184

  
185
  return qa_utils.GetCommandOutput(master.primary,
186
                                   utils.ShellQuoteArgs(cmd)).splitlines()
187

  
188

  
189
def CheckSsconfInstanceList(instance):
190
  """Checks if a certain instance is in the ssconf instance list.
191

  
192
  @type instance: string
193
  @param instance: Instance name
194

  
195
  """
196
  AssertIn(qa_utils.ResolveInstanceName(instance),
197
           _ReadSsconfInstanceList())

Also available in: Unified diff