Move RAPI constants to ganeti.constants
[ganeti-local] / daemons / ganeti-rapi
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 """ Ganeti Remote API master script.
22 """
23
24 import glob
25 import optparse
26 import sys
27 import os
28
29 from ganeti import constants
30 from ganeti import utils
31 from ganeti.rapi import RESTHTTPServer
32
33
34 def ParseOptions():
35   """Parse the command line options.
36
37   Returns:
38     (options, args) as from OptionParser.parse_args()
39
40   """
41   parser = optparse.OptionParser(description="Ganeti Remote API",
42                     usage="%prog [-d] [-p port]",
43                     version="%%prog (ganeti) %s" %
44                                  constants.RAPI_VERSION)
45   parser.add_option("-d", "--debug", dest="debug",
46                     help="Enable some debug messages",
47                     default=False, action="store_true")
48   parser.add_option("-p", "--port", dest="port",
49                     help="Port to run API (%s default)." %
50                                  constants.RAPI_PORT,
51                     default=constants.RAPI_PORT, type="int")
52   parser.add_option("-S", "--https", dest="ssl",
53                     help="Secure HTTP protocol with SSL",
54                     default=False, action="store_true")
55   parser.add_option("-K", "--ssl-key", dest="ssl_key",
56                     help="SSL key",
57                     default=None, type="string")
58   parser.add_option("-C", "--ssl-cert", dest="ssl_cert",
59                     help="SSL certificate",
60                     default=None, type="string")
61   parser.add_option("-f", "--foreground", dest="fork",
62                     help="Don't detach from the current terminal",
63                     default=True, action="store_false")
64
65   options, args = parser.parse_args()
66
67   if len(args) != 1 or args[0] not in ("start", "stop"):
68     print >> sys.stderr, "Usage: %s [-d] [-p port] start|stop\n" % sys.argv[0]
69     sys.exit(1)
70
71   if options.ssl:
72     if not (options.ssl_cert and options.ssl_key):
73       print >> sys.stderr, ("For secure mode please provide "
74                            "--ssl-key and --ssl-cert arguments")
75       sys.exit(1)
76
77   return options, args
78
79
80 def Port2PID(port):
81   """Map network port to PID.
82
83   Args:
84     port: A port number to map.
85
86   Return:
87     PID number.
88   """
89
90   _NET_STAT = ['/proc/net/tcp', '/proc/net/udp']
91
92   inode2port = {}
93   port2pid = {}
94
95   for file in _NET_STAT:
96     try:
97       try:
98         f = open(file)
99         for line in f.readlines()[1:]:
100           d = line.split()
101           inode2port[long(d[9])] = int(d[1].split(':')[1], 16)
102       finally:
103         f.close()
104     except EnvironmentError:
105       # Nothing can be done
106       pass
107
108   fdlist = glob.glob('/proc/[0-9]*/fd/*')
109   for fd in fdlist:
110     try:
111       pid = int(fd.split('/')[2])
112       inode = long(os.stat(fd)[1])
113       if inode in inode2port:
114         port2pid[inode2port[inode]] = pid
115     except EnvironmentError:
116       # Nothing can be done
117       pass
118
119   if port in port2pid:
120     return port2pid[port]
121   else:
122     return None
123
124
125 def StartAPI(options):
126   """Start the API.
127
128   Args:
129     options: arguments.
130
131   Return:
132     Exit code.
133   """
134   if options.fork:
135     utils.Daemonize(logfile=constants.LOG_RAPISERVER)
136   RESTHTTPServer.start(options)
137
138
139 def StopAPI(options):
140   """Stop the API."""
141   try:
142     pid = Port2PID(options.port)
143     if pid:
144       print ("Stopping Ganeti-RAPI PID: %d, port: %d... "
145              % (pid, options.port)),
146       os.kill(pid, 9)
147       print "done."
148     else:
149       print >> sys.stderr, "Unable to locate running Ganeti-RAPI on port: %d" \
150           % options.port
151
152   except Exception, ex:
153     print >> sys.stderr, ex
154     return 1
155   return 0
156
157
158 def main():
159   """Main function.
160
161   """
162   result = 1
163   options, args = ParseOptions()
164   if args[0] == "start":
165     result = StartAPI(options)
166   else:
167     result = StopAPI(options)
168   sys.exit(result)
169
170
171 if __name__ == '__main__':
172   main()