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