1 """
2 The LDBDServer module provides an API for responding to request from the
3 LDBDClient by connecting to the DB2 database.
4
5 This module requires U{pyGlobus<http://www-itg.lbl.gov/gtg/projects/pyGlobus/>}.
6
7
8 This file is part of the Grid LSC User Environment (GLUE)
9
10 GLUE is free software: you can redistribute it and/or modify it under the
11 terms of the GNU General Public License as published by the Free Software
12 Foundation, either version 3 of the License, or (at your option) any later
13 version.
14
15 This program is distributed in the hope that it will be useful, but WITHOUT
16 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
18 details.
19
20 You should have received a copy of the GNU General Public License along with
21 this program. If not, see <http://www.gnu.org/licenses/>.
22 """
23
24 from glue import git_version
25 __date__ = git_version.date
26 __version__ = git_version.id
27
28 import os
29 import sys
30 import re
31 import types
32 try:
33 import pyRXP
34 except ImportError:
35 import pyRXPU as pyRXP
36 import socket
37 import six.moves.socketserver
38 import six.moves.cPickle
39 from glue import ldbd
40 try:
41 import rlsClient
42 except:
43 pass
44
45
47 if uri == 'http://ldas-sw.ligo.caltech.edu/doc/ligolwAPI/html/ligolw_dtd.txt':
48
49
50 return 'file://localhost' + os.path.join( os.environ["GLUE_PREFIX"],
51 'etc/ligolw_dtd.txt' )
52 else:
53
54 return uri
55
57
58 global logger, max_bytes, xmlparser, dbobj, rls
59 global dmt_proc_dict, dmt_seg_def_dict, creator_db
60 global ldbd_com, db2_com, port
61
62
63 logger = log
64 logger.info("Initializing server module %s" % __name__ )
65
66
67 dbobj = ldbd.LIGOMetadataDatabase(configuration['dbname'])
68 max_bytes = configuration['max_client_byte_string']
69
70
71 port = configuration['port']
72 ldbd_com = configuration['ldbd_com'].split(',')
73 db2_com = configuration['db2_com'].split(',')
74
75
76 xmlparser = pyRXP.Parser()
77
78
79 try:
80 GLUE_PREFIX = os.environ["GLUE_PREFIX"]
81 xmlparser.eoCB = dtd_uri_callback
82 logger.info("Using local DTD in " +
83 'file://localhost' + os.path.join( GLUE_PREFIX, 'etc') )
84 except KeyError:
85 logger.warning('GLUE_PREFIX not set, unable to use local DTD')
86
87
88 rls_server = configuration['rls']
89 cert = configuration['certfile']
90 key = configuration['keyfile']
91 try:
92 rls = rlsClient.RlsClient(rls_server,cert,key)
93 except:
94 rls = None
95
96
97 dmt_proc_dict = {}
98 dmt_seg_def_dict = {}
99 creator_db = None
100
102 global logger, max_bytes, xmlparser, dbobj, rls
103 global dmt_proc_dict, dmt_seg_def_dict
104 logger.info("Shutting down server module %s" % __name__ )
105 if rls:
106 del rls
107 del xmlparser
108 del dbobj
109 del dmt_proc_dict
110 del dmt_seg_def_dict
111
113 """
114 Class representing exceptions within the ServerHandler class.
115 """
117 """
118 Initialize an instance.
119
120 @param args:
121
122 @return: Instance of class ServerHandlerException
123 """
124 self.args = args
125
127 """
128 An instance of this class is created to service each request of the server.
129 """
131 """
132 This method does all the work of servicing a request to the server. See
133 the documentation for the standard module SocketServer.
134
135 The input from the socket is parsed for the method with the remaining
136 strings stripped of null bytes passed to the method in a list.
137
138 There are no parameters. When the instance of the class is created to
139 process the request all necessary information is made attributes of the
140 class instance.
141
142 @return: None
143 """
144 global logger
145 global max_bytes
146
147 logger.debug("handle method of %s class called" % __name__)
148
149
150 methodDict = {
151 'PING' : self.ping,
152 'QUERY' : self.query,
153 'INSERT' : self.insert,
154 'INSERTMAP' : self.insertmap,
155 'INSERTDMT' : self.insertdmt
156 }
157
158 if True:
159
160 self.sfile = self.request.makefile("rw")
161 f = self.sfile
162
163
164 input = f.read(size=max_bytes,waitForBytes=2)
165
166
167 while input[-1] != '\0':
168 input += f.read(size=max_bytes,waitForBytes=2)
169
170
171
172
173
174
175 if input[-1] != '\0':
176 logger.error("Bad input on socket: %s" % input)
177 raise ServerHandlerException("Last byte of input is not null byte")
178
179
180
181
182 try:
183
184 stringList = input.split('\0')
185 methodString = stringList[0]
186 argStringList = stringList[1:-1]
187
188 except Exception as e:
189 logger.error("Error parsing method and argument string: %s" % e)
190
191 msg = "ERROR LDBDServer Error: " + \
192 "Error parsing method and argument string: %s" % e
193 self.__reply__(1, msg)
194 return
195
196
197 try:
198
199 if methodString in ldbd_com:
200 pass
201 else:
202 msg = '\nTo %s, authorized user please switch to the Apache driven ldbd server through ' % methodString
203 msg += '\nsecure connection by specifying procotol "https" in your --segment-url argument'
204 msg += '\nFor example, "--segment-url https://segdb.ligo.caltech.edu"'
205 logger.error(msg)
206 self.__reply__(1,msg)
207 raise ServerHandlerException(msg)
208
209 if methodString=='QUERY':
210
211
212 dbcommand = argStringList[0].split(' ')[0].upper()
213 if dbcommand in db2_com:
214 pass
215 else:
216 msg = 'ldbd server on port %d DO NOT support "%s"' % (port, dbcommand)
217 logger.error(msg)
218 self.__reply__(1,msg)
219 raise ServerHandlerException(msg)
220 except Exception as e:
221 logger.error("Error filtering allowed commands: %s" % e)
222 return
223
224
225 try:
226
227 method = methodDict[methodString]
228 except Exception as e:
229 msg = "Error converting method string %s to method call: %s" % \
230 (methodString, e)
231 logger.error(msg)
232
233 self.__reply__(1, msg)
234 return
235
236 try:
237
238 result = method(argStringList)
239 self.__reply__( result[0], result[1] )
240 except Exception as e:
241 logger.error("Error while calling method %s: %s" % (methodString, e))
242
243 return
244
246 """
247 Format and send a reply back down the socket to the client. The file
248 representing the socket is closed at the end of this method.
249
250 @param code: integer representing the error code with 0 for success
251
252 @param msg: object to be passed back to the client, either a string
253 or a list of items that can be represented by strings
254
255 @return: None
256 """
257 f = self.sfile
258 reply = "%d\0%s\0" % (code, msg)
259 f.write(reply)
260
261
262 f.close()
263
264 - def ping(self, arg):
265 """
266 Bounce back alive statment. Corresponds to the PING method in the
267 ldbdd RPC protocol.
268
269 @param arg: list (perhaps empty) of strings representing message sent
270 by client to server
271
272 @return: None
273 """
274 global logger
275
276 logger.debug("Method ping called")
277 try:
278 hostname = socket.getfqdn()
279 msg = "%s at %s is alive" % (__name__, hostname)
280 except Exception as e:
281 msg = "%s is alive" % __name__
282
283 return (0, msg)
284
286 """
287 Execute an SQL query on the database and return the result as LIGO_LW XML
288
289 @param arg: a text string containing an SQL query to be executed
290
291 @return: None
292 """
293 global logger
294 global xmlparser, dbobj
295
296
297 querystr = arg[0]
298 logger.debug("Method query called with %s" % querystr)
299
300
301 code = 1
302
303 try:
304
305 lwtparser = ldbd.LIGOLwParser()
306 ligomd = ldbd.LIGOMetadata(xmlparser,lwtparser,dbobj)
307
308
309 rowcount = ligomd.select(querystr)
310
311
312 result = ligomd.xml()
313
314 logger.debug("Method query: %d rows returned" % rowcount)
315 code = 0
316 except Exception as e:
317 result = ("Error querying metadata database: %s" % e)
318 logger.error(result)
319
320 try:
321 del ligomd
322 del lwtparser
323 except Exception as e:
324 logger.error(
325 "Error deleting metadata object in method query: %s" % e)
326
327 return (code,result)
328
330 msg = '\nTo INSERT, authorized user please switch to the Apache driven ldbd server through '
331 msg += '\nsecure connection by specifying procotol "https" in your --segment-url argument'
332 msg += '\nFor example, "--segment-url https://segdb.ligo.caltech.edu"'
333 logger.error(msg)
334 return (1, msg)
335
336
338 msg = '\nTo INSERTMAP, authorized user please switch to the Apache driven ldbd server through '
339 msg += '\nsecure connection by specifying procotol "https" in your --segment-url argument'
340 msg += '\nFor example, "--segment-url https://segdb.ligo.caltech.edu"'
341 logger.error(msg)
342 return (1, msg)
343
345 msg = '\nTo INSERTDMT, authorized user please switch to the Apache driven ldbd server through '
346 msg += '\nsecure connection by specifying procotol "https" in your --segment-url argument'
347 msg += '\nFor example, "--segment-url https://segdb.ligo.caltech.edu"'
348 logger.error(msg)
349 return (1, msg)
350