Statistics
| Branch: | Tag: | Revision:

root / scripts / gnt-os @ af1a81d1

History | View | Annotate | Download (7.7 kB)

1
#!/usr/bin/python
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-msg=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
import sys
30

    
31
from ganeti.cli import *
32
from ganeti import constants
33
from ganeti import opcodes
34
from ganeti import utils
35

    
36

    
37
def ListOS(opts, args):
38
  """List the valid OSes in the cluster.
39

    
40
  @param opts: the command line options selected by the user
41
  @type args: list
42
  @param args: should be an empty list
43
  @rtype: int
44
  @return: the desired exit code
45

    
46
  """
47
  op = opcodes.OpDiagnoseOS(output_fields=["name", "valid", "variants"],
48
                            names=[])
49
  result = SubmitOpCode(op, opts=opts)
50

    
51
  if not result:
52
    ToStderr("Can't get the OS list")
53
    return 1
54

    
55
  if not opts.no_headers:
56
    headers = {"name": "Name"}
57
  else:
58
    headers = None
59

    
60
  os_names = []
61
  for (name, valid, variants) in result:
62
    if valid:
63
      os_names.extend([[n] for n in CalculateOSNames(name, variants)])
64

    
65
  data = GenerateTable(separator=None, headers=headers, fields=["name"],
66
                       data=os_names, units=None)
67

    
68
  for line in data:
69
    ToStdout(line)
70

    
71
  return 0
72

    
73

    
74
def ShowOSInfo(opts, args):
75
  """List detailed information about OSes in the cluster.
76

    
77
  @param opts: the command line options selected by the user
78
  @type args: list
79
  @param args: should be an empty list
80
  @rtype: int
81
  @return: the desired exit code
82

    
83
  """
84
  op = opcodes.OpDiagnoseOS(output_fields=["name", "valid", "variants",
85
                                           "parameters", "api_versions"],
86
                            names=[])
87
  result = SubmitOpCode(op, opts=opts)
88

    
89
  if not result:
90
    ToStderr("Can't get the OS list")
91
    return 1
92

    
93
  do_filter = bool(args)
94

    
95
  for (name, valid, variants, parameters, api_versions) in result:
96
    if do_filter:
97
      if name not in args:
98
        continue
99
      else:
100
        args.remove(name)
101
    ToStdout("%s:", name)
102
    ToStdout("  - valid: %s", valid)
103
    if valid:
104
      ToStdout("  - API versions:")
105
      for version in sorted(api_versions):
106
        ToStdout("    - %s", version)
107
      ToStdout("  - variants:")
108
      for vname in variants:
109
        ToStdout("    - %s", vname)
110
      ToStdout("  - parameters:")
111
      for pname, pdesc in parameters:
112
        ToStdout("    - %s: %s", pname, pdesc)
113
    ToStdout("")
114

    
115
  if args:
116
    for name in args:
117
      ToStdout("%s: ", name)
118
      ToStdout("")
119

    
120
  return 0
121

    
122

    
123
def _OsStatus(status, diagnose):
124
  """Beautifier function for OS status.
125

    
126
  @type status: boolean
127
  @param status: is the OS valid
128
  @type diagnose: string
129
  @param diagnose: the error message for invalid OSes
130
  @rtype: string
131
  @return: a formatted status
132

    
133
  """
134
  if status:
135
    return "valid"
136
  else:
137
    return "invalid - %s" % diagnose
138

    
139

    
140
def DiagnoseOS(opts, args):
141
  """Analyse all OSes on this cluster.
142

    
143
  @param opts: the command line options selected by the user
144
  @type args: list
145
  @param args: should be an empty list
146
  @rtype: int
147
  @return: the desired exit code
148

    
149
  """
150
  op = opcodes.OpDiagnoseOS(output_fields=["name", "valid", "variants",
151
                                           "node_status"], 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 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
        if max_os_api >= constants.OS_API_V15:
177
          if fo_variants:
178
            fo_msg += " [variants: %s]" % utils.CommaJoin(fo_variants)
179
          else:
180
            fo_msg += " [no variants]"
181
        if max_os_api >= constants.OS_API_V20:
182
          if fo_params:
183
            fo_msg += (" [parameters: %s]" %
184
                       utils.CommaJoin([v[0] for v in fo_params]))
185
          else:
186
            fo_msg += " [no parameters]"
187
        if fo_status:
188
          nodes_valid[node_name] = fo_msg
189
        else:
190
          nodes_bad[node_name] = fo_msg
191
        for hpath, hstatus, hmsg, _, _, _ in node_info:
192
          nodes_hidden[node_name].append("    [hidden] path: %s, status: %s" %
193
                                         (hpath, _OsStatus(hstatus, hmsg)))
194
      else:
195
        nodes_bad[node_name] = "OS not found"
196

    
197
    if nodes_valid and not nodes_bad:
198
      status = "valid"
199
    elif not nodes_valid and nodes_bad:
200
      status = "invalid"
201
      has_bad = True
202
    else:
203
      status = "partial valid"
204
      has_bad = True
205

    
206
    def _OutputPerNodeOSStatus(msg_map):
207
      map_k = utils.NiceSort(msg_map.keys())
208
      for node_name in map_k:
209
        ToStdout("  Node: %s, status: %s", node_name, msg_map[node_name])
210
        for msg in nodes_hidden[node_name]:
211
          ToStdout(msg)
212

    
213
    ToStdout("OS: %s [global status: %s]", os_name, status)
214
    if os_variants:
215
      ToStdout("  Variants: [%s]" % utils.CommaJoin(os_variants))
216
    _OutputPerNodeOSStatus(nodes_valid)
217
    _OutputPerNodeOSStatus(nodes_bad)
218
    ToStdout("")
219

    
220
  return int(has_bad)
221

    
222

    
223
def ModifyOS(opts, args):
224
  """Modify OS parameters for one OS.
225

    
226
  @param opts: the command line options selected by the user
227
  @type args: list
228
  @param args: should be a list with one entry
229
  @rtype: int
230
  @return: the desired exit code
231

    
232
  """
233
  os = args[0]
234

    
235
  if opts.hvparams:
236
    os_hvp = {os: dict(opts.hvparams)}
237
  else:
238
    os_hvp = None
239

    
240
  if opts.osparams:
241
    osp = {os: opts.osparams}
242
  else:
243
    osp = None
244

    
245
  if not (os_hvp or osp):
246
    ToStderr("At least one of OS parameters or hypervisor parameters"
247
             " must be passed")
248
    return 1
249

    
250
  op = opcodes.OpSetClusterParams(vg_name=None,
251
                                  enabled_hypervisors=None,
252
                                  hvparams=None,
253
                                  beparams=None,
254
                                  nicparams=None,
255
                                  candidate_pool_size=None,
256
                                  os_hvp=os_hvp,
257
                                  osparams=osp)
258
  SubmitOpCode(op, opts=opts)
259

    
260
  return 0
261

    
262

    
263
commands = {
264
  'list': (
265
    ListOS, ARGS_NONE, [NOHDR_OPT], "", "Lists all valid operating systems"
266
    " on the cluster"),
267
  'diagnose': (
268
    DiagnoseOS, ARGS_NONE, [], "", "Diagnose all operating systems"),
269
  'info': (
270
    ShowOSInfo, [ArgOs()], [], "", "Show detailed information about "
271
    "operating systems"),
272
  'modify': (
273
    ModifyOS, ARGS_ONE_OS, [HVLIST_OPT, OSPARAMS_OPT, DRY_RUN_OPT], "",
274
    "Modify the OS parameters"),
275
  }
276

    
277
if __name__ == '__main__':
278
  sys.exit(GenericMain(commands))