root / daemons / ganeti-master @ 880478f8
History | View | Annotate | Download (4.9 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 |
"""Ganeti master script |
23 |
|
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 |
30 |
|
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. |
33 |
|
34 |
""" |
35 |
|
36 |
import os |
37 |
import sys |
38 |
import socket |
39 |
|
40 |
from optparse import OptionParser |
41 |
|
42 |
from ganeti import logger |
43 |
from ganeti import constants |
44 |
from ganeti import errors |
45 |
from ganeti import ssconf |
46 |
from ganeti import utils |
47 |
|
48 |
EXIT_OK = 0 |
49 |
EXIT_SOME_ERROR = 1 |
50 |
EXIT_NOTMASTER = 11 |
51 |
EXIT_NODESETUP_ERROR = 12 |
52 |
EXIT_DUPLICATE_IP = 13 |
53 |
EXIT_ARGS_ERROR = 14 |
54 |
|
55 |
|
56 |
def ParseOptions(): |
57 |
"""Parse the command line options. |
58 |
|
59 |
Returns: |
60 |
(options, args) as from OptionParser.parse_args() |
61 |
|
62 |
""" |
63 |
parser = OptionParser(description="Ganeti master", |
64 |
usage="%prog [-d]", |
65 |
version="%%prog (ganeti) %s" % |
66 |
constants.RELEASE_VERSION) |
67 |
|
68 |
parser.add_option("-d", "--debug", dest="debug", |
69 |
help="Enable some debug messages", |
70 |
default=False, action="store_true") |
71 |
options, args = parser.parse_args() |
72 |
|
73 |
if len(args) != 1 or args[0] not in ("start", "stop"): |
74 |
sys.stderr.write("Usage: %s [-d] start|stop\n" % sys.argv[0]) |
75 |
sys.exit(EXIT_ARGS_ERROR) |
76 |
|
77 |
return options, args |
78 |
|
79 |
|
80 |
def CheckNodeSetup(debug): |
81 |
"""Checks the node setup. |
82 |
|
83 |
If the node setup if ok, this function will return the tuple |
84 |
(master_hostname, master_netdev, master_ip). Otherwise the return |
85 |
value will be None. |
86 |
|
87 |
""" |
88 |
for fname in (constants.SSL_CERT_FILE,): |
89 |
if not os.path.isfile(fname): |
90 |
if debug: |
91 |
sys.stderr.write("Missing config file %s.\n" % fname) |
92 |
return None |
93 |
try: |
94 |
ss = ssconf.SimpleStore() |
95 |
port = ss.GetNodeDaemonPort() |
96 |
pwdata = ss.GetNodeDaemonPassword() |
97 |
master_name = ss.GetMasterNode() |
98 |
master_netdev = ss.GetMasterNetdev() |
99 |
master_ip = ss.GetMasterIP() |
100 |
except errors.ConfigurationError, err: |
101 |
if debug: |
102 |
sys.stderr.write("Cluster configuration incomplete: '%s'\n" % str(err)) |
103 |
return None |
104 |
return (master_name, master_netdev, master_ip) |
105 |
|
106 |
|
107 |
def StartMaster(master_netdev, master_ip, debug): |
108 |
"""Starts the master. |
109 |
|
110 |
""" |
111 |
result = utils.RunCmd(["fping", "-q", master_ip]) |
112 |
if not result.failed: |
113 |
r2 = utils.RunCmd(["fping", "-q", "-S127.0.0.1", master_ip]) |
114 |
if not result.failed: |
115 |
# we already have the ip: |
116 |
if debug: |
117 |
sys.stderr.write("Notice: already started.\n") |
118 |
return EXIT_OK |
119 |
else: |
120 |
return EXIT_DUPLICATE_IP |
121 |
result = utils.RunCmd(["ip", "address", "add", "%s/32" % master_ip, |
122 |
"dev", master_netdev, "label", |
123 |
"%s:0" % master_netdev]) |
124 |
if result.failed: |
125 |
if debug: |
126 |
sys.stderr.write("Can't activate master IP: %s\n" % result.output) |
127 |
return EXIT_SOME_ERROR |
128 |
|
129 |
result = utils.RunCmd(["arping", "-q", "-U", "-c 3", "-I", master_netdev, |
130 |
"-s", master_ip, master_ip]) |
131 |
# we'll ignore the exit code of arping |
132 |
return EXIT_OK |
133 |
|
134 |
|
135 |
def StopMaster(master_netdev, master_ip, debug): |
136 |
"""Stops the master. |
137 |
|
138 |
""" |
139 |
result = utils.RunCmd(["ip", "address", "del", "%s/32" % master_ip, |
140 |
"dev", master_netdev]) |
141 |
if result.failed: |
142 |
if debug: |
143 |
sys.stderr.write("Can't remove the master IP, error: %s" % result.output) |
144 |
# but otherwise ignore the failure |
145 |
return EXIT_OK |
146 |
|
147 |
|
148 |
def main(): |
149 |
"""Main function. |
150 |
|
151 |
""" |
152 |
options, args = ParseOptions() |
153 |
debug = options.debug |
154 |
result = CheckNodeSetup(debug) |
155 |
if not result: |
156 |
if debug: |
157 |
sys.stderr.write("Node configuration incomplete.\n") |
158 |
return EXIT_NODESETUP_ERROR |
159 |
|
160 |
master_node, master_netdev, master_ip = result |
161 |
if socket.gethostname() != master_node and args[0] == "start": |
162 |
if debug: |
163 |
sys.stderr.write("Not master, ignoring request.\n") |
164 |
return EXIT_NOTMASTER |
165 |
|
166 |
if args[0] == "start": |
167 |
fn = StartMaster |
168 |
else: |
169 |
fn = StopMaster |
170 |
|
171 |
return fn(master_netdev, master_ip, debug) |
172 |
|
173 |
|
174 |
if __name__=='__main__': |
175 |
exit_code = main() |
176 |
sys.exit(exit_code) |