Statistics
| Branch: | Tag: | Revision:

root / qa / qa_group.py @ cbaf1652

History | View | Annotate | Download (9.2 kB)

1
#
2
#
3

    
4
# Copyright (C) 2010, 2011, 2012 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 tests for node groups.
23

24
"""
25

    
26
from ganeti import constants
27
from ganeti import query
28
from ganeti import utils
29

    
30
import qa_config
31
import qa_utils
32

    
33
from qa_utils import AssertCommand, AssertEqual, GetCommandOutput
34

    
35

    
36
def GetDefaultGroup():
37
  """Returns the default node group.
38

39
  """
40
  groups = qa_config.get("groups", {})
41
  return groups.get("group-with-nodes", constants.INITIAL_NODE_GROUP_NAME)
42

    
43

    
44
def TestGroupAddRemoveRename():
45
  """gnt-group add/remove/rename"""
46
  existing_group_with_nodes = GetDefaultGroup()
47

    
48
  (group1, group2, group3) = qa_utils.GetNonexistentGroups(3)
49

    
50
  AssertCommand(["gnt-group", "add", group1])
51
  AssertCommand(["gnt-group", "add", group2])
52
  AssertCommand(["gnt-group", "add", group2], fail=True)
53
  AssertCommand(["gnt-group", "add", existing_group_with_nodes], fail=True)
54

    
55
  AssertCommand(["gnt-group", "rename", group1, group2], fail=True)
56
  AssertCommand(["gnt-group", "rename", group1, group3])
57

    
58
  try:
59
    AssertCommand(["gnt-group", "rename", existing_group_with_nodes, group1])
60

    
61
    AssertCommand(["gnt-group", "remove", group2])
62
    AssertCommand(["gnt-group", "remove", group3])
63
    AssertCommand(["gnt-group", "remove", group1], fail=True)
64
  finally:
65
    # Try to ensure idempotency re groups that already existed.
66
    AssertCommand(["gnt-group", "rename", group1, existing_group_with_nodes])
67

    
68

    
69
def TestGroupAddWithOptions():
70
  """gnt-group add with options"""
71
  (group1, ) = qa_utils.GetNonexistentGroups(1)
72

    
73
  AssertCommand(["gnt-group", "add", "--alloc-policy", "notvalid", group1],
74
                fail=True)
75

    
76
  AssertCommand(["gnt-group", "add", "--alloc-policy", "last_resort",
77
                 "--node-parameters", "oob_program=/bin/true", group1])
78

    
79
  AssertCommand(["gnt-group", "remove", group1])
80

    
81

    
82
def _GetGroupIPolicy(groupname):
83
  """Return the run-time values of the cluster-level instance policy.
84

85
  @type groupname: string
86
  @param groupname: node group name
87
  @rtype: tuple
88
  @return: (policy, specs), where:
89
      - policy is a dictionary of the policy values, instance specs excluded
90
      - specs is dict of dict, specs[par][key] is a spec value, where key is
91
        "min" or "max"
92

93
  """
94
  info = qa_utils.GetObjectInfo(["gnt-group", "info", groupname])
95
  assert len(info) == 1
96
  policy = info[0]["Instance policy"]
97

    
98
  (ret_policy, ret_specs) = qa_utils.ParseIPolicy(policy)
99

    
100
  # Sanity checks
101
  assert len(ret_specs) > 0
102
  good = all("min" in d and "max" in d
103
             for d in ret_specs.values())
104
  assert good, "Missing item in specs: %s" % ret_specs
105
  assert len(ret_policy) > 0
106
  return (ret_policy, ret_specs)
107

    
108

    
109
def _TestGroupSetISpecs(groupname, new_specs, fail=False, old_values=None):
110
  """Change instance specs on a group.
111

112
  @type groupname: string
113
  @param groupname: group name
114
  @type new_specs: dict of dict
115
  @param new_specs: new_specs[par][key], where key is "min", "max", "std". It
116
      can be an empty dictionary.
117
  @type fail: bool
118
  @param fail: if the change is expected to fail
119
  @type old_values: tuple
120
  @param old_values: (old_policy, old_specs), as returned by
121
     L{_GetGroupIPolicy}
122
  @return: same as L{_GetGroupIPolicy}
123

124
  """
125
  build_cmd = lambda opts: ["gnt-group", "modify"] + opts + [groupname]
126
  get_policy = lambda: _GetGroupIPolicy(groupname)
127
  return qa_utils.TestSetISpecs(new_specs, get_policy_fn=get_policy,
128
                                build_cmd_fn=build_cmd, fail=fail,
129
                                old_values=old_values)
130

    
131

    
132
def _TestGroupModifyISpecs(groupname):
133
  # This test is built on the assumption that the default ipolicy holds for
134
  # the node group under test
135
  old_values = _GetGroupIPolicy(groupname)
136
  mod_values = _TestGroupSetISpecs(groupname,
137
                                   dict((p, {"min": 4, "max": 4})
138
                                        for p in constants.ISPECS_PARAMETERS),
139
                                   old_values=old_values)
140
  for par in constants.ISPECS_PARAMETERS:
141
    # First make sure that the test works with good values
142
    mod_values = _TestGroupSetISpecs(groupname, {par: {"min": 8, "max": 8}},
143
                                     old_values=mod_values)
144
    _TestGroupSetISpecs(groupname, {par: {"min": 8, "max": 4}},
145
                        fail=True, old_values=mod_values)
146
  AssertCommand(["gnt-group", "modify", "--ipolicy-bounds-specs", "default",
147
                 groupname])
148
  AssertEqual(_GetGroupIPolicy(groupname), old_values)
149

    
150
  # Get the ipolicy command (from the cluster config)
151
  mnode = qa_config.GetMasterNode()
152
  addcmd = GetCommandOutput(mnode.primary, utils.ShellQuoteArgs([
153
    "gnt-group", "show-ispecs-cmd", "--include-defaults", groupname,
154
    ]))
155
  modcmd = ["gnt-group", "modify"]
156
  opts = addcmd.split()
157
  assert opts[0:2] == ["gnt-group", "add"]
158
  for k in range(2, len(opts) - 1):
159
    if opts[k].startswith("--ipolicy-"):
160
      assert k + 2 <= len(opts)
161
      modcmd.extend(opts[k:k + 2])
162
  modcmd.append(groupname)
163
  # Apply the ipolicy to the group and verify the result
164
  AssertCommand(modcmd)
165
  new_addcmd = GetCommandOutput(mnode.primary, utils.ShellQuoteArgs([
166
    "gnt-group", "show-ispecs-cmd", groupname,
167
    ]))
168
  AssertEqual(addcmd, new_addcmd)
169

    
170

    
171
def _TestGroupModifyIPolicy(groupname):
172
  _TestGroupModifyISpecs(groupname)
173

    
174
  # We assume that the default ipolicy holds
175
  (old_policy, old_specs) = _GetGroupIPolicy(groupname)
176
  for (par, setval, iname, expval) in [
177
    ("vcpu-ratio", 1.5, None, 1.5),
178
    ("spindle-ratio", 1.5, None, 1.5),
179
    ("disk-templates", constants.DT_PLAIN,
180
     "enabled disk templates", constants.DT_PLAIN)
181
    ]:
182
    if not iname:
183
      iname = par
184
    build_cmdline = lambda val: ["gnt-group", "modify", "--ipolicy-" + par,
185
                                 str(val), groupname]
186

    
187
    AssertCommand(build_cmdline(setval))
188
    (new_policy, new_specs) = _GetGroupIPolicy(groupname)
189
    AssertEqual(new_specs, old_specs)
190
    for (p, val) in new_policy.items():
191
      if p == iname:
192
        AssertEqual(val, expval)
193
      else:
194
        AssertEqual(val, old_policy[p])
195

    
196
    AssertCommand(build_cmdline("default"))
197
    (new_policy, new_specs) = _GetGroupIPolicy(groupname)
198
    AssertEqual(new_specs, old_specs)
199
    AssertEqual(new_policy, old_policy)
200

    
201

    
202
def TestGroupModify():
203
  """gnt-group modify"""
204
  (group1, ) = qa_utils.GetNonexistentGroups(1)
205

    
206
  AssertCommand(["gnt-group", "add", group1])
207

    
208
  try:
209
    _TestGroupModifyIPolicy(group1)
210
    AssertCommand(["gnt-group", "modify", "--alloc-policy", "unallocable",
211
                   "--node-parameters", "oob_program=/bin/false", group1])
212
    AssertCommand(["gnt-group", "modify",
213
                   "--alloc-policy", "notvalid", group1], fail=True)
214
    AssertCommand(["gnt-group", "modify",
215
                   "--node-parameters", "spindle_count=10", group1])
216
    if qa_config.TestEnabled("htools"):
217
      AssertCommand(["hbal", "-L", "-G", group1])
218
    AssertCommand(["gnt-group", "modify",
219
                   "--node-parameters", "spindle_count=default", group1])
220
  finally:
221
    AssertCommand(["gnt-group", "remove", group1])
222

    
223

    
224
def TestGroupList():
225
  """gnt-group list"""
226
  qa_utils.GenericQueryTest("gnt-group", query.GROUP_FIELDS.keys())
227

    
228

    
229
def TestGroupListFields():
230
  """gnt-group list-fields"""
231
  qa_utils.GenericQueryFieldsTest("gnt-group", query.GROUP_FIELDS.keys())
232

    
233

    
234
def TestAssignNodesIncludingSplit(orig_group, node1, node2):
235
  """gnt-group assign-nodes --force
236

237
  Expects node1 and node2 to be primary and secondary for a common instance.
238

239
  """
240
  assert node1 != node2
241

    
242
  (other_group, ) = qa_utils.GetNonexistentGroups(1)
243

    
244
  master_node = qa_config.GetMasterNode().primary
245

    
246
  def AssertInGroup(group, nodes):
247
    real_output = GetCommandOutput(master_node,
248
                                   "gnt-node list --no-headers -o group " +
249
                                   utils.ShellQuoteArgs(nodes))
250
    AssertEqual(real_output.splitlines(), [group] * len(nodes))
251

    
252
  AssertInGroup(orig_group, [node1, node2])
253
  AssertCommand(["gnt-group", "add", other_group])
254

    
255
  try:
256
    AssertCommand(["gnt-group", "assign-nodes", other_group, node1, node2])
257
    AssertInGroup(other_group, [node1, node2])
258

    
259
    # This should fail because moving node1 to orig_group would leave their
260
    # common instance split between orig_group and other_group.
261
    AssertCommand(["gnt-group", "assign-nodes", orig_group, node1], fail=True)
262
    AssertInGroup(other_group, [node1, node2])
263

    
264
    AssertCommand(["gnt-group", "assign-nodes", "--force", orig_group, node1])
265
    AssertInGroup(orig_group, [node1])
266
    AssertInGroup(other_group, [node2])
267

    
268
    AssertCommand(["gnt-group", "assign-nodes", orig_group, node2])
269
    AssertInGroup(orig_group, [node1, node2])
270
  finally:
271
    AssertCommand(["gnt-group", "remove", other_group])