Statistics
| Branch: | Tag: | Revision:

root / scripts / gnt-cluster @ 973d7867

History | View | Annotate | Download (11.8 kB)

1 a8083063 Iustin Pop
#!/usr/bin/python
2 a8083063 Iustin Pop
#
3 a8083063 Iustin Pop
4 a8083063 Iustin Pop
# Copyright (C) 2006, 2007 Google Inc.
5 a8083063 Iustin Pop
#
6 a8083063 Iustin Pop
# This program is free software; you can redistribute it and/or modify
7 a8083063 Iustin Pop
# it under the terms of the GNU General Public License as published by
8 a8083063 Iustin Pop
# the Free Software Foundation; either version 2 of the License, or
9 a8083063 Iustin Pop
# (at your option) any later version.
10 a8083063 Iustin Pop
#
11 a8083063 Iustin Pop
# This program is distributed in the hope that it will be useful, but
12 a8083063 Iustin Pop
# WITHOUT ANY WARRANTY; without even the implied warranty of
13 a8083063 Iustin Pop
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 a8083063 Iustin Pop
# General Public License for more details.
15 a8083063 Iustin Pop
#
16 a8083063 Iustin Pop
# You should have received a copy of the GNU General Public License
17 a8083063 Iustin Pop
# along with this program; if not, write to the Free Software
18 a8083063 Iustin Pop
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 a8083063 Iustin Pop
# 02110-1301, USA.
20 a8083063 Iustin Pop
21 a8083063 Iustin Pop
22 a8083063 Iustin Pop
import sys
23 a8083063 Iustin Pop
from optparse import make_option
24 a8083063 Iustin Pop
import pprint
25 a8083063 Iustin Pop
26 a8083063 Iustin Pop
from ganeti.cli import *
27 a8083063 Iustin Pop
from ganeti import opcodes
28 c2a62a33 Michael Hanselmann
from ganeti import constants
29 f4d4e184 Iustin Pop
from ganeti import errors
30 b63ed789 Iustin Pop
from ganeti import utils
31 a8083063 Iustin Pop
32 a8083063 Iustin Pop
33 a8083063 Iustin Pop
def InitCluster(opts, args):
34 a8083063 Iustin Pop
  """Initialize the cluster.
35 a8083063 Iustin Pop
36 a8083063 Iustin Pop
  Args:
37 a8083063 Iustin Pop
    opts - class with options as members
38 a8083063 Iustin Pop
    args - list of arguments, expected to be [clustername]
39 a8083063 Iustin Pop
40 a8083063 Iustin Pop
  """
41 a8083063 Iustin Pop
  op = opcodes.OpInitCluster(cluster_name=args[0],
42 a8083063 Iustin Pop
                             secondary_ip=opts.secondary_ip,
43 a8083063 Iustin Pop
                             hypervisor_type=opts.hypervisor_type,
44 a8083063 Iustin Pop
                             vg_name=opts.vg_name,
45 a8083063 Iustin Pop
                             mac_prefix=opts.mac_prefix,
46 880478f8 Iustin Pop
                             def_bridge=opts.def_bridge,
47 880478f8 Iustin Pop
                             master_netdev=opts.master_netdev)
48 a8083063 Iustin Pop
  SubmitOpCode(op)
49 a8083063 Iustin Pop
  return 0
50 a8083063 Iustin Pop
51 a8083063 Iustin Pop
52 a8083063 Iustin Pop
def DestroyCluster(opts, args):
53 a8083063 Iustin Pop
  """Destroy the cluster.
54 a8083063 Iustin Pop
55 a8083063 Iustin Pop
  Args:
56 a8083063 Iustin Pop
    opts - class with options as members
57 098c0958 Michael Hanselmann
58 a8083063 Iustin Pop
  """
59 a8083063 Iustin Pop
  if not opts.yes_do_it:
60 a8083063 Iustin Pop
    print ("Destroying a cluster is irreversibly. If you really want destroy"
61 79f7be7b Iustin Pop
           " this cluster, supply the --yes-do-it option.")
62 a8083063 Iustin Pop
    return 1
63 a8083063 Iustin Pop
64 a8083063 Iustin Pop
  op = opcodes.OpDestroyCluster()
65 a8083063 Iustin Pop
  SubmitOpCode(op)
66 a8083063 Iustin Pop
  return 0
67 a8083063 Iustin Pop
68 a8083063 Iustin Pop
69 07bd8a51 Iustin Pop
def RenameCluster(opts, args):
70 07bd8a51 Iustin Pop
  """Rename the cluster.
71 07bd8a51 Iustin Pop
72 07bd8a51 Iustin Pop
  Args:
73 07bd8a51 Iustin Pop
    opts - class with options as members, we use force only
74 07bd8a51 Iustin Pop
    args - list of arguments, expected to be [new_name]
75 07bd8a51 Iustin Pop
76 07bd8a51 Iustin Pop
  """
77 07bd8a51 Iustin Pop
  name = args[0]
78 07bd8a51 Iustin Pop
  if not opts.force:
79 07bd8a51 Iustin Pop
    usertext = ("This will rename the cluster to '%s'. If you are connected"
80 07bd8a51 Iustin Pop
                " over the network to the cluster name, the operation is very"
81 07bd8a51 Iustin Pop
                " dangerous as the IP address will be removed from the node"
82 07bd8a51 Iustin Pop
                " and the change may not go through. Continue?") % name
83 47988778 Iustin Pop
    if not AskUser(usertext):
84 07bd8a51 Iustin Pop
      return 1
85 07bd8a51 Iustin Pop
86 07bd8a51 Iustin Pop
  op = opcodes.OpRenameCluster(name=name)
87 07bd8a51 Iustin Pop
  SubmitOpCode(op)
88 07bd8a51 Iustin Pop
  return 0
89 07bd8a51 Iustin Pop
90 07bd8a51 Iustin Pop
91 a8083063 Iustin Pop
def ShowClusterVersion(opts, args):
92 a8083063 Iustin Pop
  """Write version of ganeti software to the standard output.
93 a8083063 Iustin Pop
94 a8083063 Iustin Pop
  Args:
95 a8083063 Iustin Pop
    opts - class with options as members
96 a8083063 Iustin Pop
97 a8083063 Iustin Pop
  """
98 a8083063 Iustin Pop
  op = opcodes.OpQueryClusterInfo()
99 a8083063 Iustin Pop
  result = SubmitOpCode(op)
100 a8083063 Iustin Pop
  print ("Software version: %s" % result["software_version"])
101 a8083063 Iustin Pop
  print ("Internode protocol: %s" % result["protocol_version"])
102 a8083063 Iustin Pop
  print ("Configuration format: %s" % result["config_version"])
103 a8083063 Iustin Pop
  print ("OS api version: %s" % result["os_api_version"])
104 a8083063 Iustin Pop
  print ("Export interface: %s" % result["export_version"])
105 a8083063 Iustin Pop
  return 0
106 a8083063 Iustin Pop
107 a8083063 Iustin Pop
108 a8083063 Iustin Pop
def ShowClusterMaster(opts, args):
109 a8083063 Iustin Pop
  """Write name of master node to the standard output.
110 a8083063 Iustin Pop
111 a8083063 Iustin Pop
  Args:
112 a8083063 Iustin Pop
    opts - class with options as members
113 a8083063 Iustin Pop
114 a8083063 Iustin Pop
  """
115 a8083063 Iustin Pop
  op = opcodes.OpQueryClusterInfo()
116 a8083063 Iustin Pop
  result = SubmitOpCode(op)
117 a8083063 Iustin Pop
  print (result["master"])
118 a8083063 Iustin Pop
  return 0
119 a8083063 Iustin Pop
120 a8083063 Iustin Pop
121 a8083063 Iustin Pop
def ShowClusterConfig(opts, args):
122 a8083063 Iustin Pop
  """Shows cluster information.
123 a8083063 Iustin Pop
124 a8083063 Iustin Pop
  """
125 a8083063 Iustin Pop
  op = opcodes.OpQueryClusterInfo()
126 a8083063 Iustin Pop
  result = SubmitOpCode(op)
127 a8083063 Iustin Pop
128 a8083063 Iustin Pop
  print ("Cluster name: %s" % result["name"])
129 a8083063 Iustin Pop
130 a8083063 Iustin Pop
  print ("Master node: %s" % result["master"])
131 a8083063 Iustin Pop
132 59322403 Iustin Pop
  print ("Architecture (this node): %s (%s)" %
133 59322403 Iustin Pop
         (result["architecture"][0], result["architecture"][1]))
134 a8083063 Iustin Pop
135 a8083063 Iustin Pop
  return 0
136 a8083063 Iustin Pop
137 a8083063 Iustin Pop
138 a8083063 Iustin Pop
def ClusterCopyFile(opts, args):
139 a8083063 Iustin Pop
  """Copy a file from master to some nodes.
140 a8083063 Iustin Pop
141 a8083063 Iustin Pop
  Args:
142 a8083063 Iustin Pop
    opts - class with options as members
143 a8083063 Iustin Pop
    args - list containing a single element, the file name
144 a8083063 Iustin Pop
  Opts used:
145 a8083063 Iustin Pop
    nodes - list containing the name of target nodes; if empty, all nodes
146 a8083063 Iustin Pop
147 a8083063 Iustin Pop
  """
148 a8083063 Iustin Pop
  op = opcodes.OpClusterCopyFile(filename=args[0], nodes=opts.nodes)
149 a8083063 Iustin Pop
  SubmitOpCode(op)
150 a8083063 Iustin Pop
  return 0
151 a8083063 Iustin Pop
152 a8083063 Iustin Pop
153 a8083063 Iustin Pop
def RunClusterCommand(opts, args):
154 a8083063 Iustin Pop
  """Run a command on some nodes.
155 a8083063 Iustin Pop
156 a8083063 Iustin Pop
  Args:
157 a8083063 Iustin Pop
    opts - class with options as members
158 a8083063 Iustin Pop
    args - the command list as a list
159 a8083063 Iustin Pop
  Opts used:
160 a8083063 Iustin Pop
    nodes: list containing the name of target nodes; if empty, all nodes
161 a8083063 Iustin Pop
162 a8083063 Iustin Pop
  """
163 a8083063 Iustin Pop
  command = " ".join(args)
164 a8083063 Iustin Pop
  nodes = opts.nodes
165 a8083063 Iustin Pop
  op = opcodes.OpRunClusterCommand(command=command, nodes=nodes)
166 a8083063 Iustin Pop
  result = SubmitOpCode(op)
167 02715459 Iustin Pop
  for node, output, exit_code in result:
168 a8083063 Iustin Pop
    print ("------------------------------------------------")
169 a8083063 Iustin Pop
    print ("node: %s" % node)
170 a8083063 Iustin Pop
    print ("%s" % output)
171 a8083063 Iustin Pop
    print ("return code = %s" % exit_code)
172 a8083063 Iustin Pop
173 a8083063 Iustin Pop
174 a8083063 Iustin Pop
def VerifyCluster(opts, args):
175 a8083063 Iustin Pop
  """Verify integrity of cluster, performing various test on nodes.
176 a8083063 Iustin Pop
177 a8083063 Iustin Pop
  Args:
178 a8083063 Iustin Pop
    opts - class with options as members
179 a8083063 Iustin Pop
180 a8083063 Iustin Pop
  """
181 a8083063 Iustin Pop
  op = opcodes.OpVerifyCluster()
182 a8083063 Iustin Pop
  result = SubmitOpCode(op)
183 a8083063 Iustin Pop
  return result
184 a8083063 Iustin Pop
185 a8083063 Iustin Pop
186 f4d4e184 Iustin Pop
def VerifyDisks(opts, args):
187 f4d4e184 Iustin Pop
  """Verify integrity of cluster disks.
188 f4d4e184 Iustin Pop
189 f4d4e184 Iustin Pop
  Args:
190 f4d4e184 Iustin Pop
    opts - class with options as members
191 f4d4e184 Iustin Pop
192 f4d4e184 Iustin Pop
  """
193 f4d4e184 Iustin Pop
  op = opcodes.OpVerifyDisks()
194 f4d4e184 Iustin Pop
  result = SubmitOpCode(op)
195 b63ed789 Iustin Pop
  if not isinstance(result, tuple) or len(result) != 4:
196 f4d4e184 Iustin Pop
    raise errors.ProgrammerError("Unknown result type for OpVerifyDisks")
197 f4d4e184 Iustin Pop
198 b63ed789 Iustin Pop
  nodes, nlvm, instances, missing = result
199 b63ed789 Iustin Pop
200 f4d4e184 Iustin Pop
  if nodes:
201 f4d4e184 Iustin Pop
    print "Nodes unreachable or with bad data:"
202 f4d4e184 Iustin Pop
    for name in nodes:
203 f4d4e184 Iustin Pop
      print "\t%s" % name
204 f4d4e184 Iustin Pop
  retcode = constants.EXIT_SUCCESS
205 b63ed789 Iustin Pop
206 b63ed789 Iustin Pop
  if nlvm:
207 b63ed789 Iustin Pop
    for node, text in nlvm.iteritems():
208 b63ed789 Iustin Pop
      print ("Error on node %s: LVM error: %s" %
209 b63ed789 Iustin Pop
             (node, text[-400:].encode('string_escape')))
210 b63ed789 Iustin Pop
      retcode |= 1
211 b63ed789 Iustin Pop
      print "You need to fix these nodes first before fixing instances"
212 b63ed789 Iustin Pop
213 f4d4e184 Iustin Pop
  if instances:
214 f4d4e184 Iustin Pop
    for iname in instances:
215 b63ed789 Iustin Pop
      if iname in missing:
216 b63ed789 Iustin Pop
        continue
217 f4d4e184 Iustin Pop
      op = opcodes.OpActivateInstanceDisks(instance_name=iname)
218 f4d4e184 Iustin Pop
      try:
219 f4d4e184 Iustin Pop
        print "Activating disks for instance '%s'" % iname
220 f4d4e184 Iustin Pop
        SubmitOpCode(op)
221 f4d4e184 Iustin Pop
      except errors.GenericError, err:
222 f4d4e184 Iustin Pop
        nret, msg = FormatError(err)
223 f4d4e184 Iustin Pop
        retcode |= nret
224 b63ed789 Iustin Pop
        print >> sys.stderr, ("Error activating disks for instance %s: %s" %
225 b63ed789 Iustin Pop
                              (iname, msg))
226 b63ed789 Iustin Pop
227 b63ed789 Iustin Pop
  if missing:
228 b63ed789 Iustin Pop
    for iname, ival in missing.iteritems():
229 b63ed789 Iustin Pop
      all_missing = utils.all(ival, lambda x: x[0] in nlvm)
230 b63ed789 Iustin Pop
      if all_missing:
231 b63ed789 Iustin Pop
        print ("Instance %s cannot be verified as it lives on"
232 b63ed789 Iustin Pop
               " broken nodes" % iname)
233 b63ed789 Iustin Pop
      else:
234 b63ed789 Iustin Pop
        print "Instance %s has missing logical volumes:" % iname
235 b63ed789 Iustin Pop
        ival.sort()
236 b63ed789 Iustin Pop
        for node, vol in ival:
237 b63ed789 Iustin Pop
          if node in nlvm:
238 b63ed789 Iustin Pop
            print ("\tbroken node %s /dev/xenvg/%s" % (node, vol))
239 b63ed789 Iustin Pop
          else:
240 b63ed789 Iustin Pop
            print ("\t%s /dev/xenvg/%s" % (node, vol))
241 b63ed789 Iustin Pop
    print ("You need to run replace_disks for all the above"
242 b63ed789 Iustin Pop
           " instances, if this message persist after fixing nodes.")
243 b63ed789 Iustin Pop
    retcode |= 1
244 f4d4e184 Iustin Pop
245 f4d4e184 Iustin Pop
  return retcode
246 f4d4e184 Iustin Pop
247 f4d4e184 Iustin Pop
248 a8083063 Iustin Pop
def MasterFailover(opts, args):
249 a8083063 Iustin Pop
  """Failover the master node.
250 a8083063 Iustin Pop
251 a8083063 Iustin Pop
  This command, when run on a non-master node, will cause the current
252 a8083063 Iustin Pop
  master to cease being master, and the non-master to become new
253 a8083063 Iustin Pop
  master.
254 a8083063 Iustin Pop
255 a8083063 Iustin Pop
  """
256 a8083063 Iustin Pop
  op = opcodes.OpMasterFailover()
257 a8083063 Iustin Pop
  SubmitOpCode(op)
258 a8083063 Iustin Pop
259 a8083063 Iustin Pop
260 73415719 Iustin Pop
def SearchTags(opts, args):
261 73415719 Iustin Pop
  """Searches the tags on all the cluster.
262 73415719 Iustin Pop
263 73415719 Iustin Pop
  """
264 73415719 Iustin Pop
  op = opcodes.OpSearchTags(pattern=args[0])
265 73415719 Iustin Pop
  result = SubmitOpCode(op)
266 73415719 Iustin Pop
  if not result:
267 73415719 Iustin Pop
    return 1
268 73415719 Iustin Pop
  result = list(result)
269 73415719 Iustin Pop
  result.sort()
270 73415719 Iustin Pop
  for path, tag in result:
271 73415719 Iustin Pop
    print "%s %s" % (path, tag)
272 73415719 Iustin Pop
273 73415719 Iustin Pop
274 a8083063 Iustin Pop
# this is an option common to more than one command, so we declare
275 a8083063 Iustin Pop
# it here and reuse it
276 a8083063 Iustin Pop
node_option = make_option("-n", "--node", action="append", dest="nodes",
277 f4bc1f2c Michael Hanselmann
                          help="Node to copy to (if not given, all nodes),"
278 f4bc1f2c Michael Hanselmann
                               " can be given multiple times",
279 f4bc1f2c Michael Hanselmann
                          metavar="<node>", default=[])
280 a8083063 Iustin Pop
281 a8083063 Iustin Pop
commands = {
282 a8083063 Iustin Pop
  'init': (InitCluster, ARGS_ONE,
283 a8083063 Iustin Pop
           [DEBUG_OPT,
284 a8083063 Iustin Pop
            make_option("-s", "--secondary-ip", dest="secondary_ip",
285 a8083063 Iustin Pop
                        help="Specify the secondary ip for this node;"
286 a8083063 Iustin Pop
                        " if given, the entire cluster must have secondary"
287 a8083063 Iustin Pop
                        " addresses",
288 a8083063 Iustin Pop
                        metavar="ADDRESS", default=None),
289 a8083063 Iustin Pop
            make_option("-t", "--hypervisor-type", dest="hypervisor_type",
290 2a6469d5 Alexander Schreiber
                        help="Specify the hypervisor type "
291 2a6469d5 Alexander Schreiber
                        "(xen-3.0, fake, xen-hvm-3.1)",
292 2a6469d5 Alexander Schreiber
                        metavar="TYPE", choices=["xen-3.0",
293 2a6469d5 Alexander Schreiber
                                                 "fake",
294 2a6469d5 Alexander Schreiber
                                                 "xen-hvm-3.1"],
295 a8083063 Iustin Pop
                        default="xen-3.0",),
296 a8083063 Iustin Pop
            make_option("-m", "--mac-prefix", dest="mac_prefix",
297 a8083063 Iustin Pop
                        help="Specify the mac prefix for the instance IP"
298 a8083063 Iustin Pop
                        " addresses, in the format XX:XX:XX",
299 a8083063 Iustin Pop
                        metavar="PREFIX",
300 a8083063 Iustin Pop
                        default="aa:00:00",),
301 a8083063 Iustin Pop
            make_option("-g", "--vg-name", dest="vg_name",
302 a8083063 Iustin Pop
                        help="Specify the volume group name "
303 a8083063 Iustin Pop
                        " (cluster-wide) for disk allocation [xenvg]",
304 a8083063 Iustin Pop
                        metavar="VG",
305 a8083063 Iustin Pop
                        default="xenvg",),
306 a8083063 Iustin Pop
            make_option("-b", "--bridge", dest="def_bridge",
307 a8083063 Iustin Pop
                        help="Specify the default bridge name (cluster-wide)"
308 cf62a272 Michael Hanselmann
                          " to connect the instances to [%s]" %
309 cf62a272 Michael Hanselmann
                          constants.DEFAULT_BRIDGE,
310 a8083063 Iustin Pop
                        metavar="BRIDGE",
311 cf62a272 Michael Hanselmann
                        default=constants.DEFAULT_BRIDGE,),
312 880478f8 Iustin Pop
            make_option("--master-netdev", dest="master_netdev",
313 880478f8 Iustin Pop
                        help="Specify the node interface (cluster-wide)"
314 cf62a272 Michael Hanselmann
                          " on which the master IP address will be added "
315 cf62a272 Michael Hanselmann
                          " [%s]" % constants.DEFAULT_BRIDGE,
316 880478f8 Iustin Pop
                        metavar="NETDEV",
317 cf62a272 Michael Hanselmann
                        default=constants.DEFAULT_BRIDGE,),
318 a8083063 Iustin Pop
            ],
319 a8083063 Iustin Pop
           "[opts...] <cluster_name>",
320 a8083063 Iustin Pop
           "Initialises a new cluster configuration"),
321 a8083063 Iustin Pop
  'destroy': (DestroyCluster, ARGS_NONE,
322 a8083063 Iustin Pop
              [DEBUG_OPT,
323 a8083063 Iustin Pop
               make_option("--yes-do-it", dest="yes_do_it",
324 a8083063 Iustin Pop
                           help="Destroy cluster",
325 a8083063 Iustin Pop
                           action="store_true"),
326 a8083063 Iustin Pop
              ],
327 a8083063 Iustin Pop
              "", "Destroy cluster"),
328 07bd8a51 Iustin Pop
  'rename': (RenameCluster, ARGS_ONE, [DEBUG_OPT, FORCE_OPT],
329 07bd8a51 Iustin Pop
               "<new_name>",
330 07bd8a51 Iustin Pop
               "Renames the cluster"),
331 a8083063 Iustin Pop
  'verify': (VerifyCluster, ARGS_NONE, [DEBUG_OPT],
332 a8083063 Iustin Pop
             "", "Does a check on the cluster configuration"),
333 f4d4e184 Iustin Pop
  'verify-disks': (VerifyDisks, ARGS_NONE, [DEBUG_OPT],
334 f4d4e184 Iustin Pop
                   "", "Does a check on the cluster disk status"),
335 a8083063 Iustin Pop
  'masterfailover': (MasterFailover, ARGS_NONE, [DEBUG_OPT],
336 a8083063 Iustin Pop
                     "", "Makes the current node the master"),
337 a8083063 Iustin Pop
  'version': (ShowClusterVersion, ARGS_NONE, [DEBUG_OPT],
338 a8083063 Iustin Pop
              "", "Shows the cluster version"),
339 a8083063 Iustin Pop
  'getmaster': (ShowClusterMaster, ARGS_NONE, [DEBUG_OPT],
340 a8083063 Iustin Pop
                "", "Shows the cluster master"),
341 a8083063 Iustin Pop
  'copyfile': (ClusterCopyFile, ARGS_ONE, [DEBUG_OPT, node_option],
342 a8083063 Iustin Pop
               "[-n node...] <filename>",
343 a8083063 Iustin Pop
               "Copies a file to all (or only some) nodes"),
344 a8083063 Iustin Pop
  'command': (RunClusterCommand, ARGS_ATLEAST(1), [DEBUG_OPT, node_option],
345 a8083063 Iustin Pop
              "[-n node...] <command>",
346 a8083063 Iustin Pop
              "Runs a command on all (or only some) nodes"),
347 a8083063 Iustin Pop
  'info': (ShowClusterConfig, ARGS_NONE, [DEBUG_OPT],
348 a8083063 Iustin Pop
                 "", "Show cluster configuration"),
349 846baef9 Iustin Pop
  'list-tags': (ListTags, ARGS_NONE,
350 846baef9 Iustin Pop
                [DEBUG_OPT], "", "List the tags of the cluster"),
351 810c50b7 Iustin Pop
  'add-tags': (AddTags, ARGS_ANY, [DEBUG_OPT, TAG_SRC_OPT],
352 846baef9 Iustin Pop
               "tag...", "Add tags to the cluster"),
353 810c50b7 Iustin Pop
  'remove-tags': (RemoveTags, ARGS_ANY, [DEBUG_OPT, TAG_SRC_OPT],
354 846baef9 Iustin Pop
                  "tag...", "Remove tags from the cluster"),
355 73415719 Iustin Pop
  'search-tags': (SearchTags, ARGS_ONE,
356 73415719 Iustin Pop
                  [DEBUG_OPT], "", "Searches the tags on all objects on"
357 73415719 Iustin Pop
                  " the cluster for a given pattern (regex)"),
358 a8083063 Iustin Pop
  }
359 a8083063 Iustin Pop
360 a8083063 Iustin Pop
if __name__ == '__main__':
361 846baef9 Iustin Pop
  sys.exit(GenericMain(commands, override={"tag_type": constants.TAG_CLUSTER}))