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