Statistics
| Branch: | Tag: | Revision:

root / scripts / gnt-cluster @ f4d4e184

History | View | Annotate | Download (10.6 kB)

1
#!/usr/bin/python
2
#
3

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

    
22
import sys
23
from optparse import make_option
24
import pprint
25

    
26
from ganeti.cli import *
27
from ganeti import opcodes
28
from ganeti import constants
29
from ganeti import errors
30

    
31

    
32
def InitCluster(opts, args):
33
  """Initialize the cluster.
34

    
35
  Args:
36
    opts - class with options as members
37
    args - list of arguments, expected to be [clustername]
38

    
39
  """
40
  op = opcodes.OpInitCluster(cluster_name=args[0],
41
                             secondary_ip=opts.secondary_ip,
42
                             hypervisor_type=opts.hypervisor_type,
43
                             vg_name=opts.vg_name,
44
                             mac_prefix=opts.mac_prefix,
45
                             def_bridge=opts.def_bridge,
46
                             master_netdev=opts.master_netdev)
47
  SubmitOpCode(op)
48
  return 0
49

    
50

    
51
def DestroyCluster(opts, args):
52
  """Destroy the cluster.
53

    
54
  Args:
55
    opts - class with options as members
56

    
57
  """
58
  if not opts.yes_do_it:
59
    print ("Destroying a cluster is irreversibly. If you really want destroy"
60
           " this cluster, supply the --yes-do-it option.")
61
    return 1
62

    
63
  op = opcodes.OpDestroyCluster()
64
  SubmitOpCode(op)
65
  return 0
66

    
67

    
68
def RenameCluster(opts, args):
69
  """Rename the cluster.
70

    
71
  Args:
72
    opts - class with options as members, we use force only
73
    args - list of arguments, expected to be [new_name]
74

    
75
  """
76
  name = args[0]
77
  if not opts.force:
78
    usertext = ("This will rename the cluster to '%s'. If you are connected"
79
                " over the network to the cluster name, the operation is very"
80
                " dangerous as the IP address will be removed from the node"
81
                " and the change may not go through. Continue?") % name
82
    if not AskUser(usertext):
83
      return 1
84

    
85
  op = opcodes.OpRenameCluster(name=name)
86
  SubmitOpCode(op)
87
  return 0
88

    
89

    
90
def ShowClusterVersion(opts, args):
91
  """Write version of ganeti software to the standard output.
92

    
93
  Args:
94
    opts - class with options as members
95

    
96
  """
97
  op = opcodes.OpQueryClusterInfo()
98
  result = SubmitOpCode(op)
99
  print ("Software version: %s" % result["software_version"])
100
  print ("Internode protocol: %s" % result["protocol_version"])
101
  print ("Configuration format: %s" % result["config_version"])
102
  print ("OS api version: %s" % result["os_api_version"])
103
  print ("Export interface: %s" % result["export_version"])
104
  return 0
105

    
106

    
107
def ShowClusterMaster(opts, args):
108
  """Write name of master node to the standard output.
109

    
110
  Args:
111
    opts - class with options as members
112

    
113
  """
114
  op = opcodes.OpQueryClusterInfo()
115
  result = SubmitOpCode(op)
116
  print (result["master"])
117
  return 0
118

    
119

    
120
def ShowClusterConfig(opts, args):
121
  """Shows cluster information.
122

    
123
  """
124
  op = opcodes.OpQueryClusterInfo()
125
  result = SubmitOpCode(op)
126

    
127
  print ("Cluster name: %s" % result["name"])
128

    
129
  print ("Master node: %s" % result["master"])
130

    
131
  print ("Architecture (this node): %s (%s)" %
132
         (result["architecture"][0], result["architecture"][1]))
133

    
134
  return 0
135

    
136

    
137
def ClusterCopyFile(opts, args):
138
  """Copy a file from master to some nodes.
139

    
140
  Args:
141
    opts - class with options as members
142
    args - list containing a single element, the file name
143
  Opts used:
144
    nodes - list containing the name of target nodes; if empty, all nodes
145

    
146
  """
147
  op = opcodes.OpClusterCopyFile(filename=args[0], nodes=opts.nodes)
148
  SubmitOpCode(op)
149
  return 0
150

    
151

    
152
def RunClusterCommand(opts, args):
153
  """Run a command on some nodes.
154

    
155
  Args:
156
    opts - class with options as members
157
    args - the command list as a list
158
  Opts used:
159
    nodes: list containing the name of target nodes; if empty, all nodes
160

    
161
  """
162
  command = " ".join(args)
163
  nodes = opts.nodes
164
  op = opcodes.OpRunClusterCommand(command=command, nodes=nodes)
165
  result = SubmitOpCode(op)
166
  for node, output, exit_code in result:
167
    print ("------------------------------------------------")
168
    print ("node: %s" % node)
169
    print ("%s" % output)
170
    print ("return code = %s" % exit_code)
171

    
172

    
173
def VerifyCluster(opts, args):
174
  """Verify integrity of cluster, performing various test on nodes.
175

    
176
  Args:
177
    opts - class with options as members
178

    
179
  """
180
  op = opcodes.OpVerifyCluster()
181
  result = SubmitOpCode(op)
182
  return result
183

    
184

    
185
def VerifyDisks(opts, args):
186
  """Verify integrity of cluster disks.
187

    
188
  Args:
189
    opts - class with options as members
190

    
191
  """
192
  op = opcodes.OpVerifyDisks()
193
  result = SubmitOpCode(op)
194
  if not isinstance(result, tuple) or len(result) != 2:
195
    raise errors.ProgrammerError("Unknown result type for OpVerifyDisks")
196

    
197
  nodes, instances = result
198
  if nodes:
199
    print "Nodes unreachable or with bad data:"
200
    for name in nodes:
201
      print "\t%s" % name
202
  retcode = constants.EXIT_SUCCESS
203
  if instances:
204
    for iname in instances:
205
      op = opcodes.OpActivateInstanceDisks(instance_name=iname)
206
      try:
207
        print "Activating disks for instance '%s'" % iname
208
        SubmitOpCode(op)
209
      except errors.GenericError, err:
210
        nret, msg = FormatError(err)
211
        retcode |= nret
212
        print >>sys.stderr, ("Error activating disks for instance %s: %s" %
213
                             (iname, msg))
214

    
215
  return retcode
216

    
217

    
218
def MasterFailover(opts, args):
219
  """Failover the master node.
220

    
221
  This command, when run on a non-master node, will cause the current
222
  master to cease being master, and the non-master to become new
223
  master.
224

    
225
  """
226
  op = opcodes.OpMasterFailover()
227
  SubmitOpCode(op)
228

    
229

    
230
def SearchTags(opts, args):
231
  """Searches the tags on all the cluster.
232

    
233
  """
234
  op = opcodes.OpSearchTags(pattern=args[0])
235
  result = SubmitOpCode(op)
236
  if not result:
237
    return 1
238
  result = list(result)
239
  result.sort()
240
  for path, tag in result:
241
    print "%s %s" % (path, tag)
242

    
243

    
244
# this is an option common to more than one command, so we declare
245
# it here and reuse it
246
node_option = make_option("-n", "--node", action="append", dest="nodes",
247
                          help="Node to copy to (if not given, all nodes),"
248
                               " can be given multiple times",
249
                          metavar="<node>", default=[])
250

    
251
commands = {
252
  'init': (InitCluster, ARGS_ONE,
253
           [DEBUG_OPT,
254
            make_option("-s", "--secondary-ip", dest="secondary_ip",
255
                        help="Specify the secondary ip for this node;"
256
                        " if given, the entire cluster must have secondary"
257
                        " addresses",
258
                        metavar="ADDRESS", default=None),
259
            make_option("-t", "--hypervisor-type", dest="hypervisor_type",
260
                        help="Specify the hypervisor type (xen-3.0, fake)",
261
                        metavar="TYPE", choices=["xen-3.0", "fake"],
262
                        default="xen-3.0",),
263
            make_option("-m", "--mac-prefix", dest="mac_prefix",
264
                        help="Specify the mac prefix for the instance IP"
265
                        " addresses, in the format XX:XX:XX",
266
                        metavar="PREFIX",
267
                        default="aa:00:00",),
268
            make_option("-g", "--vg-name", dest="vg_name",
269
                        help="Specify the volume group name "
270
                        " (cluster-wide) for disk allocation [xenvg]",
271
                        metavar="VG",
272
                        default="xenvg",),
273
            make_option("-b", "--bridge", dest="def_bridge",
274
                        help="Specify the default bridge name (cluster-wide)"
275
                          " to connect the instances to [%s]" %
276
                          constants.DEFAULT_BRIDGE,
277
                        metavar="BRIDGE",
278
                        default=constants.DEFAULT_BRIDGE,),
279
            make_option("--master-netdev", dest="master_netdev",
280
                        help="Specify the node interface (cluster-wide)"
281
                          " on which the master IP address will be added "
282
                          " [%s]" % constants.DEFAULT_BRIDGE,
283
                        metavar="NETDEV",
284
                        default=constants.DEFAULT_BRIDGE,),
285
            ],
286
           "[opts...] <cluster_name>",
287
           "Initialises a new cluster configuration"),
288
  'destroy': (DestroyCluster, ARGS_NONE,
289
              [DEBUG_OPT,
290
               make_option("--yes-do-it", dest="yes_do_it",
291
                           help="Destroy cluster",
292
                           action="store_true"),
293
              ],
294
              "", "Destroy cluster"),
295
  'rename': (RenameCluster, ARGS_ONE, [DEBUG_OPT, FORCE_OPT],
296
               "<new_name>",
297
               "Renames the cluster"),
298
  'verify': (VerifyCluster, ARGS_NONE, [DEBUG_OPT],
299
             "", "Does a check on the cluster configuration"),
300
  'verify-disks': (VerifyDisks, ARGS_NONE, [DEBUG_OPT],
301
                   "", "Does a check on the cluster disk status"),
302
  'masterfailover': (MasterFailover, ARGS_NONE, [DEBUG_OPT],
303
                     "", "Makes the current node the master"),
304
  'version': (ShowClusterVersion, ARGS_NONE, [DEBUG_OPT],
305
              "", "Shows the cluster version"),
306
  'getmaster': (ShowClusterMaster, ARGS_NONE, [DEBUG_OPT],
307
                "", "Shows the cluster master"),
308
  'copyfile': (ClusterCopyFile, ARGS_ONE, [DEBUG_OPT, node_option],
309
               "[-n node...] <filename>",
310
               "Copies a file to all (or only some) nodes"),
311
  'command': (RunClusterCommand, ARGS_ATLEAST(1), [DEBUG_OPT, node_option],
312
              "[-n node...] <command>",
313
              "Runs a command on all (or only some) nodes"),
314
  'info': (ShowClusterConfig, ARGS_NONE, [DEBUG_OPT],
315
                 "", "Show cluster configuration"),
316
  'list-tags': (ListTags, ARGS_NONE,
317
                [DEBUG_OPT], "", "List the tags of the cluster"),
318
  'add-tags': (AddTags, ARGS_ANY, [DEBUG_OPT, TAG_SRC_OPT],
319
               "tag...", "Add tags to the cluster"),
320
  'remove-tags': (RemoveTags, ARGS_ANY, [DEBUG_OPT, TAG_SRC_OPT],
321
                  "tag...", "Remove tags from the cluster"),
322
  'search-tags': (SearchTags, ARGS_ONE,
323
                  [DEBUG_OPT], "", "Searches the tags on all objects on"
324
                  " the cluster for a given pattern (regex)"),
325
  }
326

    
327
if __name__ == '__main__':
328
  sys.exit(GenericMain(commands, override={"tag_type": constants.TAG_CLUSTER}))