4 # Copyright (C) 2006, 2007 Google Inc.
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.
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.
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
23 from optparse import make_option
26 from ganeti.cli import *
27 from ganeti import opcodes
28 from ganeti import constants
31 def InitCluster(opts, args):
32 """Initialize the cluster.
35 opts - class with options as members
36 args - list of arguments, expected to be [clustername]
39 op = opcodes.OpInitCluster(cluster_name=args[0],
40 secondary_ip=opts.secondary_ip,
41 hypervisor_type=opts.hypervisor_type,
43 mac_prefix=opts.mac_prefix,
44 def_bridge=opts.def_bridge,
45 master_netdev=opts.master_netdev)
50 def DestroyCluster(opts, args):
51 """Destroy the cluster.
54 opts - class with options as members
57 if not opts.yes_do_it:
58 print ("Destroying a cluster is irreversibly. If you really want destroy"
59 " this cluster, supply the --yes-do-it option.")
62 op = opcodes.OpDestroyCluster()
67 def RenameCluster(opts, args):
68 """Rename the cluster.
71 opts - class with options as members, we use force only
72 args - list of arguments, expected to be [new_name]
77 usertext = ("This will rename the cluster to '%s'. If you are connected"
78 " over the network to the cluster name, the operation is very"
79 " dangerous as the IP address will be removed from the node"
80 " and the change may not go through. Continue?") % name
81 if not AskUser(usertext):
84 op = opcodes.OpRenameCluster(name=name)
89 def ShowClusterVersion(opts, args):
90 """Write version of ganeti software to the standard output.
93 opts - class with options as members
96 op = opcodes.OpQueryClusterInfo()
97 result = SubmitOpCode(op)
98 print ("Software version: %s" % result["software_version"])
99 print ("Internode protocol: %s" % result["protocol_version"])
100 print ("Configuration format: %s" % result["config_version"])
101 print ("OS api version: %s" % result["os_api_version"])
102 print ("Export interface: %s" % result["export_version"])
106 def ShowClusterMaster(opts, args):
107 """Write name of master node to the standard output.
110 opts - class with options as members
113 op = opcodes.OpQueryClusterInfo()
114 result = SubmitOpCode(op)
115 print (result["master"])
119 def ShowClusterConfig(opts, args):
120 """Shows cluster information.
123 op = opcodes.OpQueryClusterInfo()
124 result = SubmitOpCode(op)
126 print ("Cluster name: %s" % result["name"])
128 print ("Master node: %s" % result["master"])
130 print ("Architecture (this node): %s (%s)" %
131 (result["architecture"][0], result["architecture"][1]))
136 def ClusterCopyFile(opts, args):
137 """Copy a file from master to some nodes.
140 opts - class with options as members
141 args - list containing a single element, the file name
143 nodes - list containing the name of target nodes; if empty, all nodes
146 op = opcodes.OpClusterCopyFile(filename=args[0], nodes=opts.nodes)
151 def RunClusterCommand(opts, args):
152 """Run a command on some nodes.
155 opts - class with options as members
156 args - the command list as a list
158 nodes: list containing the name of target nodes; if empty, all nodes
161 command = " ".join(args)
163 op = opcodes.OpRunClusterCommand(command=command, nodes=nodes)
164 result = SubmitOpCode(op)
165 for node, output, exit_code in result:
166 print ("------------------------------------------------")
167 print ("node: %s" % node)
168 print ("%s" % output)
169 print ("return code = %s" % exit_code)
172 def VerifyCluster(opts, args):
173 """Verify integrity of cluster, performing various test on nodes.
176 opts - class with options as members
179 op = opcodes.OpVerifyCluster()
180 result = SubmitOpCode(op)
184 def MasterFailover(opts, args):
185 """Failover the master node.
187 This command, when run on a non-master node, will cause the current
188 master to cease being master, and the non-master to become new
192 op = opcodes.OpMasterFailover()
196 def SearchTags(opts, args):
197 """Searches the tags on all the cluster.
200 op = opcodes.OpSearchTags(pattern=args[0])
201 result = SubmitOpCode(op)
204 result = list(result)
206 for path, tag in result:
207 print "%s %s" % (path, tag)
210 # this is an option common to more than one command, so we declare
211 # it here and reuse it
212 node_option = make_option("-n", "--node", action="append", dest="nodes",
213 help="Node to copy to (if not given, all nodes)"
214 ", can be given multiple times", metavar="<node>",
218 'init': (InitCluster, ARGS_ONE,
220 make_option("-s", "--secondary-ip", dest="secondary_ip",
221 help="Specify the secondary ip for this node;"
222 " if given, the entire cluster must have secondary"
224 metavar="ADDRESS", default=None),
225 make_option("-t", "--hypervisor-type", dest="hypervisor_type",
226 help="Specify the hypervisor type (xen-3.0, fake)",
227 metavar="TYPE", choices=["xen-3.0", "fake"],
229 make_option("-m", "--mac-prefix", dest="mac_prefix",
230 help="Specify the mac prefix for the instance IP"
231 " addresses, in the format XX:XX:XX",
233 default="aa:00:00",),
234 make_option("-g", "--vg-name", dest="vg_name",
235 help="Specify the volume group name "
236 " (cluster-wide) for disk allocation [xenvg]",
239 make_option("-b", "--bridge", dest="def_bridge",
240 help="Specify the default bridge name (cluster-wide)"
241 " to connect the instances to [%s]" %
242 constants.DEFAULT_BRIDGE,
244 default=constants.DEFAULT_BRIDGE,),
245 make_option("--master-netdev", dest="master_netdev",
246 help="Specify the node interface (cluster-wide)"
247 " on which the master IP address will be added "
248 " [%s]" % constants.DEFAULT_BRIDGE,
250 default=constants.DEFAULT_BRIDGE,),
252 "[opts...] <cluster_name>",
253 "Initialises a new cluster configuration"),
254 'destroy': (DestroyCluster, ARGS_NONE,
256 make_option("--yes-do-it", dest="yes_do_it",
257 help="Destroy cluster",
258 action="store_true"),
260 "", "Destroy cluster"),
261 'rename': (RenameCluster, ARGS_ONE, [DEBUG_OPT, FORCE_OPT],
263 "Renames the cluster"),
264 'verify': (VerifyCluster, ARGS_NONE, [DEBUG_OPT],
265 "", "Does a check on the cluster configuration"),
266 'masterfailover': (MasterFailover, ARGS_NONE, [DEBUG_OPT],
267 "", "Makes the current node the master"),
268 'version': (ShowClusterVersion, ARGS_NONE, [DEBUG_OPT],
269 "", "Shows the cluster version"),
270 'getmaster': (ShowClusterMaster, ARGS_NONE, [DEBUG_OPT],
271 "", "Shows the cluster master"),
272 'copyfile': (ClusterCopyFile, ARGS_ONE, [DEBUG_OPT, node_option],
273 "[-n node...] <filename>",
274 "Copies a file to all (or only some) nodes"),
275 'command': (RunClusterCommand, ARGS_ATLEAST(1), [DEBUG_OPT, node_option],
276 "[-n node...] <command>",
277 "Runs a command on all (or only some) nodes"),
278 'info': (ShowClusterConfig, ARGS_NONE, [DEBUG_OPT],
279 "", "Show cluster configuration"),
280 'list-tags': (ListTags, ARGS_NONE,
281 [DEBUG_OPT], "", "List the tags of the cluster"),
282 'add-tags': (AddTags, ARGS_ANY, [DEBUG_OPT, TAG_SRC_OPT],
283 "tag...", "Add tags to the cluster"),
284 'remove-tags': (RemoveTags, ARGS_ANY, [DEBUG_OPT, TAG_SRC_OPT],
285 "tag...", "Remove tags from the cluster"),
286 'search-tags': (SearchTags, ARGS_ONE,
287 [DEBUG_OPT], "", "Searches the tags on all objects on"
288 " the cluster for a given pattern (regex)"),
291 if __name__ == '__main__':
292 sys.exit(GenericMain(commands, override={"tag_type": constants.TAG_CLUSTER}))