root / daemons / ganeti-master @ ebe8ef17
History | View | Annotate | Download (5.1 kB)
1 | 880478f8 | Iustin Pop | #!/usr/bin/python |
---|---|---|---|
2 | 880478f8 | Iustin Pop | # |
3 | 880478f8 | Iustin Pop | |
4 | 880478f8 | Iustin Pop | # Copyright (C) 2006, 2007 Google Inc. |
5 | 880478f8 | Iustin Pop | # |
6 | 880478f8 | Iustin Pop | # This program is free software; you can redistribute it and/or modify |
7 | 880478f8 | Iustin Pop | # it under the terms of the GNU General Public License as published by |
8 | 880478f8 | Iustin Pop | # the Free Software Foundation; either version 2 of the License, or |
9 | 880478f8 | Iustin Pop | # (at your option) any later version. |
10 | 880478f8 | Iustin Pop | # |
11 | 880478f8 | Iustin Pop | # This program is distributed in the hope that it will be useful, but |
12 | 880478f8 | Iustin Pop | # WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | 880478f8 | Iustin Pop | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
14 | 880478f8 | Iustin Pop | # General Public License for more details. |
15 | 880478f8 | Iustin Pop | # |
16 | 880478f8 | Iustin Pop | # You should have received a copy of the GNU General Public License |
17 | 880478f8 | Iustin Pop | # along with this program; if not, write to the Free Software |
18 | 880478f8 | Iustin Pop | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
19 | 880478f8 | Iustin Pop | # 02110-1301, USA. |
20 | 880478f8 | Iustin Pop | |
21 | 880478f8 | Iustin Pop | |
22 | 880478f8 | Iustin Pop | """Ganeti master script |
23 | 880478f8 | Iustin Pop | |
24 | 880478f8 | Iustin Pop | Exit codes, for both start and stop: |
25 | 880478f8 | Iustin Pop | - 0: master setup successful |
26 | 880478f8 | Iustin Pop | - 1: some generic error (this exit code can also be thrown by exceptions) |
27 | 880478f8 | Iustin Pop | - 11: node is not master, nothing to do |
28 | 880478f8 | Iustin Pop | - 12: node setup incomplete, cannot start |
29 | 880478f8 | Iustin Pop | - 13: node should be master, but someone has the ip address already |
30 | 880478f8 | Iustin Pop | |
31 | 880478f8 | Iustin Pop | Only exit codes 0 and 11 represent an ok state. Code 1 was left for |
32 | 880478f8 | Iustin Pop | generic errors as other python code can cause exit with code 1. |
33 | 880478f8 | Iustin Pop | |
34 | 880478f8 | Iustin Pop | """ |
35 | 880478f8 | Iustin Pop | |
36 | 880478f8 | Iustin Pop | import os |
37 | 880478f8 | Iustin Pop | import sys |
38 | 880478f8 | Iustin Pop | |
39 | 880478f8 | Iustin Pop | from optparse import OptionParser |
40 | 880478f8 | Iustin Pop | |
41 | 880478f8 | Iustin Pop | from ganeti import constants |
42 | 880478f8 | Iustin Pop | from ganeti import errors |
43 | 880478f8 | Iustin Pop | from ganeti import ssconf |
44 | 880478f8 | Iustin Pop | from ganeti import utils |
45 | 880478f8 | Iustin Pop | |
46 | 880478f8 | Iustin Pop | EXIT_OK = 0 |
47 | 880478f8 | Iustin Pop | EXIT_SOME_ERROR = 1 |
48 | 38242904 | Iustin Pop | EXIT_NOTMASTER = constants.EXIT_NOTMASTER |
49 | 619fdc8e | Iustin Pop | EXIT_NODESETUP_ERROR = constants.EXIT_NODESETUP_ERROR |
50 | 880478f8 | Iustin Pop | EXIT_DUPLICATE_IP = 13 |
51 | 880478f8 | Iustin Pop | EXIT_ARGS_ERROR = 14 |
52 | 880478f8 | Iustin Pop | |
53 | 880478f8 | Iustin Pop | |
54 | 880478f8 | Iustin Pop | def ParseOptions(): |
55 | 880478f8 | Iustin Pop | """Parse the command line options. |
56 | 880478f8 | Iustin Pop | |
57 | 880478f8 | Iustin Pop | Returns: |
58 | 880478f8 | Iustin Pop | (options, args) as from OptionParser.parse_args() |
59 | 880478f8 | Iustin Pop | |
60 | 880478f8 | Iustin Pop | """ |
61 | 880478f8 | Iustin Pop | parser = OptionParser(description="Ganeti master", |
62 | 880478f8 | Iustin Pop | usage="%prog [-d]", |
63 | 880478f8 | Iustin Pop | version="%%prog (ganeti) %s" % |
64 | 880478f8 | Iustin Pop | constants.RELEASE_VERSION) |
65 | 880478f8 | Iustin Pop | |
66 | 880478f8 | Iustin Pop | parser.add_option("-d", "--debug", dest="debug", |
67 | 880478f8 | Iustin Pop | help="Enable some debug messages", |
68 | 880478f8 | Iustin Pop | default=False, action="store_true") |
69 | 880478f8 | Iustin Pop | options, args = parser.parse_args() |
70 | 880478f8 | Iustin Pop | |
71 | 880478f8 | Iustin Pop | if len(args) != 1 or args[0] not in ("start", "stop"): |
72 | 880478f8 | Iustin Pop | sys.stderr.write("Usage: %s [-d] start|stop\n" % sys.argv[0]) |
73 | 880478f8 | Iustin Pop | sys.exit(EXIT_ARGS_ERROR) |
74 | 880478f8 | Iustin Pop | |
75 | 880478f8 | Iustin Pop | return options, args |
76 | 880478f8 | Iustin Pop | |
77 | 880478f8 | Iustin Pop | |
78 | 880478f8 | Iustin Pop | def CheckNodeSetup(debug): |
79 | 880478f8 | Iustin Pop | """Checks the node setup. |
80 | 880478f8 | Iustin Pop | |
81 | 880478f8 | Iustin Pop | If the node setup if ok, this function will return the tuple |
82 | 880478f8 | Iustin Pop | (master_hostname, master_netdev, master_ip). Otherwise the return |
83 | 880478f8 | Iustin Pop | value will be None. |
84 | 880478f8 | Iustin Pop | |
85 | 880478f8 | Iustin Pop | """ |
86 | 880478f8 | Iustin Pop | for fname in (constants.SSL_CERT_FILE,): |
87 | 880478f8 | Iustin Pop | if not os.path.isfile(fname): |
88 | 880478f8 | Iustin Pop | if debug: |
89 | 880478f8 | Iustin Pop | sys.stderr.write("Missing config file %s.\n" % fname) |
90 | 880478f8 | Iustin Pop | return None |
91 | 880478f8 | Iustin Pop | try: |
92 | 880478f8 | Iustin Pop | ss = ssconf.SimpleStore() |
93 | 880478f8 | Iustin Pop | port = ss.GetNodeDaemonPort() |
94 | 880478f8 | Iustin Pop | pwdata = ss.GetNodeDaemonPassword() |
95 | 880478f8 | Iustin Pop | master_name = ss.GetMasterNode() |
96 | 880478f8 | Iustin Pop | master_netdev = ss.GetMasterNetdev() |
97 | 880478f8 | Iustin Pop | master_ip = ss.GetMasterIP() |
98 | 880478f8 | Iustin Pop | except errors.ConfigurationError, err: |
99 | 880478f8 | Iustin Pop | if debug: |
100 | 880478f8 | Iustin Pop | sys.stderr.write("Cluster configuration incomplete: '%s'\n" % str(err)) |
101 | 880478f8 | Iustin Pop | return None |
102 | 880478f8 | Iustin Pop | return (master_name, master_netdev, master_ip) |
103 | 880478f8 | Iustin Pop | |
104 | 880478f8 | Iustin Pop | |
105 | 880478f8 | Iustin Pop | def StartMaster(master_netdev, master_ip, debug): |
106 | 880478f8 | Iustin Pop | """Starts the master. |
107 | 880478f8 | Iustin Pop | |
108 | 880478f8 | Iustin Pop | """ |
109 | 16abfbc2 | Alexander Schreiber | if utils.TcpPing(utils.HostInfo().name, master_ip, |
110 | 16abfbc2 | Alexander Schreiber | constants.DEFAULT_NODED_PORT): |
111 | 16abfbc2 | Alexander Schreiber | if utils.TcpPing(constants.LOCALHOST_IP_ADDRESS, master_ip, |
112 | 16abfbc2 | Alexander Schreiber | constants.DEFAULT_NODED_PORT): |
113 | 880478f8 | Iustin Pop | # we already have the ip: |
114 | 880478f8 | Iustin Pop | if debug: |
115 | 880478f8 | Iustin Pop | sys.stderr.write("Notice: already started.\n") |
116 | 880478f8 | Iustin Pop | return EXIT_OK |
117 | 880478f8 | Iustin Pop | else: |
118 | 880478f8 | Iustin Pop | return EXIT_DUPLICATE_IP |
119 | 880478f8 | Iustin Pop | result = utils.RunCmd(["ip", "address", "add", "%s/32" % master_ip, |
120 | 880478f8 | Iustin Pop | "dev", master_netdev, "label", |
121 | 880478f8 | Iustin Pop | "%s:0" % master_netdev]) |
122 | 880478f8 | Iustin Pop | if result.failed: |
123 | 880478f8 | Iustin Pop | if debug: |
124 | 880478f8 | Iustin Pop | sys.stderr.write("Can't activate master IP: %s\n" % result.output) |
125 | 880478f8 | Iustin Pop | return EXIT_SOME_ERROR |
126 | 880478f8 | Iustin Pop | |
127 | 880478f8 | Iustin Pop | result = utils.RunCmd(["arping", "-q", "-U", "-c 3", "-I", master_netdev, |
128 | 880478f8 | Iustin Pop | "-s", master_ip, master_ip]) |
129 | 880478f8 | Iustin Pop | # we'll ignore the exit code of arping |
130 | 880478f8 | Iustin Pop | return EXIT_OK |
131 | 880478f8 | Iustin Pop | |
132 | 880478f8 | Iustin Pop | |
133 | 880478f8 | Iustin Pop | def StopMaster(master_netdev, master_ip, debug): |
134 | 880478f8 | Iustin Pop | """Stops the master. |
135 | 880478f8 | Iustin Pop | |
136 | 880478f8 | Iustin Pop | """ |
137 | 880478f8 | Iustin Pop | result = utils.RunCmd(["ip", "address", "del", "%s/32" % master_ip, |
138 | 880478f8 | Iustin Pop | "dev", master_netdev]) |
139 | 880478f8 | Iustin Pop | if result.failed: |
140 | 880478f8 | Iustin Pop | if debug: |
141 | 880478f8 | Iustin Pop | sys.stderr.write("Can't remove the master IP, error: %s" % result.output) |
142 | 880478f8 | Iustin Pop | # but otherwise ignore the failure |
143 | 880478f8 | Iustin Pop | return EXIT_OK |
144 | 880478f8 | Iustin Pop | |
145 | 880478f8 | Iustin Pop | |
146 | 880478f8 | Iustin Pop | def main(): |
147 | 880478f8 | Iustin Pop | """Main function. |
148 | 880478f8 | Iustin Pop | |
149 | 880478f8 | Iustin Pop | """ |
150 | 880478f8 | Iustin Pop | options, args = ParseOptions() |
151 | 880478f8 | Iustin Pop | debug = options.debug |
152 | 89e1fc26 | Iustin Pop | try: |
153 | 89e1fc26 | Iustin Pop | myself = utils.HostInfo() |
154 | 89e1fc26 | Iustin Pop | except errors.ResolverError, err: |
155 | 89e1fc26 | Iustin Pop | sys.stderr.write("Cannot resolve my own name (%s)\n" % err.args[0]) |
156 | 89e1fc26 | Iustin Pop | return EXIT_NODESETUP_ERROR |
157 | 89e1fc26 | Iustin Pop | |
158 | 880478f8 | Iustin Pop | result = CheckNodeSetup(debug) |
159 | 880478f8 | Iustin Pop | if not result: |
160 | 880478f8 | Iustin Pop | if debug: |
161 | 880478f8 | Iustin Pop | sys.stderr.write("Node configuration incomplete.\n") |
162 | 880478f8 | Iustin Pop | return EXIT_NODESETUP_ERROR |
163 | 880478f8 | Iustin Pop | |
164 | 880478f8 | Iustin Pop | master_node, master_netdev, master_ip = result |
165 | 89e1fc26 | Iustin Pop | if myself.name != master_node and args[0] == "start": |
166 | 880478f8 | Iustin Pop | if debug: |
167 | 880478f8 | Iustin Pop | sys.stderr.write("Not master, ignoring request.\n") |
168 | 880478f8 | Iustin Pop | return EXIT_NOTMASTER |
169 | 880478f8 | Iustin Pop | |
170 | 880478f8 | Iustin Pop | if args[0] == "start": |
171 | 880478f8 | Iustin Pop | fn = StartMaster |
172 | 880478f8 | Iustin Pop | else: |
173 | 880478f8 | Iustin Pop | fn = StopMaster |
174 | 880478f8 | Iustin Pop | |
175 | 3ecf6786 | Iustin Pop | result = fn(master_netdev, master_ip, debug) |
176 | 3ecf6786 | Iustin Pop | sys.exit(result) |
177 | 880478f8 | Iustin Pop | |
178 | 880478f8 | Iustin Pop | |
179 | 3ecf6786 | Iustin Pop | if __name__ == '__main__': |
180 | 3ecf6786 | Iustin Pop | main() |