4 # Copyright (C) 2013 Google Inc.
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.
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.
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
22 """QA utility functions for managing instances
28 from ganeti import utils
29 from ganeti import constants
30 from ganeti import pathutils
36 from qa_utils import AssertIn, AssertCommand
39 def RemoveInstance(instance):
40 AssertCommand(["gnt-instance", "remove", "-f", instance.name])
43 def GetGenericAddParameters(inst, disk_template, force_mac=None):
45 params.append("%s=%s,%s=%s" % (constants.BE_MINMEM,
46 qa_config.get(constants.BE_MINMEM),
48 qa_config.get(constants.BE_MAXMEM)))
50 if disk_template != constants.DT_DISKLESS:
51 for idx, disk in enumerate(qa_config.GetDiskOptions()):
52 size = disk.get("size")
53 name = disk.get("name")
54 diskparams = "%s:size=%s" % (idx, size)
56 diskparams += ",name=%s" % name
57 if qa_config.AreSpindlesSupported():
58 spindles = disk.get("spindles")
60 raise qa_error.Error("'spindles' is a required parameter for disks"
61 " when you enable exclusive storage tests")
62 diskparams += ",spindles=%s" % spindles
63 params.extend(["--disk", diskparams])
65 # Set static MAC address if configured
69 nic0_mac = inst.GetNicMacAddr(0, None)
72 params.extend(["--net", "0:mac=%s" % nic0_mac])
77 def _CreateInstanceByDiskTemplateRaw(nodes_spec, disk_template, fail=False):
78 """Creates an instance with the given disk template on the given nodes(s).
79 Note that this function does not check if enough nodes are given for
80 the respective disk template.
82 @type nodes_spec: string
83 @param nodes_spec: string specification of one node (by node name) or several
84 nodes according to the requirements of the disk template
85 @type disk_template: string
86 @param disk_template: the disk template to be used by the instance
87 @return: the created instance
90 instance = qa_config.AcquireInstance()
92 cmd = (["gnt-instance", "add",
93 "--os-type=%s" % qa_config.get("os"),
94 "--disk-template=%s" % disk_template,
95 "--node=%s" % nodes_spec] +
96 GetGenericAddParameters(instance, disk_template))
97 cmd.append(instance.name)
99 AssertCommand(cmd, fail=fail)
102 CheckSsconfInstanceList(instance.name)
103 instance.SetDiskTemplate(disk_template)
110 # Handle the case where creation is expected to fail
116 def CreateInstanceDrbd8(nodes, fail=False):
117 """Creates an instance using disk template 'drbd' on the given nodes.
119 @type nodes: list of nodes
120 @param nodes: nodes to be used by the instance
121 @return: the created instance
124 assert len(nodes) > 1
125 return _CreateInstanceByDiskTemplateRaw(
126 ":".join(map(operator.attrgetter("primary"), nodes)),
127 constants.DT_DRBD8, fail=fail)
130 def CreateInstanceByDiskTemplateOneNode(nodes, disk_template, fail=False):
131 """Creates an instance using the given disk template for disk templates
132 for which one given node is sufficient. These templates are for example:
133 plain, diskless, file, sharedfile, blockdev, rados.
135 @type nodes: list of nodes
136 @param nodes: a list of nodes, whose first element is used to create the
138 @type disk_template: string
139 @param disk_template: the disk template to be used by the instance
140 @return: the created instance
143 assert len(nodes) > 0
144 return _CreateInstanceByDiskTemplateRaw(nodes[0].primary, disk_template,
148 def CreateInstanceByDiskTemplate(nodes, disk_template, fail=False):
149 """Given a disk template, this function creates an instance using
150 the template. It uses the required number of nodes depending on
151 the disk template. This function is intended to be used by tests
152 that don't care about the specifics of the instance other than
153 that it uses the given disk template.
155 Note: If you use this function, make sure to call
156 'TestInstanceRemove' at the end of your tests to avoid orphaned
157 instances hanging around and interfering with the following tests.
159 @type nodes: list of nodes
160 @param nodes: the list of the nodes on which the instance will be placed;
161 it needs to have sufficiently many elements for the given
163 @type disk_template: string
164 @param disk_template: the disk template to be used by the instance
165 @return: the created instance
168 if disk_template == constants.DT_DRBD8:
169 return CreateInstanceDrbd8(nodes, fail=fail)
170 elif disk_template in [constants.DT_DISKLESS, constants.DT_PLAIN,
172 return CreateInstanceByDiskTemplateOneNode(nodes, disk_template, fail=fail)
174 # FIXME: This assumes that for all other disk templates, we only need one
175 # node and no disk template specific parameters. This else-branch is
176 # currently only used in cases where we expect failure. Extend it when
177 # QA needs for these templates change.
178 return CreateInstanceByDiskTemplateOneNode(nodes, disk_template, fail=fail)
181 def _ReadSsconfInstanceList():
182 """Reads ssconf_instance_list from the master node.
185 master = qa_config.GetMasterNode()
187 ssconf_path = utils.PathJoin(pathutils.DATA_DIR,
188 "ssconf_%s" % constants.SS_INSTANCE_LIST)
190 cmd = ["cat", qa_utils.MakeNodePath(master, ssconf_path)]
192 return qa_utils.GetCommandOutput(master.primary,
193 utils.ShellQuoteArgs(cmd)).splitlines()
196 def CheckSsconfInstanceList(instance):
197 """Checks if a certain instance is in the ssconf instance list.
199 @type instance: string
200 @param instance: Instance name
203 AssertIn(qa_utils.ResolveInstanceName(instance),
204 _ReadSsconfInstanceList())