DeprecationWarning fixes for pylint
[ganeti-local] / lib / client / gnt_os.py
1 #
2 #
3
4 # Copyright (C) 2006, 2007, 2010 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 """OS scripts related commands"""
22
23 # pylint: disable=W0401,W0613,W0614,C0103
24 # W0401: Wildcard import ganeti.cli
25 # W0613: Unused argument, since all functions follow the same API
26 # W0614: Unused import %s from wildcard import (since we need cli)
27 # C0103: Invalid name gnt-os
28
29 from ganeti.cli import *
30 from ganeti import constants
31 from ganeti import opcodes
32 from ganeti import utils
33
34
35 def ListOS(opts, args):
36   """List the valid OSes in the cluster.
37
38   @param opts: the command line options selected by the user
39   @type args: list
40   @param args: should be an empty list
41   @rtype: int
42   @return: the desired exit code
43
44   """
45   op = opcodes.OpOsDiagnose(output_fields=["name", "variants"], names=[])
46   result = SubmitOpCode(op, opts=opts)
47
48   if not result:
49     ToStderr("Can't get the OS list")
50     return 1
51
52   if not opts.no_headers:
53     headers = {"name": "Name"}
54   else:
55     headers = None
56
57   os_names = []
58   for (name, variants) in result:
59     os_names.extend([[n] for n in CalculateOSNames(name, variants)])
60
61   data = GenerateTable(separator=None, headers=headers, fields=["name"],
62                        data=os_names, units=None)
63
64   for line in data:
65     ToStdout(line)
66
67   return 0
68
69
70 def ShowOSInfo(opts, args):
71   """List detailed information about OSes in the cluster.
72
73   @param opts: the command line options selected by the user
74   @type args: list
75   @param args: should be an empty list
76   @rtype: int
77   @return: the desired exit code
78
79   """
80   op = opcodes.OpOsDiagnose(output_fields=["name", "valid", "variants",
81                                            "parameters", "api_versions",
82                                            "blacklisted", "hidden"],
83                             names=[])
84   result = SubmitOpCode(op, opts=opts)
85
86   if not result:
87     ToStderr("Can't get the OS list")
88     return 1
89
90   do_filter = bool(args)
91
92   for (name, valid, variants, parameters, api_versions, blk, hid) in result:
93     if do_filter:
94       if name not in args:
95         continue
96       else:
97         args.remove(name)
98     ToStdout("%s:", name)
99     ToStdout("  - valid: %s", valid)
100     ToStdout("  - hidden: %s", hid)
101     ToStdout("  - blacklisted: %s", blk)
102     if valid:
103       ToStdout("  - API versions:")
104       for version in sorted(api_versions):
105         ToStdout("    - %s", version)
106       ToStdout("  - variants:")
107       for vname in variants:
108         ToStdout("    - %s", vname)
109       ToStdout("  - parameters:")
110       for pname, pdesc in parameters:
111         ToStdout("    - %s: %s", pname, pdesc)
112     ToStdout("")
113
114   if args:
115     for name in args:
116       ToStdout("%s: ", name)
117       ToStdout("")
118
119   return 0
120
121
122 def _OsStatus(status, diagnose):
123   """Beautifier function for OS status.
124
125   @type status: boolean
126   @param status: is the OS valid
127   @type diagnose: string
128   @param diagnose: the error message for invalid OSes
129   @rtype: string
130   @return: a formatted status
131
132   """
133   if status:
134     return "valid"
135   else:
136     return "invalid - %s" % diagnose
137
138
139 def DiagnoseOS(opts, args):
140   """Analyse all OSes on this cluster.
141
142   @param opts: the command line options selected by the user
143   @type args: list
144   @param args: should be an empty list
145   @rtype: int
146   @return: the desired exit code
147
148   """
149   op = opcodes.OpOsDiagnose(output_fields=["name", "valid", "variants",
150                                            "node_status", "hidden",
151                                            "blacklisted"], names=[])
152   result = SubmitOpCode(op, opts=opts)
153
154   if not result:
155     ToStderr("Can't get the OS list")
156     return 1
157
158   has_bad = False
159
160   for os_name, _, os_variants, node_data, hid, blk in result:
161     nodes_valid = {}
162     nodes_bad = {}
163     nodes_hidden = {}
164     for node_name, node_info in node_data.iteritems():
165       nodes_hidden[node_name] = []
166       if node_info: # at least one entry in the per-node list
167         (fo_path, fo_status, fo_msg, fo_variants,
168          fo_params, fo_api) = node_info.pop(0)
169         fo_msg = "%s (path: %s)" % (_OsStatus(fo_status, fo_msg), fo_path)
170         if fo_api:
171           max_os_api = max(fo_api)
172           fo_msg += " [API versions: %s]" % utils.CommaJoin(fo_api)
173         else:
174           max_os_api = 0
175           fo_msg += " [no API versions declared]"
176
177         if max_os_api >= constants.OS_API_V15:
178           if fo_variants:
179             fo_msg += " [variants: %s]" % utils.CommaJoin(fo_variants)
180           else:
181             fo_msg += " [no variants]"
182         if max_os_api >= constants.OS_API_V20:
183           if fo_params:
184             fo_msg += (" [parameters: %s]" %
185                        utils.CommaJoin([v[0] for v in fo_params]))
186           else:
187             fo_msg += " [no parameters]"
188         if fo_status:
189           nodes_valid[node_name] = fo_msg
190         else:
191           nodes_bad[node_name] = fo_msg
192         for hpath, hstatus, hmsg, _, _, _ in node_info:
193           nodes_hidden[node_name].append("    [hidden] path: %s, status: %s" %
194                                          (hpath, _OsStatus(hstatus, hmsg)))
195       else:
196         nodes_bad[node_name] = "OS not found"
197
198     # TODO: Shouldn't the global status be calculated by the LU?
199     if nodes_valid and not nodes_bad:
200       status = "valid"
201     elif not nodes_valid and nodes_bad:
202       status = "invalid"
203       has_bad = True
204     else:
205       status = "partial valid"
206       has_bad = True
207
208     def _OutputPerNodeOSStatus(msg_map):
209       map_k = utils.NiceSort(msg_map.keys())
210       for node_name in map_k:
211         ToStdout("  Node: %s, status: %s", node_name, msg_map[node_name])
212         for msg in nodes_hidden[node_name]:
213           ToStdout(msg)
214
215     st_msg = "OS: %s [global status: %s]" % (os_name, status)
216     if hid:
217       st_msg += " [hidden]"
218     if blk:
219       st_msg += " [blacklisted]"
220     ToStdout(st_msg)
221     if os_variants:
222       ToStdout("  Variants: [%s]" % utils.CommaJoin(os_variants))
223     _OutputPerNodeOSStatus(nodes_valid)
224     _OutputPerNodeOSStatus(nodes_bad)
225     ToStdout("")
226
227   return int(has_bad)
228
229
230 def ModifyOS(opts, args):
231   """Modify OS parameters for one OS.
232
233   @param opts: the command line options selected by the user
234   @type args: list
235   @param args: should be a list with one entry
236   @rtype: int
237   @return: the desired exit code
238
239   """
240   os = args[0]
241
242   if opts.hvparams:
243     os_hvp = {os: dict(opts.hvparams)}
244   else:
245     os_hvp = None
246
247   if opts.osparams:
248     osp = {os: opts.osparams}
249   else:
250     osp = None
251
252   if opts.hidden is not None:
253     if opts.hidden:
254       ohid = [(constants.DDM_ADD, os)]
255     else:
256       ohid = [(constants.DDM_REMOVE, os)]
257   else:
258     ohid = None
259
260   if opts.blacklisted is not None:
261     if opts.blacklisted:
262       oblk = [(constants.DDM_ADD, os)]
263     else:
264       oblk = [(constants.DDM_REMOVE, os)]
265   else:
266     oblk = None
267
268   if not (os_hvp or osp or ohid or oblk):
269     ToStderr("At least one of OS parameters or hypervisor parameters"
270              " must be passed")
271     return 1
272
273   op = opcodes.OpClusterSetParams(os_hvp=os_hvp,
274                                   osparams=osp,
275                                   hidden_os=ohid,
276                                   blacklisted_os=oblk)
277   SubmitOpCode(op, opts=opts)
278
279   return 0
280
281
282 commands = {
283   "list": (
284     ListOS, ARGS_NONE, [NOHDR_OPT, PRIORITY_OPT],
285     "", "Lists all valid operating systems on the cluster"),
286   "diagnose": (
287     DiagnoseOS, ARGS_NONE, [PRIORITY_OPT],
288     "", "Diagnose all operating systems"),
289   "info": (
290     ShowOSInfo, [ArgOs()], [PRIORITY_OPT],
291     "", "Show detailed information about "
292     "operating systems"),
293   "modify": (
294     ModifyOS, ARGS_ONE_OS,
295     [HVLIST_OPT, OSPARAMS_OPT, DRY_RUN_OPT, PRIORITY_OPT,
296      HID_OS_OPT, BLK_OS_OPT],
297     "", "Modify the OS parameters"),
298   }
299
300
301 def Main():
302   return GenericMain(commands)