Statistics
| Branch: | Tag: | Revision:

root / scripts / gnt-node @ 9a033156

History | View | Annotate | Download (11.2 kB)

1 a8083063 Iustin Pop
#!/usr/bin/python
2 a8083063 Iustin Pop
#
3 a8083063 Iustin Pop
4 e7c6e02b Michael Hanselmann
# Copyright (C) 2006, 2007, 2008 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
25 a8083063 Iustin Pop
from ganeti.cli import *
26 a8083063 Iustin Pop
from ganeti import opcodes
27 a8083063 Iustin Pop
from ganeti import logger
28 a8083063 Iustin Pop
from ganeti import utils
29 846baef9 Iustin Pop
from ganeti import constants
30 c450e9b0 Iustin Pop
from ganeti import errors
31 a8083063 Iustin Pop
32 a8083063 Iustin Pop
33 48c4dfa8 Iustin Pop
_LIST_DEF_FIELDS = [
34 48c4dfa8 Iustin Pop
  "name", "dtotal", "dfree",
35 48c4dfa8 Iustin Pop
  "mtotal", "mnode", "mfree",
36 48c4dfa8 Iustin Pop
  "pinst_cnt", "sinst_cnt",
37 48c4dfa8 Iustin Pop
  ]
38 48c4dfa8 Iustin Pop
39 a8083063 Iustin Pop
def AddNode(opts, args):
40 a8083063 Iustin Pop
  """Add node cli-to-processor bridge."""
41 99e8bbde Guido Trotter
  logger.ToStderr("-- WARNING -- \n"
42 99e8bbde Guido Trotter
    "Performing this operation is going to replace the ssh daemon keypair\n"
43 99e8bbde Guido Trotter
    "on the target machine (%s) with the ones of the current one\n"
44 99e8bbde Guido Trotter
    "and grant full intra-cluster ssh root access to/from it\n" % args[0])
45 e7c6e02b Michael Hanselmann
  op = opcodes.OpAddNode(node_name=args[0], secondary_ip=opts.secondary_ip,
46 e7c6e02b Michael Hanselmann
                         readd=opts.readd)
47 a8083063 Iustin Pop
  SubmitOpCode(op)
48 a8083063 Iustin Pop
49 a8083063 Iustin Pop
50 a8083063 Iustin Pop
def ListNodes(opts, args):
51 a8083063 Iustin Pop
  """List nodes and their properties.
52 a8083063 Iustin Pop
53 a8083063 Iustin Pop
  """
54 a8083063 Iustin Pop
  if opts.output is None:
55 48c4dfa8 Iustin Pop
    selected_fields = _LIST_DEF_FIELDS
56 48c4dfa8 Iustin Pop
  elif opts.output.startswith("+"):
57 48c4dfa8 Iustin Pop
    selected_fields = _LIST_DEF_FIELDS + opts.output[1:].split(",")
58 a8083063 Iustin Pop
  else:
59 a8083063 Iustin Pop
    selected_fields = opts.output.split(",")
60 a8083063 Iustin Pop
61 246e180a Iustin Pop
  op = opcodes.OpQueryNodes(output_fields=selected_fields, names=[])
62 a8083063 Iustin Pop
  output = SubmitOpCode(op)
63 a8083063 Iustin Pop
64 a8083063 Iustin Pop
  if not opts.no_headers:
65 e8a4c138 Iustin Pop
    headers = {
66 e8a4c138 Iustin Pop
      "name": "Node", "pinst_cnt": "Pinst", "sinst_cnt": "Sinst",
67 e8a4c138 Iustin Pop
      "pinst_list": "PriInstances", "sinst_list": "SecInstances",
68 e8a4c138 Iustin Pop
      "pip": "PrimaryIP", "sip": "SecondaryIP",
69 e8a4c138 Iustin Pop
      "dtotal": "DTotal", "dfree": "DFree",
70 e8a4c138 Iustin Pop
      "mtotal": "MTotal", "mnode": "MNode", "mfree": "MFree",
71 e8a4c138 Iustin Pop
      "bootid": "BootID",
72 e8a4c138 Iustin Pop
      "ctotal": "CTotal",
73 e8a4c138 Iustin Pop
      }
74 137161c9 Michael Hanselmann
  else:
75 137161c9 Michael Hanselmann
    headers = None
76 137161c9 Michael Hanselmann
77 137161c9 Michael Hanselmann
  if opts.human_readable:
78 137161c9 Michael Hanselmann
    unitfields = ["dtotal", "dfree", "mtotal", "mnode", "mfree"]
79 137161c9 Michael Hanselmann
  else:
80 137161c9 Michael Hanselmann
    unitfields = None
81 137161c9 Michael Hanselmann
82 ec223efb Iustin Pop
  numfields = ["dtotal", "dfree",
83 ec223efb Iustin Pop
               "mtotal", "mnode", "mfree",
84 e8a4c138 Iustin Pop
               "pinst_cnt", "sinst_cnt",
85 e8a4c138 Iustin Pop
               "ctotal"]
86 ec223efb Iustin Pop
87 ec223efb Iustin Pop
  # change raw values to nicer strings
88 ec223efb Iustin Pop
  for row in output:
89 ec223efb Iustin Pop
    for idx, field in enumerate(selected_fields):
90 ec223efb Iustin Pop
      val = row[idx]
91 ec223efb Iustin Pop
      if field == "pinst_list":
92 ec223efb Iustin Pop
        val = ",".join(val)
93 ec223efb Iustin Pop
      elif field == "sinst_list":
94 ec223efb Iustin Pop
        val = ",".join(val)
95 ec223efb Iustin Pop
      elif val is None:
96 ec223efb Iustin Pop
        val = "?"
97 ec223efb Iustin Pop
      row[idx] = str(val)
98 137161c9 Michael Hanselmann
99 16be8703 Iustin Pop
  data = GenerateTable(separator=opts.separator, headers=headers,
100 16be8703 Iustin Pop
                       fields=selected_fields, unitfields=unitfields,
101 16be8703 Iustin Pop
                       numfields=numfields, data=output)
102 16be8703 Iustin Pop
  for line in data:
103 16be8703 Iustin Pop
    logger.ToStdout(line)
104 a8083063 Iustin Pop
105 a8083063 Iustin Pop
  return 0
106 a8083063 Iustin Pop
107 a8083063 Iustin Pop
108 a5bc662a Iustin Pop
def EvacuateNode(opts, args):
109 a5bc662a Iustin Pop
  """Relocate all secondary instance from a node.
110 a5bc662a Iustin Pop
111 a5bc662a Iustin Pop
  """
112 a5bc662a Iustin Pop
  force = opts.force
113 a5bc662a Iustin Pop
  selected_fields = ["name", "sinst_list"]
114 a5bc662a Iustin Pop
  src_node, dst_node = args
115 a5bc662a Iustin Pop
116 a5bc662a Iustin Pop
  op = opcodes.OpQueryNodes(output_fields=selected_fields, names=[src_node])
117 a5bc662a Iustin Pop
  result = SubmitOpCode(op)
118 a5bc662a Iustin Pop
  src_node, sinst = result[0]
119 a5bc662a Iustin Pop
  op = opcodes.OpQueryNodes(output_fields=["name"], names=[dst_node])
120 a5bc662a Iustin Pop
  result = SubmitOpCode(op)
121 a5bc662a Iustin Pop
  dst_node = result[0][0]
122 a5bc662a Iustin Pop
123 a5bc662a Iustin Pop
  if src_node == dst_node:
124 a5bc662a Iustin Pop
    raise errors.OpPrereqError("Evacuate node needs different source and"
125 a5bc662a Iustin Pop
                               " target nodes (node %s given twice)" %
126 a5bc662a Iustin Pop
                               src_node)
127 a5bc662a Iustin Pop
128 a5bc662a Iustin Pop
  if not sinst:
129 a5bc662a Iustin Pop
    logger.ToStderr("No secondary instances on node %s, exiting." % src_node)
130 a5bc662a Iustin Pop
    return constants.EXIT_SUCCESS
131 a5bc662a Iustin Pop
132 a5bc662a Iustin Pop
  sinst = utils.NiceSort(sinst)
133 a5bc662a Iustin Pop
134 a5bc662a Iustin Pop
  retcode = constants.EXIT_SUCCESS
135 a5bc662a Iustin Pop
136 a5bc662a Iustin Pop
  if not force and not AskUser("Relocate instance(s) %s from node\n"
137 a5bc662a Iustin Pop
                               " %s to node\n %s?" %
138 a5bc662a Iustin Pop
                               (",".join("'%s'" % name for name in sinst),
139 a5bc662a Iustin Pop
                               src_node, dst_node)):
140 a5bc662a Iustin Pop
    return constants.EXIT_CONFIRMATION
141 a5bc662a Iustin Pop
142 a5bc662a Iustin Pop
  good_cnt = bad_cnt = 0
143 a5bc662a Iustin Pop
  for iname in sinst:
144 a5bc662a Iustin Pop
    op = opcodes.OpReplaceDisks(instance_name=iname,
145 22d31e49 Michael Hanselmann
                                remote_node=dst_node,
146 22d31e49 Michael Hanselmann
                                mode=constants.REPLACE_DISK_ALL,
147 22d31e49 Michael Hanselmann
                                disks=["sda", "sdb"])
148 a5bc662a Iustin Pop
    try:
149 a5bc662a Iustin Pop
      logger.ToStdout("Replacing disks for instance %s" % iname)
150 a5bc662a Iustin Pop
      SubmitOpCode(op)
151 a5bc662a Iustin Pop
      logger.ToStdout("Instance %s has been relocated" % iname)
152 a5bc662a Iustin Pop
      good_cnt += 1
153 a5bc662a Iustin Pop
    except errors.GenericError, err:
154 a5bc662a Iustin Pop
      nret, msg = FormatError(err)
155 a5bc662a Iustin Pop
      retcode |= nret
156 a5bc662a Iustin Pop
      logger.ToStderr("Error replacing disks for instance %s: %s" %
157 a5bc662a Iustin Pop
                      (iname, msg))
158 a5bc662a Iustin Pop
      bad_cnt += 1
159 a5bc662a Iustin Pop
160 a5bc662a Iustin Pop
  if retcode == constants.EXIT_SUCCESS:
161 a5bc662a Iustin Pop
    logger.ToStdout("All %d instance(s) relocated successfully." % good_cnt)
162 a5bc662a Iustin Pop
  else:
163 a5bc662a Iustin Pop
    logger.ToStdout("There were errors during the relocation:\n"
164 a5bc662a Iustin Pop
                    "%d error(s) out of %d instance(s)." %
165 a5bc662a Iustin Pop
                    (bad_cnt, good_cnt + bad_cnt))
166 a5bc662a Iustin Pop
  return retcode
167 a5bc662a Iustin Pop
168 a5bc662a Iustin Pop
169 c450e9b0 Iustin Pop
def FailoverNode(opts, args):
170 c450e9b0 Iustin Pop
  """Failover all primary instance on a node.
171 c450e9b0 Iustin Pop
172 c450e9b0 Iustin Pop
  """
173 c450e9b0 Iustin Pop
  force = opts.force
174 c450e9b0 Iustin Pop
  selected_fields = ["name", "pinst_list"]
175 c450e9b0 Iustin Pop
176 c450e9b0 Iustin Pop
  op = opcodes.OpQueryNodes(output_fields=selected_fields, names=args)
177 c450e9b0 Iustin Pop
  result = SubmitOpCode(op)
178 c450e9b0 Iustin Pop
  node, pinst = result[0]
179 c450e9b0 Iustin Pop
180 c450e9b0 Iustin Pop
  if not pinst:
181 c450e9b0 Iustin Pop
    logger.ToStderr("No primary instances on node %s, exiting." % node)
182 c450e9b0 Iustin Pop
    return 0
183 c450e9b0 Iustin Pop
184 c450e9b0 Iustin Pop
  pinst = utils.NiceSort(pinst)
185 c450e9b0 Iustin Pop
186 c450e9b0 Iustin Pop
  retcode = 0
187 c450e9b0 Iustin Pop
188 c450e9b0 Iustin Pop
  if not force and not AskUser("Fail over instance(s) %s?" %
189 c450e9b0 Iustin Pop
                               (",".join("'%s'" % name for name in pinst))):
190 c450e9b0 Iustin Pop
    return 2
191 c450e9b0 Iustin Pop
192 c450e9b0 Iustin Pop
  good_cnt = bad_cnt = 0
193 c450e9b0 Iustin Pop
  for iname in pinst:
194 c450e9b0 Iustin Pop
    op = opcodes.OpFailoverInstance(instance_name=iname,
195 c450e9b0 Iustin Pop
                                    ignore_consistency=opts.ignore_consistency)
196 c450e9b0 Iustin Pop
    try:
197 c450e9b0 Iustin Pop
      logger.ToStdout("Failing over instance %s" % iname)
198 c450e9b0 Iustin Pop
      SubmitOpCode(op)
199 c450e9b0 Iustin Pop
      logger.ToStdout("Instance %s has been failed over" % iname)
200 c450e9b0 Iustin Pop
      good_cnt += 1
201 c450e9b0 Iustin Pop
    except errors.GenericError, err:
202 c450e9b0 Iustin Pop
      nret, msg = FormatError(err)
203 c450e9b0 Iustin Pop
      retcode |= nret
204 c450e9b0 Iustin Pop
      logger.ToStderr("Error failing over instance %s: %s" % (iname, msg))
205 c450e9b0 Iustin Pop
      bad_cnt += 1
206 c450e9b0 Iustin Pop
207 c450e9b0 Iustin Pop
  if retcode == 0:
208 c450e9b0 Iustin Pop
    logger.ToStdout("All %d instance(s) failed over successfully." % good_cnt)
209 c450e9b0 Iustin Pop
  else:
210 c450e9b0 Iustin Pop
    logger.ToStdout("There were errors during the failover:\n"
211 c450e9b0 Iustin Pop
                    "%d error(s) out of %d instance(s)." %
212 c450e9b0 Iustin Pop
                    (bad_cnt, good_cnt + bad_cnt))
213 c450e9b0 Iustin Pop
  return retcode
214 c450e9b0 Iustin Pop
215 c450e9b0 Iustin Pop
216 a8083063 Iustin Pop
def ShowNodeConfig(opts, args):
217 a8083063 Iustin Pop
  """Show node information.
218 a8083063 Iustin Pop
219 a8083063 Iustin Pop
  """
220 4a72cc75 Iustin Pop
  op = opcodes.OpQueryNodes(output_fields=["name", "pip", "sip",
221 4a72cc75 Iustin Pop
                                           "pinst_list", "sinst_list"],
222 246e180a Iustin Pop
                            names=args)
223 a8083063 Iustin Pop
  result = SubmitOpCode(op)
224 a8083063 Iustin Pop
225 a8083063 Iustin Pop
  for name, primary_ip, secondary_ip, pinst, sinst in result:
226 a8083063 Iustin Pop
    logger.ToStdout("Node name: %s" % name)
227 a8083063 Iustin Pop
    logger.ToStdout("  primary ip: %s" % primary_ip)
228 a8083063 Iustin Pop
    logger.ToStdout("  secondary ip: %s" % secondary_ip)
229 a8083063 Iustin Pop
    if pinst:
230 a8083063 Iustin Pop
      logger.ToStdout("  primary for instances:")
231 a8083063 Iustin Pop
      for iname in pinst:
232 a8083063 Iustin Pop
        logger.ToStdout("    - %s" % iname)
233 a8083063 Iustin Pop
    else:
234 a8083063 Iustin Pop
      logger.ToStdout("  primary for no instances")
235 a8083063 Iustin Pop
    if sinst:
236 a8083063 Iustin Pop
      logger.ToStdout("  secondary for instances:")
237 a8083063 Iustin Pop
      for iname in sinst:
238 a8083063 Iustin Pop
        logger.ToStdout("    - %s" % iname)
239 a8083063 Iustin Pop
    else:
240 a8083063 Iustin Pop
      logger.ToStdout("  secondary for no instances")
241 a8083063 Iustin Pop
242 a8083063 Iustin Pop
  return 0
243 a8083063 Iustin Pop
244 a8083063 Iustin Pop
245 a8083063 Iustin Pop
def RemoveNode(opts, args):
246 a8083063 Iustin Pop
  """Remove node cli-to-processor bridge."""
247 a8083063 Iustin Pop
  op = opcodes.OpRemoveNode(node_name=args[0])
248 a8083063 Iustin Pop
  SubmitOpCode(op)
249 a8083063 Iustin Pop
250 a8083063 Iustin Pop
251 dcb93971 Michael Hanselmann
def ListVolumes(opts, args):
252 dcb93971 Michael Hanselmann
  """List logical volumes on node(s).
253 dcb93971 Michael Hanselmann
254 dcb93971 Michael Hanselmann
  """
255 dcb93971 Michael Hanselmann
  if opts.output is None:
256 dcb93971 Michael Hanselmann
    selected_fields = ["node", "phys", "vg",
257 dcb93971 Michael Hanselmann
                       "name", "size", "instance"]
258 dcb93971 Michael Hanselmann
  else:
259 dcb93971 Michael Hanselmann
    selected_fields = opts.output.split(",")
260 dcb93971 Michael Hanselmann
261 dcb93971 Michael Hanselmann
  op = opcodes.OpQueryNodeVolumes(nodes=args, output_fields=selected_fields)
262 dcb93971 Michael Hanselmann
  output = SubmitOpCode(op)
263 dcb93971 Michael Hanselmann
264 dcb93971 Michael Hanselmann
  if not opts.no_headers:
265 137161c9 Michael Hanselmann
    headers = {"node": "Node", "phys": "PhysDev",
266 137161c9 Michael Hanselmann
               "vg": "VG", "name": "Name",
267 137161c9 Michael Hanselmann
               "size": "Size", "instance": "Instance"}
268 137161c9 Michael Hanselmann
  else:
269 137161c9 Michael Hanselmann
    headers = None
270 137161c9 Michael Hanselmann
271 137161c9 Michael Hanselmann
  if opts.human_readable:
272 137161c9 Michael Hanselmann
    unitfields = ["size"]
273 137161c9 Michael Hanselmann
  else:
274 137161c9 Michael Hanselmann
    unitfields = None
275 137161c9 Michael Hanselmann
276 137161c9 Michael Hanselmann
  numfields = ["size"]
277 137161c9 Michael Hanselmann
278 16be8703 Iustin Pop
  data = GenerateTable(separator=opts.separator, headers=headers,
279 16be8703 Iustin Pop
                       fields=selected_fields, unitfields=unitfields,
280 16be8703 Iustin Pop
                       numfields=numfields, data=output)
281 16be8703 Iustin Pop
282 16be8703 Iustin Pop
  for line in data:
283 16be8703 Iustin Pop
    logger.ToStdout(line)
284 dcb93971 Michael Hanselmann
285 dcb93971 Michael Hanselmann
  return 0
286 dcb93971 Michael Hanselmann
287 dcb93971 Michael Hanselmann
288 a8083063 Iustin Pop
commands = {
289 a8083063 Iustin Pop
  'add': (AddNode, ARGS_ONE,
290 a8083063 Iustin Pop
          [DEBUG_OPT,
291 a8083063 Iustin Pop
           make_option("-s", "--secondary-ip", dest="secondary_ip",
292 a8083063 Iustin Pop
                       help="Specify the secondary ip for the node",
293 e7c6e02b Michael Hanselmann
                       metavar="ADDRESS", default=None),
294 e7c6e02b Michael Hanselmann
           make_option("--readd", dest="readd",
295 e7c6e02b Michael Hanselmann
                       default=False, action="store_true",
296 e7c6e02b Michael Hanselmann
                       help="Readd old node after replacing it"),
297 e7c6e02b Michael Hanselmann
           ],
298 9a033156 Iustin Pop
          "[-s ip] <node_name>", "Add a node to the cluster"),
299 a5bc662a Iustin Pop
  'evacuate': (EvacuateNode, ARGS_FIXED(2),
300 a5bc662a Iustin Pop
               [DEBUG_OPT, FORCE_OPT],
301 9a033156 Iustin Pop
               "[-f] <src> <dst>",
302 a5bc662a Iustin Pop
               "Relocate the secondary instances from the first node"
303 9b603bff Alexander Schreiber
               " to the second one (only for instances of type remote_raid1"
304 9b603bff Alexander Schreiber
               " drbd)"),
305 c450e9b0 Iustin Pop
  'failover': (FailoverNode, ARGS_ONE,
306 c450e9b0 Iustin Pop
               [DEBUG_OPT, FORCE_OPT,
307 c450e9b0 Iustin Pop
                make_option("--ignore-consistency", dest="ignore_consistency",
308 c450e9b0 Iustin Pop
                            action="store_true", default=False,
309 c450e9b0 Iustin Pop
                            help="Ignore the consistency of the disks on"
310 c450e9b0 Iustin Pop
                            " the secondary"),
311 c450e9b0 Iustin Pop
                ],
312 9a033156 Iustin Pop
               "[-f] <node>",
313 c450e9b0 Iustin Pop
               "Stops the primary instances on a node and start them on their"
314 c450e9b0 Iustin Pop
               " secondary node (only for instances of type remote_raid1)"),
315 a8083063 Iustin Pop
  'info': (ShowNodeConfig, ARGS_ANY, [DEBUG_OPT],
316 9a033156 Iustin Pop
           "[<node_name>...]", "Show information about the node(s)"),
317 a8083063 Iustin Pop
  'list': (ListNodes, ARGS_NONE,
318 dcb93971 Michael Hanselmann
           [DEBUG_OPT, NOHDR_OPT, SEP_OPT, USEUNITS_OPT, FIELDS_OPT],
319 9a033156 Iustin Pop
           "", "Lists the nodes in the cluster. The available fields"
320 d8a4b51d Iustin Pop
           " are (see the man page for details): name, pinst_cnt, pinst_list,"
321 d8a4b51d Iustin Pop
           " sinst_cnt, sinst_list, pip, sip, dtotal, dfree, mtotal, mnode,"
322 e8a4c138 Iustin Pop
           " mfree, bootid, cpu_count. The default field list is"
323 48c4dfa8 Iustin Pop
           " (in order): %s." % ", ".join(_LIST_DEF_FIELDS),
324 48c4dfa8 Iustin Pop
           ),
325 a8083063 Iustin Pop
  'remove': (RemoveNode, ARGS_ONE, [DEBUG_OPT],
326 9a033156 Iustin Pop
             "<node_name>", "Removes a node from the cluster"),
327 dcb93971 Michael Hanselmann
  'volumes': (ListVolumes, ARGS_ANY,
328 dcb93971 Michael Hanselmann
              [DEBUG_OPT, NOHDR_OPT, SEP_OPT, USEUNITS_OPT, FIELDS_OPT],
329 9a033156 Iustin Pop
              "[<node_name>...]", "List logical volumes on node(s)"),
330 846baef9 Iustin Pop
  'list-tags': (ListTags, ARGS_ONE, [DEBUG_OPT],
331 9a033156 Iustin Pop
                "<node_name>", "List the tags of the given node"),
332 810c50b7 Iustin Pop
  'add-tags': (AddTags, ARGS_ATLEAST(1), [DEBUG_OPT, TAG_SRC_OPT],
333 9a033156 Iustin Pop
               "<node_name> tag...", "Add tags to the given node"),
334 810c50b7 Iustin Pop
  'remove-tags': (RemoveTags, ARGS_ATLEAST(1), [DEBUG_OPT, TAG_SRC_OPT],
335 9a033156 Iustin Pop
                  "<node_name> tag...", "Remove tags from the given node"),
336 a8083063 Iustin Pop
  }
337 a8083063 Iustin Pop
338 a8083063 Iustin Pop
339 a8083063 Iustin Pop
if __name__ == '__main__':
340 846baef9 Iustin Pop
  sys.exit(GenericMain(commands, override={"tag_type": constants.TAG_NODE}))