Statistics
| Branch: | Tag: | Revision:

root / daemons / ganeti-master @ eee1fa2d

History | View | Annotate | Download (5.1 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

    
39
from optparse import OptionParser
40

    
41
from ganeti import constants
42
from ganeti import errors
43
from ganeti import ssconf
44
from ganeti import utils
45

    
46
EXIT_OK = 0
47
EXIT_SOME_ERROR = 1
48
EXIT_NOTMASTER = constants.EXIT_NOTMASTER
49
EXIT_NODESETUP_ERROR = constants.EXIT_NODESETUP_ERROR
50
EXIT_DUPLICATE_IP = 13
51
EXIT_ARGS_ERROR = 14
52

    
53

    
54
def ParseOptions():
55
  """Parse the command line options.
56

    
57
  Returns:
58
    (options, args) as from OptionParser.parse_args()
59

    
60
  """
61
  parser = OptionParser(description="Ganeti master",
62
                        usage="%prog [-d]",
63
                        version="%%prog (ganeti) %s" %
64
                        constants.RELEASE_VERSION)
65

    
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()
70

    
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)
74

    
75
  return options, args
76

    
77

    
78
def CheckNodeSetup(debug):
79
  """Checks the node setup.
80

    
81
  If the node setup if ok, this function will return the tuple
82
  (master_hostname, master_netdev, master_ip). Otherwise the return
83
  value will be None.
84

    
85
  """
86
  for fname in (constants.SSL_CERT_FILE,):
87
    if not os.path.isfile(fname):
88
      if debug:
89
        sys.stderr.write("Missing config file %s.\n" % fname)
90
      return None
91
  try:
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:
99
    if debug:
100
      sys.stderr.write("Cluster configuration incomplete: '%s'\n" % str(err))
101
    return None
102
  return (master_name, master_netdev, master_ip)
103

    
104

    
105
def StartMaster(master_netdev, master_ip, debug):
106
  """Starts the master.
107

    
108
  """
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:
113
      if debug:
114
        sys.stderr.write("Notice: already started.\n")
115
      return EXIT_OK
116
    else:
117
      return EXIT_DUPLICATE_IP
118
  result = utils.RunCmd(["ip", "address", "add", "%s/32" % master_ip,
119
                         "dev", master_netdev, "label",
120
                         "%s:0" % master_netdev])
121
  if result.failed:
122
    if debug:
123
      sys.stderr.write("Can't activate master IP: %s\n" % result.output)
124
    return EXIT_SOME_ERROR
125

    
126
  result = utils.RunCmd(["arping", "-q", "-U", "-c 3", "-I", master_netdev,
127
                         "-s", master_ip, master_ip])
128
  # we'll ignore the exit code of arping
129
  return EXIT_OK
130

    
131

    
132
def StopMaster(master_netdev, master_ip, debug):
133
  """Stops the master.
134

    
135
  """
136
  result = utils.RunCmd(["ip", "address", "del", "%s/32" % master_ip,
137
                         "dev", master_netdev])
138
  if result.failed:
139
    if debug:
140
      sys.stderr.write("Can't remove the master IP, error: %s" % result.output)
141
    # but otherwise ignore the failure
142
  return EXIT_OK
143

    
144

    
145
def main():
146
  """Main function.
147

    
148
  """
149
  options, args = ParseOptions()
150
  debug = options.debug
151
  try:
152
    myself = utils.HostInfo()
153
  except errors.ResolverError, err:
154
    sys.stderr.write("Cannot resolve my own name (%s)\n" % err.args[0])
155
    return EXIT_NODESETUP_ERROR
156

    
157
  result = CheckNodeSetup(debug)
158
  if not result:
159
    if debug:
160
      sys.stderr.write("Node configuration incomplete.\n")
161
    return EXIT_NODESETUP_ERROR
162

    
163
  master_node, master_netdev, master_ip = result
164
  if myself.name != master_node and args[0] == "start":
165
    if debug:
166
      sys.stderr.write("Not master, ignoring request.\n")
167
    return EXIT_NOTMASTER
168

    
169
  if args[0] == "start":
170
    fn = StartMaster
171
  else:
172
    fn = StopMaster
173

    
174
  result = fn(master_netdev, master_ip, debug)
175
  sys.exit(result)
176

    
177

    
178
if __name__ == '__main__':
179
  main()