Revision 6d50f5f9

b/.gitignore
68 68

  
69 69
# scripts
70 70
/scripts/gnt-debug
71
/scripts/gnt-os
b/Makefile.am
139 139

  
140 140
client_PYTHON = \
141 141
	lib/client/__init__.py \
142
	lib/client/gnt_debug.py
142
	lib/client/gnt_debug.py \
143
	lib/client/gnt_os.py
143 144

  
144 145
hypervisor_PYTHON = \
145 146
	lib/hypervisor/__init__.py \
......
256 257
	scripts/gnt-os
257 258

  
258 259
PYTHON_BOOTSTRAP = \
259
	scripts/gnt-debug
260
	scripts/gnt-debug \
261
	scripts/gnt-os
260 262

  
261 263
dist_sbin_SCRIPTS = \
262 264
	daemons/ganeti-noded \
......
268 270
	scripts/gnt-cluster \
269 271
	scripts/gnt-instance \
270 272
	scripts/gnt-job \
271
	scripts/gnt-node \
272
	scripts/gnt-os
273
	scripts/gnt-node
273 274

  
274 275
nodist_sbin_SCRIPTS = \
275 276
	$(PYTHON_BOOTSTRAP) \
b/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-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
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.OpDiagnoseOS(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.OpDiagnoseOS(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.OpDiagnoseOS(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
    if nodes_valid and not nodes_bad:
199
      status = "valid"
200
    elif not nodes_valid and nodes_bad:
201
      status = "invalid"
202
      has_bad = True
203
    else:
204
      status = "partial valid"
205
      has_bad = True
206

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

  
214
    st_msg = "OS: %s [global status: %s]" % (os_name, status)
215
    if hid:
216
      st_msg += " [hidden]"
217
    if blk:
218
      st_msg += " [blacklisted]"
219
    ToStdout(st_msg)
220
    if os_variants:
221
      ToStdout("  Variants: [%s]" % utils.CommaJoin(os_variants))
222
    _OutputPerNodeOSStatus(nodes_valid)
223
    _OutputPerNodeOSStatus(nodes_bad)
224
    ToStdout("")
225

  
226
  return int(has_bad)
227

  
228

  
229
def ModifyOS(opts, args):
230
  """Modify OS parameters for one OS.
231

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

  
238
  """
239
  os = args[0]
240

  
241
  if opts.hvparams:
242
    os_hvp = {os: dict(opts.hvparams)}
243
  else:
244
    os_hvp = None
245

  
246
  if opts.osparams:
247
    osp = {os: opts.osparams}
248
  else:
249
    osp = None
250

  
251
  if opts.hidden is not None:
252
    if opts.hidden:
253
      ohid = [(constants.DDM_ADD, os)]
254
    else:
255
      ohid = [(constants.DDM_REMOVE, os)]
256
  else:
257
    ohid = None
258

  
259
  if opts.blacklisted is not None:
260
    if opts.blacklisted:
261
      oblk = [(constants.DDM_ADD, os)]
262
    else:
263
      oblk = [(constants.DDM_REMOVE, os)]
264
  else:
265
    oblk = None
266

  
267
  if not (os_hvp or osp or ohid or oblk):
268
    ToStderr("At least one of OS parameters or hypervisor parameters"
269
             " must be passed")
270
    return 1
271

  
272
  op = opcodes.OpSetClusterParams(os_hvp=os_hvp,
273
                                  osparams=osp,
274
                                  hidden_os=ohid,
275
                                  blacklisted_os=oblk)
276
  SubmitOpCode(op, opts=opts)
277

  
278
  return 0
279

  
280

  
281
commands = {
282
  'list': (
283
    ListOS, ARGS_NONE, [NOHDR_OPT, PRIORITY_OPT],
284
    "", "Lists all valid operating systems on the cluster"),
285
  'diagnose': (
286
    DiagnoseOS, ARGS_NONE, [PRIORITY_OPT],
287
    "", "Diagnose all operating systems"),
288
  'info': (
289
    ShowOSInfo, [ArgOs()], [PRIORITY_OPT],
290
    "", "Show detailed information about "
291
    "operating systems"),
292
  'modify': (
293
    ModifyOS, ARGS_ONE_OS,
294
    [HVLIST_OPT, OSPARAMS_OPT, DRY_RUN_OPT, PRIORITY_OPT,
295
     HID_OS_OPT, BLK_OS_OPT],
296
    "", "Modify the OS parameters"),
297
  }
298

  
299

  
300
def Main():
301
  return GenericMain(commands)
/dev/null
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", "variants"], names=[])
48
  result = SubmitOpCode(op, opts=opts)
49

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

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

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

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

  
66
  for line in data:
67
    ToStdout(line)
68

  
69
  return 0
70

  
71

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

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

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

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

  
92
  do_filter = bool(args)
93

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

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

  
121
  return 0
122

  
123

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

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

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

  
140

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

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

  
150
  """
151
  op = opcodes.OpDiagnoseOS(output_fields=["name", "valid", "variants",
152
                                           "node_status", "hidden",
153
                                           "blacklisted"], names=[])
154
  result = SubmitOpCode(op, opts=opts)
155

  
156
  if not result:
157
    ToStderr("Can't get the OS list")
158
    return 1
159

  
160
  has_bad = False
161

  
162
  for os_name, _, os_variants, node_data, hid, blk in result:
163
    nodes_valid = {}
164
    nodes_bad = {}
165
    nodes_hidden = {}
166
    for node_name, node_info in node_data.iteritems():
167
      nodes_hidden[node_name] = []
168
      if node_info: # at least one entry in the per-node list
169
        (fo_path, fo_status, fo_msg, fo_variants,
170
         fo_params, fo_api) = node_info.pop(0)
171
        fo_msg = "%s (path: %s)" % (_OsStatus(fo_status, fo_msg), fo_path)
172
        if fo_api:
173
          max_os_api = max(fo_api)
174
          fo_msg += " [API versions: %s]" % utils.CommaJoin(fo_api)
175
        else:
176
          max_os_api = 0
177
          fo_msg += " [no API versions declared]"
178

  
179
        if max_os_api >= constants.OS_API_V15:
180
          if fo_variants:
181
            fo_msg += " [variants: %s]" % utils.CommaJoin(fo_variants)
182
          else:
183
            fo_msg += " [no variants]"
184
        if max_os_api >= constants.OS_API_V20:
185
          if fo_params:
186
            fo_msg += (" [parameters: %s]" %
187
                       utils.CommaJoin([v[0] for v in fo_params]))
188
          else:
189
            fo_msg += " [no parameters]"
190
        if fo_status:
191
          nodes_valid[node_name] = fo_msg
192
        else:
193
          nodes_bad[node_name] = fo_msg
194
        for hpath, hstatus, hmsg, _, _, _ in node_info:
195
          nodes_hidden[node_name].append("    [hidden] path: %s, status: %s" %
196
                                         (hpath, _OsStatus(hstatus, hmsg)))
197
      else:
198
        nodes_bad[node_name] = "OS not found"
199

  
200
    if nodes_valid and not nodes_bad:
201
      status = "valid"
202
    elif not nodes_valid and nodes_bad:
203
      status = "invalid"
204
      has_bad = True
205
    else:
206
      status = "partial valid"
207
      has_bad = True
208

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

  
216
    st_msg = "OS: %s [global status: %s]" % (os_name, status)
217
    if hid:
218
      st_msg += " [hidden]"
219
    if blk:
220
      st_msg += " [blacklisted]"
221
    ToStdout(st_msg)
222
    if os_variants:
223
      ToStdout("  Variants: [%s]" % utils.CommaJoin(os_variants))
224
    _OutputPerNodeOSStatus(nodes_valid)
225
    _OutputPerNodeOSStatus(nodes_bad)
226
    ToStdout("")
227

  
228
  return int(has_bad)
229

  
230

  
231
def ModifyOS(opts, args):
232
  """Modify OS parameters for one OS.
233

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

  
240
  """
241
  os = args[0]
242

  
243
  if opts.hvparams:
244
    os_hvp = {os: dict(opts.hvparams)}
245
  else:
246
    os_hvp = None
247

  
248
  if opts.osparams:
249
    osp = {os: opts.osparams}
250
  else:
251
    osp = None
252

  
253
  if opts.hidden is not None:
254
    if opts.hidden:
255
      ohid = [(constants.DDM_ADD, os)]
256
    else:
257
      ohid = [(constants.DDM_REMOVE, os)]
258
  else:
259
    ohid = None
260

  
261
  if opts.blacklisted is not None:
262
    if opts.blacklisted:
263
      oblk = [(constants.DDM_ADD, os)]
264
    else:
265
      oblk = [(constants.DDM_REMOVE, os)]
266
  else:
267
    oblk = None
268

  
269
  if not (os_hvp or osp or ohid or oblk):
270
    ToStderr("At least one of OS parameters or hypervisor parameters"
271
             " must be passed")
272
    return 1
273

  
274
  op = opcodes.OpSetClusterParams(os_hvp=os_hvp,
275
                                  osparams=osp,
276
                                  hidden_os=ohid,
277
                                  blacklisted_os=oblk)
278
  SubmitOpCode(op, opts=opts)
279

  
280
  return 0
281

  
282

  
283
commands = {
284
  'list': (
285
    ListOS, ARGS_NONE, [NOHDR_OPT, PRIORITY_OPT],
286
    "", "Lists all valid operating systems on the cluster"),
287
  'diagnose': (
288
    DiagnoseOS, ARGS_NONE, [PRIORITY_OPT],
289
    "", "Diagnose all operating systems"),
290
  'info': (
291
    ShowOSInfo, [ArgOs()], [PRIORITY_OPT],
292
    "", "Show detailed information about "
293
    "operating systems"),
294
  'modify': (
295
    ModifyOS, ARGS_ONE_OS,
296
    [HVLIST_OPT, OSPARAMS_OPT, DRY_RUN_OPT, PRIORITY_OPT,
297
     HID_OS_OPT, BLK_OS_OPT],
298
    "", "Modify the OS parameters"),
299
  }
300

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

Also available in: Unified diff