gnt_group.py 10.2 KB
Newer Older
1
2
3
#
#

4
# Copyright (C) 2010, 2011, 2012 Google Inc.
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301, USA.

"""Node group related commands"""

23
# pylint: disable=W0401,W0614
24
25
26
27
# W0401: Wildcard import ganeti.cli
# W0614: Unused import %s from wildcard import (since we need cli)

from ganeti.cli import *
28
from ganeti import constants
29
from ganeti import objects
30
from ganeti import opcodes
31
from ganeti import utils
32
33
34


#: default list of fields for L{ListGroups}
35
_LIST_DEF_FIELDS = ["name", "node_cnt", "pinst_cnt", "alloc_policy", "ndparams"]
36
37


38
39
40
_ENV_OVERRIDE = frozenset(["list"])


41
42
43
44
45
46
47
48
49
50
def AddGroup(opts, args):
  """Add a node group to the cluster.

  @param opts: the command line options selected by the user
  @type args: list
  @param args: a list of length 1 with the name of the group to create
  @rtype: int
  @return: the desired exit code

  """
51
52
53
54
55
56
57
58
  ipolicy = \
    objects.CreateIPolicyFromOpts(ispecs_mem_size=opts.ispecs_mem_size,
                                  ispecs_cpu_count=opts.ispecs_cpu_count,
                                  ispecs_disk_count=opts.ispecs_disk_count,
                                  ispecs_disk_size=opts.ispecs_disk_size,
                                  ispecs_nic_count=opts.ispecs_nic_count,
                                  group_ipolicy=True)

59
  (group_name,) = args
60
  diskparams = dict(opts.diskparams)
61
62
63
64
65
66
67

  if opts.disk_state:
    disk_state = utils.FlatToDict(opts.disk_state)
  else:
    disk_state = {}
  hv_state = dict(opts.hv_state)

Iustin Pop's avatar
Iustin Pop committed
68
  op = opcodes.OpGroupAdd(group_name=group_name, ndparams=opts.ndparams,
69
                          alloc_policy=opts.alloc_policy,
70
71
72
                          diskparams=diskparams, ipolicy=ipolicy,
                          hv_state=hv_state,
                          disk_state=disk_state)
73
74
75
  SubmitOpCode(op, opts=opts)


76
77
78
79
80
81
82
83
84
85
86
87
88
def AssignNodes(opts, args):
  """Assign nodes to a group.

  @param opts: the command line options selected by the user
  @type args: list
  @param args: args[0]: group to assign nodes to; args[1:]: nodes to assign
  @rtype: int
  @return: the desired exit code

  """
  group_name = args[0]
  node_names = args[1:]

89
  op = opcodes.OpGroupAssignNodes(group_name=group_name, nodes=node_names,
90
91
92
93
                                  force=opts.force)
  SubmitOpCode(op, opts=opts)


94
95
96
97
98
99
100
101
102
103
104
105
106
107
def _FmtDict(data):
  """Format dict data into command-line format.

  @param data: The input dict to be formatted
  @return: The formatted dict

  """
  if not data:
    return "(empty)"

  return utils.CommaJoin(["%s=%s" % (key, value)
                          for key, value in data.items()])


108
109
110
111
112
113
114
115
116
117
118
def ListGroups(opts, args):
  """List node groups and their properties.

  @param opts: the command line options selected by the user
  @type args: list
  @param args: groups to list, or empty for all
  @rtype: int
  @return: the desired exit code

  """
  desired_fields = ParseFields(opts.output, _LIST_DEF_FIELDS)
119
120
121
122
123
  fmtoverride = {
    "node_list": (",".join, False),
    "pinst_list": (",".join, False),
    "ndparams": (_FmtDict, False),
    }
124

125
126
  return GenericList(constants.QR_GROUP, desired_fields, args, None,
                     opts.separator, not opts.no_headers,
127
128
                     format_override=fmtoverride, verbose=opts.verbose,
                     force_filter=opts.force_filter)
129
130


131
132
def ListGroupFields(opts, args):
  """List node fields.
133

134
135
136
137
138
  @param opts: the command line options selected by the user
  @type args: list
  @param args: fields to list, or empty for all
  @rtype: int
  @return: the desired exit code
139

140
141
142
  """
  return GenericListFields(constants.QR_GROUP, args, opts.separator,
                           not opts.no_headers)
143
144


145
146
147
def SetGroupParams(opts, args):
  """Modifies a node group's parameters.

Stephen Shirley's avatar
Stephen Shirley committed
148
  @param opts: the command line options selected by the user
149
150
151
152
153
154
155
  @type args: list
  @param args: should contain only one element, the node group name

  @rtype: int
  @return: the desired exit code

  """
156
157
158
159
160
  allmods = [opts.ndparams, opts.alloc_policy, opts.diskparams, opts.hv_state,
             opts.disk_state, opts.ispecs_mem_size, opts.ispecs_cpu_count,
             opts.ispecs_disk_count, opts.ispecs_disk_size,
             opts.ispecs_nic_count, opts.diskparams]
  if allmods.count(None) == len(allmods):
161
162
163
    ToStderr("Please give at least one of the parameters.")
    return 1

164
165
166
167
168
169
170
  if opts.disk_state:
    disk_state = utils.FlatToDict(opts.disk_state)
  else:
    disk_state = {}

  hv_state = dict(opts.hv_state)

171
  diskparams = dict(opts.diskparams)
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192

  # set the default values
  to_ipolicy = [
    opts.ispecs_mem_size,
    opts.ispecs_cpu_count,
    opts.ispecs_disk_count,
    opts.ispecs_disk_size,
    opts.ispecs_nic_count,
    ]
  for ispec in to_ipolicy:
    for param in ispec:
      if isinstance(ispec[param], basestring):
        if ispec[param].lower() == "default":
          ispec[param] = constants.VALUE_DEFAULT
  # create ipolicy object
  ipolicy = objects.CreateIPolicyFromOpts(\
    ispecs_mem_size=opts.ispecs_mem_size,
    ispecs_cpu_count=opts.ispecs_cpu_count,
    ispecs_disk_count=opts.ispecs_disk_count,
    ispecs_disk_size=opts.ispecs_disk_size,
    ispecs_nic_count=opts.ispecs_nic_count,
193
    ispecs_disk_templates=opts.ispecs_disk_templates,
194
195
196
    group_ipolicy=True,
    allowed_values=[constants.VALUE_DEFAULT])

Michael Hanselmann's avatar
Michael Hanselmann committed
197
198
  op = opcodes.OpGroupSetParams(group_name=args[0],
                                ndparams=opts.ndparams,
199
                                alloc_policy=opts.alloc_policy,
200
201
                                hv_state=hv_state,
                                disk_state=disk_state,
202
203
204
                                diskparams=diskparams,
                                ipolicy=ipolicy)

205
206
207
208
209
210
211
212
213
214
  result = SubmitOrSend(op, opts)

  if result:
    ToStdout("Modified node group %s", args[0])
    for param, data in result:
      ToStdout(" - %-5s -> %s", param, data)

  return 0


215
216
217
218
219
220
221
222
223
224
225
def RemoveGroup(opts, args):
  """Remove a node group from the cluster.

  @param opts: the command line options selected by the user
  @type args: list
  @param args: a list of length 1 with the name of the group to remove
  @rtype: int
  @return: the desired exit code

  """
  (group_name,) = args
226
  op = opcodes.OpGroupRemove(group_name=group_name)
227
228
229
230
231
232
233
234
235
236
237
238
239
  SubmitOpCode(op, opts=opts)


def RenameGroup(opts, args):
  """Rename a node group.

  @param opts: the command line options selected by the user
  @type args: list
  @param args: a list of length 2, [old_name, new_name]
  @rtype: int
  @return: the desired exit code

  """
240
241
  group_name, new_name = args
  op = opcodes.OpGroupRename(group_name=group_name, new_name=new_name)
242
243
244
  SubmitOpCode(op, opts=opts)


245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
def EvacuateGroup(opts, args):
  """Evacuate a node group.

  """
  (group_name, ) = args

  cl = GetClient()

  op = opcodes.OpGroupEvacuate(group_name=group_name,
                               iallocator=opts.iallocator,
                               target_groups=opts.to,
                               early_release=opts.early_release)
  result = SubmitOpCode(op, cl=cl, opts=opts)

  # Keep track of submitted jobs
  jex = JobExecutor(cl=cl, opts=opts)

  for (status, job_id) in result[constants.JOB_IDS_KEY]:
    jex.AddJobId(None, status, job_id)

  results = jex.GetResults()
  bad_cnt = len([row for row in results if not row[0]])
  if bad_cnt == 0:
    ToStdout("All instances evacuated successfully.")
    rcode = constants.EXIT_SUCCESS
  else:
    ToStdout("There were %s errors during the evacuation.", bad_cnt)
    rcode = constants.EXIT_FAILURE

  return rcode

276
commands = {
277
  "add": (
278
    AddGroup, ARGS_ONE_GROUP,
279
280
    [DRY_RUN_OPT, ALLOC_POLICY_OPT, NODE_PARAMS_OPT, DISK_PARAMS_OPT,
     HV_STATE_OPT, DISK_STATE_OPT] + INSTANCE_POLICY_OPTS,
281
    "<group_name>", "Add a new node group to the cluster"),
282
283
284
  "assign-nodes": (
    AssignNodes, ARGS_ONE_GROUP + ARGS_MANY_NODES, [DRY_RUN_OPT, FORCE_OPT],
    "<group_name> <node>...", "Assign nodes to a group"),
285
286
  "list": (
    ListGroups, ARGS_MANY_GROUPS,
287
    [NOHDR_OPT, SEP_OPT, FIELDS_OPT, VERBOSE_OPT, FORCE_FILTER_OPT],
288
    "[<group_name>...]",
289
290
291
292
293
294
    "Lists the node groups in the cluster. The available fields can be shown"
    " using the \"list-fields\" command (see the man page for details)."
    " The default list is (in order): %s." % utils.CommaJoin(_LIST_DEF_FIELDS)),
  "list-fields": (
    ListGroupFields, [ArgUnknown()], [NOHDR_OPT, SEP_OPT], "[fields...]",
    "Lists all available fields for node groups"),
295
296
  "modify": (
    SetGroupParams, ARGS_ONE_GROUP,
297
    [DRY_RUN_OPT, SUBMIT_OPT, ALLOC_POLICY_OPT, NODE_PARAMS_OPT, HV_STATE_OPT,
298
     DISK_STATE_OPT, DISK_PARAMS_OPT] + INSTANCE_POLICY_OPTS,
299
    "<group_name>", "Alters the parameters of a node group"),
300
301
  "remove": (
    RemoveGroup, ARGS_ONE_GROUP, [DRY_RUN_OPT],
302
    "[--dry-run] <group-name>",
303
304
305
    "Remove an (empty) node group from the cluster"),
  "rename": (
    RenameGroup, [ArgGroup(min=2, max=2)], [DRY_RUN_OPT],
306
    "[--dry-run] <group-name> <new-name>", "Rename a node group"),
307
308
309
  "evacuate": (
    EvacuateGroup, [ArgGroup(min=1, max=1)],
    [TO_GROUP_OPT, IALLOCATOR_OPT, EARLY_RELEASE_OPT],
310
311
    "[-I <iallocator>] [--to <group>]",
    "Evacuate all instances within a group"),
312
313
314
315
316
317
318
319
320
321
322
323
  "list-tags": (
    ListTags, ARGS_ONE_GROUP, [PRIORITY_OPT],
    "<instance_name>", "List the tags of the given instance"),
  "add-tags": (
    AddTags, [ArgGroup(min=1, max=1), ArgUnknown()],
    [TAG_SRC_OPT, PRIORITY_OPT],
    "<instance_name> tag...", "Add tags to the given instance"),
  "remove-tags": (
    RemoveTags, [ArgGroup(min=1, max=1), ArgUnknown()],
    [TAG_SRC_OPT, PRIORITY_OPT],
    "<instance_name> tag...", "Remove tags from given instance"),
  }
324
325
326


def Main():
327
  return GenericMain(commands,
328
329
                     override={"tag_type": constants.TAG_NODEGROUP},
                     env_override=_ENV_OVERRIDE)