Merge commit 'v2.5.1' into devel-2.5
[ganeti-local] / lib / client / gnt_group.py
1 #
2 #
3
4 # Copyright (C) 2010, 2011 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 """Node group related commands"""
22
23 # pylint: disable=W0401,W0614
24 # W0401: Wildcard import ganeti.cli
25 # W0614: Unused import %s from wildcard import (since we need cli)
26
27 from ganeti.cli import *
28 from ganeti import constants
29 from ganeti import opcodes
30 from ganeti import utils
31
32
33 #: default list of fields for L{ListGroups}
34 _LIST_DEF_FIELDS = ["name", "node_cnt", "pinst_cnt", "alloc_policy", "ndparams"]
35
36
37 def AddGroup(opts, args):
38   """Add a node group to the cluster.
39
40   @param opts: the command line options selected by the user
41   @type args: list
42   @param args: a list of length 1 with the name of the group to create
43   @rtype: int
44   @return: the desired exit code
45
46   """
47   (group_name,) = args
48   op = opcodes.OpGroupAdd(group_name=group_name, ndparams=opts.ndparams,
49                           alloc_policy=opts.alloc_policy)
50   SubmitOpCode(op, opts=opts)
51
52
53 def AssignNodes(opts, args):
54   """Assign nodes to a group.
55
56   @param opts: the command line options selected by the user
57   @type args: list
58   @param args: args[0]: group to assign nodes to; args[1:]: nodes to assign
59   @rtype: int
60   @return: the desired exit code
61
62   """
63   group_name = args[0]
64   node_names = args[1:]
65
66   op = opcodes.OpGroupAssignNodes(group_name=group_name, nodes=node_names,
67                                   force=opts.force)
68   SubmitOpCode(op, opts=opts)
69
70
71 def _FmtDict(data):
72   """Format dict data into command-line format.
73
74   @param data: The input dict to be formatted
75   @return: The formatted dict
76
77   """
78   if not data:
79     return "(empty)"
80
81   return utils.CommaJoin(["%s=%s" % (key, value)
82                           for key, value in data.items()])
83
84
85 def ListGroups(opts, args):
86   """List node groups and their properties.
87
88   @param opts: the command line options selected by the user
89   @type args: list
90   @param args: groups to list, or empty for all
91   @rtype: int
92   @return: the desired exit code
93
94   """
95   desired_fields = ParseFields(opts.output, _LIST_DEF_FIELDS)
96   fmtoverride = {
97     "node_list": (",".join, False),
98     "pinst_list": (",".join, False),
99     "ndparams": (_FmtDict, False),
100     }
101
102   return GenericList(constants.QR_GROUP, desired_fields, args, None,
103                      opts.separator, not opts.no_headers,
104                      format_override=fmtoverride, verbose=opts.verbose,
105                      force_filter=opts.force_filter)
106
107
108 def ListGroupFields(opts, args):
109   """List node fields.
110
111   @param opts: the command line options selected by the user
112   @type args: list
113   @param args: fields to list, or empty for all
114   @rtype: int
115   @return: the desired exit code
116
117   """
118   return GenericListFields(constants.QR_GROUP, args, opts.separator,
119                            not opts.no_headers)
120
121
122 def SetGroupParams(opts, args):
123   """Modifies a node group's parameters.
124
125   @param opts: the command line options selected by the user
126   @type args: list
127   @param args: should contain only one element, the node group name
128
129   @rtype: int
130   @return: the desired exit code
131
132   """
133   if opts.ndparams is None and opts.alloc_policy is None:
134     ToStderr("Please give at least one of the parameters.")
135     return 1
136
137   op = opcodes.OpGroupSetParams(group_name=args[0],
138                                 ndparams=opts.ndparams,
139                                 alloc_policy=opts.alloc_policy)
140   result = SubmitOrSend(op, opts)
141
142   if result:
143     ToStdout("Modified node group %s", args[0])
144     for param, data in result:
145       ToStdout(" - %-5s -> %s", param, data)
146
147   return 0
148
149
150 def RemoveGroup(opts, args):
151   """Remove a node group from the cluster.
152
153   @param opts: the command line options selected by the user
154   @type args: list
155   @param args: a list of length 1 with the name of the group to remove
156   @rtype: int
157   @return: the desired exit code
158
159   """
160   (group_name,) = args
161   op = opcodes.OpGroupRemove(group_name=group_name)
162   SubmitOpCode(op, opts=opts)
163
164
165 def RenameGroup(opts, args):
166   """Rename a node group.
167
168   @param opts: the command line options selected by the user
169   @type args: list
170   @param args: a list of length 2, [old_name, new_name]
171   @rtype: int
172   @return: the desired exit code
173
174   """
175   group_name, new_name = args
176   op = opcodes.OpGroupRename(group_name=group_name, new_name=new_name)
177   SubmitOpCode(op, opts=opts)
178
179
180 def EvacuateGroup(opts, args):
181   """Evacuate a node group.
182
183   """
184   (group_name, ) = args
185
186   cl = GetClient()
187
188   op = opcodes.OpGroupEvacuate(group_name=group_name,
189                                iallocator=opts.iallocator,
190                                target_groups=opts.to,
191                                early_release=opts.early_release)
192   result = SubmitOpCode(op, cl=cl, opts=opts)
193
194   # Keep track of submitted jobs
195   jex = JobExecutor(cl=cl, opts=opts)
196
197   for (status, job_id) in result[constants.JOB_IDS_KEY]:
198     jex.AddJobId(None, status, job_id)
199
200   results = jex.GetResults()
201   bad_cnt = len([row for row in results if not row[0]])
202   if bad_cnt == 0:
203     ToStdout("All instances evacuated successfully.")
204     rcode = constants.EXIT_SUCCESS
205   else:
206     ToStdout("There were %s errors during the evacuation.", bad_cnt)
207     rcode = constants.EXIT_FAILURE
208
209   return rcode
210
211
212 commands = {
213   "add": (
214     AddGroup, ARGS_ONE_GROUP, [DRY_RUN_OPT, ALLOC_POLICY_OPT, NODE_PARAMS_OPT],
215     "<group_name>", "Add a new node group to the cluster"),
216   "assign-nodes": (
217     AssignNodes, ARGS_ONE_GROUP + ARGS_MANY_NODES, [DRY_RUN_OPT, FORCE_OPT],
218     "<group_name> <node>...", "Assign nodes to a group"),
219   "list": (
220     ListGroups, ARGS_MANY_GROUPS,
221     [NOHDR_OPT, SEP_OPT, FIELDS_OPT, VERBOSE_OPT, FORCE_FILTER_OPT],
222     "[<group_name>...]",
223     "Lists the node groups in the cluster. The available fields can be shown"
224     " using the \"list-fields\" command (see the man page for details)."
225     " The default list is (in order): %s." % utils.CommaJoin(_LIST_DEF_FIELDS)),
226   "list-fields": (
227     ListGroupFields, [ArgUnknown()], [NOHDR_OPT, SEP_OPT], "[fields...]",
228     "Lists all available fields for node groups"),
229   "modify": (
230     SetGroupParams, ARGS_ONE_GROUP,
231     [DRY_RUN_OPT, SUBMIT_OPT, ALLOC_POLICY_OPT, NODE_PARAMS_OPT],
232     "<group_name>", "Alters the parameters of a node group"),
233   "remove": (
234     RemoveGroup, ARGS_ONE_GROUP, [DRY_RUN_OPT],
235     "[--dry-run] <group-name>",
236     "Remove an (empty) node group from the cluster"),
237   "rename": (
238     RenameGroup, [ArgGroup(min=2, max=2)], [DRY_RUN_OPT],
239     "[--dry-run] <group-name> <new-name>", "Rename a node group"),
240   "evacuate": (
241     EvacuateGroup, [ArgGroup(min=1, max=1)],
242     [TO_GROUP_OPT, IALLOCATOR_OPT, EARLY_RELEASE_OPT],
243     "[-I <iallocator>] [--to <group>]",
244     "Evacuate all instances within a group"),
245   "list-tags": (
246     ListTags, ARGS_ONE_GROUP, [],
247     "<group_name>", "List the tags of the given group"),
248   "add-tags": (
249     AddTags, [ArgGroup(min=1, max=1), ArgUnknown()],
250     [TAG_SRC_OPT, PRIORITY_OPT, SUBMIT_OPT],
251     "<group_name> tag...", "Add tags to the given group"),
252   "remove-tags": (
253     RemoveTags, [ArgGroup(min=1, max=1), ArgUnknown()],
254     [TAG_SRC_OPT, PRIORITY_OPT, SUBMIT_OPT],
255     "<group_name> tag...", "Remove tags from the given group"),
256   }
257
258
259 def Main():
260   return GenericMain(commands,
261                      override={"tag_type": constants.TAG_NODEGROUP})