gnt-os 5.57 KB
Newer Older
Iustin Pop's avatar
Iustin Pop committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
#!/usr/bin/python
#

# Copyright (C) 2006, 2007 Google Inc.
#
# 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.

Iustin Pop's avatar
Iustin Pop committed
21
"""OS scripts related commands"""
Iustin Pop's avatar
Iustin Pop committed
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)
Iustin Pop's avatar
Iustin Pop committed
27
# C0103: Invalid name gnt-os
28

Iustin Pop's avatar
Iustin Pop committed
29 30 31 32 33
import sys

from ganeti.cli import *
from ganeti import opcodes
from ganeti import utils
Guido Trotter's avatar
Guido Trotter committed
34

35

Iustin Pop's avatar
Iustin Pop committed
36
def ListOS(opts, args):
37 38 39 40 41 42 43
  """List the valid OSes in the cluster.

  @param opts: the command line options selected by the user
  @type args: list
  @param args: should be an empty list
  @rtype: int
  @return: the desired exit code
Iustin Pop's avatar
Iustin Pop committed
44 45

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

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

  if not opts.no_headers:
55 56 57
    headers = {"name": "Name"}
  else:
    headers = None
Iustin Pop's avatar
Iustin Pop committed
58

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

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

  for line in data:
68
    ToStdout(line)
Iustin Pop's avatar
Iustin Pop committed
69 70 71

  return 0

Guido Trotter's avatar
Guido Trotter committed
72

73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
def _OsStatus(status, diagnose):
  """Beautifier function for OS status.

  @type status: boolean
  @param status: is the OS valid
  @type diagnose: string
  @param diagnose: the error message for invalid OSes
  @rtype: string
  @return: a formatted status

  """
  if status:
    return "valid"
  else:
    return "invalid - %s" % diagnose

Iustin Pop's avatar
Iustin Pop committed
89 90 91
def DiagnoseOS(opts, args):
  """Analyse all OSes on this cluster.

92 93 94 95 96 97
  @param opts: the command line options selected by the user
  @type args: list
  @param args: should be an empty list
  @rtype: int
  @return: the desired exit code

Iustin Pop's avatar
Iustin Pop committed
98
  """
99 100
  op = opcodes.OpDiagnoseOS(output_fields=["name", "valid", "variants",
                                           "node_status"], names=[])
101
  result = SubmitOpCode(op, opts=opts)
Iustin Pop's avatar
Iustin Pop committed
102 103

  if not result:
104
    ToStderr("Can't get the OS list")
Iustin Pop's avatar
Iustin Pop committed
105 106
    return 1

107 108
  has_bad = False

Iustin Pop's avatar
Iustin Pop committed
109
  for os_name, _, os_variants, node_data in result:
Guido Trotter's avatar
Guido Trotter committed
110
    nodes_valid = {}
Iustin Pop's avatar
Iustin Pop committed
111
    nodes_bad = {}
112 113 114 115
    nodes_hidden = {}
    for node_name, node_info in node_data.iteritems():
      nodes_hidden[node_name] = []
      if node_info: # at least one entry in the per-node list
116 117 118 119 120 121
        (first_os_path, first_os_status, first_os_msg,
         first_os_variants) = node_info.pop(0)
        if not first_os_variants:
          first_os_variants = []
        first_os_msg = ("%s (path: %s) [variants: %s]" %
                        (_OsStatus(first_os_status, first_os_msg),
122
                         first_os_path, utils.CommaJoin(first_os_variants)))
123
        if first_os_status:
124
          nodes_valid[node_name] = first_os_msg
Guido Trotter's avatar
Guido Trotter committed
125
        else:
126
          nodes_bad[node_name] = first_os_msg
127
        for hpath, hstatus, hmsg in node_info:
128
          nodes_hidden[node_name].append("    [hidden] path: %s, status: %s" %
129
                                         (hpath, _OsStatus(hstatus, hmsg)))
Iustin Pop's avatar
Iustin Pop committed
130
      else:
Guido Trotter's avatar
Guido Trotter committed
131
        nodes_bad[node_name] = "OS not found"
Iustin Pop's avatar
Iustin Pop committed
132 133 134 135 136

    if nodes_valid and not nodes_bad:
      status = "valid"
    elif not nodes_valid and nodes_bad:
      status = "invalid"
137
      has_bad = True
Iustin Pop's avatar
Iustin Pop committed
138 139
    else:
      status = "partial valid"
140
      has_bad = True
141

142 143
    def _OutputPerNodeOSStatus(msg_map):
      map_k = utils.NiceSort(msg_map.keys())
Guido Trotter's avatar
Guido Trotter committed
144
      for node_name in map_k:
145
        ToStdout("  Node: %s, status: %s", node_name, msg_map[node_name])
146
        for msg in nodes_hidden[node_name]:
147
          ToStdout(msg)
Guido Trotter's avatar
Guido Trotter committed
148

149
    ToStdout("OS: %s [global status: %s]", os_name, status)
150
    if os_variants:
151
      ToStdout("  Variants: [%s]" % utils.CommaJoin(os_variants))
Guido Trotter's avatar
Guido Trotter committed
152 153
    _OutputPerNodeOSStatus(nodes_valid)
    _OutputPerNodeOSStatus(nodes_bad)
154
    ToStdout("")
Iustin Pop's avatar
Iustin Pop committed
155

156 157
  return int(has_bad)

Iustin Pop's avatar
Iustin Pop committed
158

159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184
def ModifyOS(opts, args):
  """Modify OS parameters for one OS.

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

  """
  os = args[0]

  op = opcodes.OpSetClusterParams(vg_name=None,
                                  enabled_hypervisors=None,
                                  hvparams=None,
                                  beparams=None,
                                  nicparams=None,
                                  candidate_pool_size=None,
                                  os_hvp={
                                    os: dict(opts.hvparams)
                                    })
  SubmitOpCode(op)

  return 0


Iustin Pop's avatar
Iustin Pop committed
185
commands = {
186
  'list': (
187
    ListOS, ARGS_NONE, [NOHDR_OPT], "", "Lists all valid OSes on the master"),
188
  'diagnose': (
189
    DiagnoseOS, ARGS_NONE, [], "", "Diagnose all OSes"),
190 191
  'modify': (
    ModifyOS, ARGS_ONE_OS, [HVLIST_OPT], "", "Modify os parameters"),
Iustin Pop's avatar
Iustin Pop committed
192 193 194
  }

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