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
22 """Ganeti master script
24 Exit codes, for both start and stop:
25 - 0: master setup successful
26 - 1: some generic error (this exit code can also be thrown by exceptions)
27 - 11: node is not master, nothing to do
28 - 12: node setup incomplete, cannot start
29 - 13: node should be master, but someone has the ip address already
31 Only exit codes 0 and 11 represent an ok state. Code 1 was left for
32 generic errors as other python code can cause exit with code 1.
39 from optparse import OptionParser
41 from ganeti import constants
42 from ganeti import errors
43 from ganeti import ssconf
44 from ganeti import utils
48 EXIT_NOTMASTER = constants.EXIT_NOTMASTER
49 EXIT_NODESETUP_ERROR = constants.EXIT_NODESETUP_ERROR
50 EXIT_DUPLICATE_IP = 13
55 """Parse the command line options.
58 (options, args) as from OptionParser.parse_args()
61 parser = OptionParser(description="Ganeti master",
63 version="%%prog (ganeti) %s" %
64 constants.RELEASE_VERSION)
66 parser.add_option("-d", "--debug", dest="debug",
67 help="Enable some debug messages",
68 default=False, action="store_true")
69 options, args = parser.parse_args()
71 if len(args) != 1 or args[0] not in ("start", "stop"):
72 sys.stderr.write("Usage: %s [-d] start|stop\n" % sys.argv[0])
73 sys.exit(EXIT_ARGS_ERROR)
78 def CheckNodeSetup(debug):
79 """Checks the node setup.
81 If the node setup if ok, this function will return the tuple
82 (master_hostname, master_netdev, master_ip). Otherwise the return
86 for fname in (constants.SSL_CERT_FILE,):
87 if not os.path.isfile(fname):
89 sys.stderr.write("Missing config file %s.\n" % fname)
92 ss = ssconf.SimpleStore()
93 port = ss.GetNodeDaemonPort()
94 pwdata = ss.GetNodeDaemonPassword()
95 master_name = ss.GetMasterNode()
96 master_netdev = ss.GetMasterNetdev()
97 master_ip = ss.GetMasterIP()
98 except errors.ConfigurationError, err:
100 sys.stderr.write("Cluster configuration incomplete: '%s'\n" % str(err))
102 return (master_name, master_netdev, master_ip)
105 def StartMaster(master_netdev, master_ip, debug):
106 """Starts the master.
109 if utils.TcpPing(master_ip, constants.DEFAULT_NODED_PORT):
110 if utils.TcpPing(master_ip, constants.DEFAULT_NODED_PORT,
111 source=constants.LOCALHOST_IP_ADDRESS):
112 # we already have the ip:
114 sys.stderr.write("Notice: already started.\n")
117 return EXIT_DUPLICATE_IP
119 result = utils.RunCmd(["ip", "address", "add", "%s/32" % master_ip,
120 "dev", master_netdev, "label",
121 "%s:0" % master_netdev])
124 sys.stderr.write("Can't activate master IP: %s\n" % result.output)
125 return EXIT_SOME_ERROR
127 result = utils.RunCmd(["arping", "-q", "-U", "-c 3", "-I", master_netdev,
128 "-s", master_ip, master_ip])
129 # we'll ignore the exit code of arping
131 if constants.RAPI_ENABLE:
133 result = utils.RunCmd(["ganeti-rapi", "--port=%s" % constants.RAPI_PORT])
134 if debug and result.failed:
135 sys.stderr.write("Failed to start ganeti-rapi, error: %s\n" %
141 def StopMaster(master_netdev, master_ip, debug):
145 if constants.RAPI_ENABLE:
147 result = utils.RunCmd(["fuser", "-k", "-n", "tcp",
148 str(constants.RAPI_PORT)])
149 if debug and result.failed:
150 sys.stderr.write("Failed to stop ganeti-rapi, error: %s\n" %
153 result = utils.RunCmd(["ip", "address", "del", "%s/32" % master_ip,
154 "dev", master_netdev])
157 sys.stderr.write("Can't remove the master IP, error: %s" % result.output)
158 # but otherwise ignore the failure
167 options, args = ParseOptions()
168 debug = options.debug
170 myself = utils.HostInfo()
171 except errors.ResolverError, err:
172 sys.stderr.write("Cannot resolve my own name (%s)\n" % err.args[0])
173 return EXIT_NODESETUP_ERROR
175 result = CheckNodeSetup(debug)
178 sys.stderr.write("Node configuration incomplete.\n")
179 return EXIT_NODESETUP_ERROR
181 master_node, master_netdev, master_ip = result
182 if myself.name != master_node and args[0] == "start":
184 sys.stderr.write("Not master, ignoring request.\n")
185 return EXIT_NOTMASTER
187 if args[0] == "start":
192 result = fn(master_netdev, master_ip, debug)
196 if __name__ == '__main__':