xref: /titanic_44/usr/src/tools/onbld/Checks/DbLookups.py (revision cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0)
1*cdf0c1d5Smjnelson#! /usr/bin/python
2*cdf0c1d5Smjnelson#
3*cdf0c1d5Smjnelson# CDDL HEADER START
4*cdf0c1d5Smjnelson#
5*cdf0c1d5Smjnelson# The contents of this file are subject to the terms of the
6*cdf0c1d5Smjnelson# Common Development and Distribution License (the "License").
7*cdf0c1d5Smjnelson# You may not use this file except in compliance with the License.
8*cdf0c1d5Smjnelson#
9*cdf0c1d5Smjnelson# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*cdf0c1d5Smjnelson# or http://www.opensolaris.org/os/licensing.
11*cdf0c1d5Smjnelson# See the License for the specific language governing permissions
12*cdf0c1d5Smjnelson# and limitations under the License.
13*cdf0c1d5Smjnelson#
14*cdf0c1d5Smjnelson# When distributing Covered Code, include this CDDL HEADER in each
15*cdf0c1d5Smjnelson# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*cdf0c1d5Smjnelson# If applicable, add the following below this CDDL HEADER, with the
17*cdf0c1d5Smjnelson# fields enclosed by brackets "[]" replaced with your own identifying
18*cdf0c1d5Smjnelson# information: Portions Copyright [yyyy] [name of copyright owner]
19*cdf0c1d5Smjnelson#
20*cdf0c1d5Smjnelson# CDDL HEADER END
21*cdf0c1d5Smjnelson#
22*cdf0c1d5Smjnelson
23*cdf0c1d5Smjnelson#
24*cdf0c1d5Smjnelson# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
25*cdf0c1d5Smjnelson# Use is subject to license terms.
26*cdf0c1d5Smjnelson#
27*cdf0c1d5Smjnelson# ident	"%Z%%M%	%I%	%E% SMI"
28*cdf0c1d5Smjnelson#
29*cdf0c1d5Smjnelson
30*cdf0c1d5Smjnelson#
31*cdf0c1d5Smjnelson# Various database lookup classes/methods, i.e.:
32*cdf0c1d5Smjnelson#     * monaco
33*cdf0c1d5Smjnelson#     * bugs.opensolaris.org (b.o.o.)
34*cdf0c1d5Smjnelson#     * opensolaris.org/cgi/arc.py (for ARC)
35*cdf0c1d5Smjnelson#
36*cdf0c1d5Smjnelson
37*cdf0c1d5Smjnelsonimport re
38*cdf0c1d5Smjnelsonimport urllib
39*cdf0c1d5Smjnelsonimport htmllib
40*cdf0c1d5Smjnelsonimport os
41*cdf0c1d5Smjnelsonfrom socket import socket, AF_INET, SOCK_STREAM
42*cdf0c1d5Smjnelson
43*cdf0c1d5Smjnelsonfrom onbld.Checks import onSWAN
44*cdf0c1d5Smjnelson
45*cdf0c1d5Smjnelsonclass BugException(Exception):
46*cdf0c1d5Smjnelson	def __init__(self, data=''):
47*cdf0c1d5Smjnelson		self.data = data
48*cdf0c1d5Smjnelson		Exception.__init__(self, data)
49*cdf0c1d5Smjnelson
50*cdf0c1d5Smjnelson	def __str__(self):
51*cdf0c1d5Smjnelson		return "Unknown error: %s" % self.data
52*cdf0c1d5Smjnelson
53*cdf0c1d5Smjnelsonclass NonExistentBug(BugException):
54*cdf0c1d5Smjnelson	def __str__(self):
55*cdf0c1d5Smjnelson		return "Bug %s does not exist" % self.data
56*cdf0c1d5Smjnelson
57*cdf0c1d5Smjnelsonclass Monaco(object):
58*cdf0c1d5Smjnelson	"""
59*cdf0c1d5Smjnelson	Query bug database.
60*cdf0c1d5Smjnelson
61*cdf0c1d5Smjnelson	Methods:
62*cdf0c1d5Smjnelson	queryBugs()
63*cdf0c1d5Smjnelson	expertQuery()
64*cdf0c1d5Smjnelson	"""
65*cdf0c1d5Smjnelson
66*cdf0c1d5Smjnelson	def __init__(self):
67*cdf0c1d5Smjnelson		self.__baseURL = "http://hestia.sfbay.sun.com/cgi-bin/expert?"
68*cdf0c1d5Smjnelson
69*cdf0c1d5Smjnelson	def expertQuery(self, cmd, format="Normal+text", header=False):
70*cdf0c1d5Smjnelson		"""Return results of user-supplied bug query.
71*cdf0c1d5Smjnelson
72*cdf0c1d5Smjnelson		Argument:
73*cdf0c1d5Smjnelson		cmd: query to run
74*cdf0c1d5Smjnelson
75*cdf0c1d5Smjnelson		Keyword arguments:
76*cdf0c1d5Smjnelson		format: desired output format (default="Normal+text")
77*cdf0c1d5Smjnelson		header: include headers in output? (default=False)
78*cdf0c1d5Smjnelson
79*cdf0c1d5Smjnelson		Returns:
80*cdf0c1d5Smjnelson		List of lines representing the output from Monaco
81*cdf0c1d5Smjnelson		"""
82*cdf0c1d5Smjnelson
83*cdf0c1d5Smjnelson		url = self.__baseURL + "format=" + format + ";Go=2;"
84*cdf0c1d5Smjnelson		if not header: url += "no_header=on;"
85*cdf0c1d5Smjnelson		url += "cmds=" + urllib.quote_plus("\n".join(cmd))
86*cdf0c1d5Smjnelson		myMonaco = urllib.urlopen(url)
87*cdf0c1d5Smjnelson		return myMonaco.readlines()
88*cdf0c1d5Smjnelson
89*cdf0c1d5Smjnelson	def queryBugs(self, crs):
90*cdf0c1d5Smjnelson		"""Return all info for requested change reports.
91*cdf0c1d5Smjnelson
92*cdf0c1d5Smjnelson		Argument:
93*cdf0c1d5Smjnelson		crs: list of change request ids
94*cdf0c1d5Smjnelson
95*cdf0c1d5Smjnelson		Returns:
96*cdf0c1d5Smjnelson		Dictionary, mapping CR=>dictionary, where the nested dictionary
97*cdf0c1d5Smjnelson		is a mapping of field=>value
98*cdf0c1d5Smjnelson		"""
99*cdf0c1d5Smjnelson		monacoFields = [ "cr_number", "synopsis", "category", "sub_category",
100*cdf0c1d5Smjnelson			"area", "release", "build", "responsible_manager",
101*cdf0c1d5Smjnelson			"responsible_engineer", "priority", "status", "sub_status",
102*cdf0c1d5Smjnelson			"submitted_by", "date_submitted" ]
103*cdf0c1d5Smjnelson		cmd = []
104*cdf0c1d5Smjnelson		cmd.append("set What = cr." + ', cr.'.join(monacoFields))
105*cdf0c1d5Smjnelson		cmd.append("")
106*cdf0c1d5Smjnelson		cmd.append("set Which = cr.cr_number in (" + ','.join(crs) +")")
107*cdf0c1d5Smjnelson		cmd.append("")
108*cdf0c1d5Smjnelson		cmd.append("set FinalClauses = order by cr.cr_number")
109*cdf0c1d5Smjnelson		cmd.append("")
110*cdf0c1d5Smjnelson		cmd.append("doMeta genQuery cr")
111*cdf0c1d5Smjnelson		output = self.expertQuery(cmd, "Pipe-delimited+text")
112*cdf0c1d5Smjnelson		results = {}
113*cdf0c1d5Smjnelson		for line in output:
114*cdf0c1d5Smjnelson			values = line.split('|')
115*cdf0c1d5Smjnelson			v = 0
116*cdf0c1d5Smjnelson			cr = values[0]
117*cdf0c1d5Smjnelson			results[cr] = {}
118*cdf0c1d5Smjnelson			for field in monacoFields:
119*cdf0c1d5Smjnelson				results[cr][field] = values[v]
120*cdf0c1d5Smjnelson				v += 1
121*cdf0c1d5Smjnelson		return results
122*cdf0c1d5Smjnelson
123*cdf0c1d5Smjnelsonclass BooBug(object):
124*cdf0c1d5Smjnelson	"""Look up a single bug on bugs.opensolaris.org."""
125*cdf0c1d5Smjnelson	def __init__(self, cr):
126*cdf0c1d5Smjnelson		cr = str(cr)
127*cdf0c1d5Smjnelson		url = "http://bugs.opensolaris.org/view_bug.do?bug_id="+cr
128*cdf0c1d5Smjnelson		data = urllib.urlopen(url).readlines()
129*cdf0c1d5Smjnelson		self.__fields = {}
130*cdf0c1d5Smjnelson		self.__fields["cr_number"] = cr
131*cdf0c1d5Smjnelson		htmlParser = htmllib.HTMLParser(None)
132*cdf0c1d5Smjnelson		metaHtmlRe = re.compile(r'^<meta name="([^"]+)" content="([^"]*)">$')
133*cdf0c1d5Smjnelson		for line in data:
134*cdf0c1d5Smjnelson			m = metaHtmlRe.search(line)
135*cdf0c1d5Smjnelson			if not m:
136*cdf0c1d5Smjnelson				continue
137*cdf0c1d5Smjnelson			val = urllib.unquote(m.group(2))
138*cdf0c1d5Smjnelson			htmlParser.save_bgn()
139*cdf0c1d5Smjnelson			htmlParser.feed(val)
140*cdf0c1d5Smjnelson			self.__fields[m.group(1)] = htmlParser.save_end()
141*cdf0c1d5Smjnelson		htmlParser.close()
142*cdf0c1d5Smjnelson		if "synopsis" not in self.__fields:
143*cdf0c1d5Smjnelson			raise NonExistentBug(cr)
144*cdf0c1d5Smjnelson
145*cdf0c1d5Smjnelson	def synopsis(self):
146*cdf0c1d5Smjnelson		return self.__fields["synopsis"]
147*cdf0c1d5Smjnelson	def product(self):
148*cdf0c1d5Smjnelson		return self.__fields["product"]
149*cdf0c1d5Smjnelson	def cat(self):
150*cdf0c1d5Smjnelson		return self.__fields["category"]
151*cdf0c1d5Smjnelson	def subcat(self):
152*cdf0c1d5Smjnelson		return self.__fields["subcategory"]
153*cdf0c1d5Smjnelson	def keywords(self):
154*cdf0c1d5Smjnelson		return self.__fields["keywords"]
155*cdf0c1d5Smjnelson	def state(self):
156*cdf0c1d5Smjnelson		return self.__fields["state"]
157*cdf0c1d5Smjnelson	def submit_date(self):
158*cdf0c1d5Smjnelson		return self.__fields["submit_date"]
159*cdf0c1d5Smjnelson	def type(self):
160*cdf0c1d5Smjnelson		return self.__fields["type"]
161*cdf0c1d5Smjnelson	def date(self):
162*cdf0c1d5Smjnelson		return self.__fields["date"]
163*cdf0c1d5Smjnelson	def number(self):
164*cdf0c1d5Smjnelson		return self.__fields["cr_number"]
165*cdf0c1d5Smjnelson
166*cdf0c1d5Smjnelsonclass BugDB(object):
167*cdf0c1d5Smjnelson	"""Lookup change requests.
168*cdf0c1d5Smjnelson
169*cdf0c1d5Smjnelson	Object can be used on or off of SWAN, using either monaco or
170*cdf0c1d5Smjnelson	bugs.opensolaris.org as a database.
171*cdf0c1d5Smjnelson
172*cdf0c1d5Smjnelson	Usage:
173*cdf0c1d5Smjnelson	bdb = BugDB()
174*cdf0c1d5Smjnelson	r = bdb.lookup("6455550")
175*cdf0c1d5Smjnelson	print r["6455550"]["synopsis"]
176*cdf0c1d5Smjnelson	r = bdb.lookup(["6455550", "6505625"])
177*cdf0c1d5Smjnelson	print r["6505625"]["synopsis"]
178*cdf0c1d5Smjnelson	"""
179*cdf0c1d5Smjnelson
180*cdf0c1d5Smjnelson	def __init__(self, forceBoo = False):
181*cdf0c1d5Smjnelson		"""Create a BugDB object.
182*cdf0c1d5Smjnelson
183*cdf0c1d5Smjnelson		Keyword argument:
184*cdf0c1d5Smjnelson		forceBoo: use b.o.o even from SWAN (default=False)
185*cdf0c1d5Smjnelson		"""
186*cdf0c1d5Smjnelson		if forceBoo:
187*cdf0c1d5Smjnelson			self.__onSWAN = False
188*cdf0c1d5Smjnelson		else:
189*cdf0c1d5Smjnelson			self.__onSWAN = onSWAN()
190*cdf0c1d5Smjnelson			if self.__onSWAN:
191*cdf0c1d5Smjnelson				self.__m = Monaco()
192*cdf0c1d5Smjnelson
193*cdf0c1d5Smjnelson	def lookup(self, crs):
194*cdf0c1d5Smjnelson		"""Return all info for requested change reports.
195*cdf0c1d5Smjnelson
196*cdf0c1d5Smjnelson		Argument:
197*cdf0c1d5Smjnelson		crs: one change request id (may be integer, string, or list),
198*cdf0c1d5Smjnelson	             or multiple change request ids (must be a list)
199*cdf0c1d5Smjnelson
200*cdf0c1d5Smjnelson		Returns:
201*cdf0c1d5Smjnelson		Dictionary, mapping CR=>dictionary, where the nested dictionary
202*cdf0c1d5Smjnelson		is a mapping of field=>value
203*cdf0c1d5Smjnelson		"""
204*cdf0c1d5Smjnelson		if not isinstance(crs, list):
205*cdf0c1d5Smjnelson			crs = [str(crs)]
206*cdf0c1d5Smjnelson		if self.__onSWAN:
207*cdf0c1d5Smjnelson			results = self.__m.queryBugs(crs)
208*cdf0c1d5Smjnelson			return self.__m.queryBugs(crs)
209*cdf0c1d5Smjnelson		# else we're off-swan and querying via boo, which we can
210*cdf0c1d5Smjnelson		# only do one bug at a time
211*cdf0c1d5Smjnelson		results = {}
212*cdf0c1d5Smjnelson		for cr in crs:
213*cdf0c1d5Smjnelson			cr = str(cr)
214*cdf0c1d5Smjnelson			try:
215*cdf0c1d5Smjnelson				b = BooBug(cr)
216*cdf0c1d5Smjnelson			except NonExistentBug:
217*cdf0c1d5Smjnelson				continue
218*cdf0c1d5Smjnelson
219*cdf0c1d5Smjnelson			results[cr] = {}
220*cdf0c1d5Smjnelson			results[cr]["cr_number"] = cr
221*cdf0c1d5Smjnelson			results[cr]["product"] = b.product()
222*cdf0c1d5Smjnelson			results[cr]["synopsis"] = b.synopsis()
223*cdf0c1d5Smjnelson			results[cr]["category"] = b.cat()
224*cdf0c1d5Smjnelson			results[cr]["sub_category"] = b.subcat()
225*cdf0c1d5Smjnelson			results[cr]["keywords"] = b.keywords()
226*cdf0c1d5Smjnelson			results[cr]["status"] = b.state()
227*cdf0c1d5Smjnelson			results[cr]["date_submitted"] = b.submit_date()
228*cdf0c1d5Smjnelson			results[cr]["type"] = b.type()
229*cdf0c1d5Smjnelson			results[cr]["date"] = b.date()
230*cdf0c1d5Smjnelson
231*cdf0c1d5Smjnelson		return results
232*cdf0c1d5Smjnelson
233*cdf0c1d5Smjnelson####################################################################
234*cdf0c1d5Smjnelson
235*cdf0c1d5Smjnelsonclass ARC(object):
236*cdf0c1d5Smjnelson	"""Lookup an ARC case on opensolaris.org.
237*cdf0c1d5Smjnelson
238*cdf0c1d5Smjnelson	Usage:
239*cdf0c1d5Smjnelson	a = ARC("PSARC", "2008/002")
240*cdf0c1d5Smjnelson	if a.valid():
241*cdf0c1d5Smjnelson		print a.name()
242*cdf0c1d5Smjnelson	"""
243*cdf0c1d5Smjnelson	def __init__(self, arc, case):
244*cdf0c1d5Smjnelson		self.__valid = False
245*cdf0c1d5Smjnelson		q = "http://opensolaris.org/cgi/arc.py?n=1"
246*cdf0c1d5Smjnelson		q += "&arc0=" + arc
247*cdf0c1d5Smjnelson		q += "&case0=" + case
248*cdf0c1d5Smjnelson		data = urllib.urlopen(q).readlines()
249*cdf0c1d5Smjnelson		self.__fields = {}
250*cdf0c1d5Smjnelson		for line in data:
251*cdf0c1d5Smjnelson			line = line.rstrip('\n')
252*cdf0c1d5Smjnelson			fields = line.split('|')
253*cdf0c1d5Smjnelson			validity = fields[0]
254*cdf0c1d5Smjnelson
255*cdf0c1d5Smjnelson			if validity != "0":
256*cdf0c1d5Smjnelson				return
257*cdf0c1d5Smjnelson			else:
258*cdf0c1d5Smjnelson				self.__fields["Name"] = fields[2]
259*cdf0c1d5Smjnelson
260*cdf0c1d5Smjnelson		self.__valid = True
261*cdf0c1d5Smjnelson
262*cdf0c1d5Smjnelson	def valid(self):
263*cdf0c1d5Smjnelson		return self.__valid
264*cdf0c1d5Smjnelson	def name(self):
265*cdf0c1d5Smjnelson		return self.__fields["Name"]
266*cdf0c1d5Smjnelson	def status(self):
267*cdf0c1d5Smjnelson		return self.__fields["Status"]
268*cdf0c1d5Smjnelson	def type(self):
269*cdf0c1d5Smjnelson		return self.__fields["Type"]
270*cdf0c1d5Smjnelson
271*cdf0c1d5Smjnelson####################################################################
272*cdf0c1d5Smjnelson
273*cdf0c1d5Smjnelson# Pointers to the webrti server hostname & port to use
274*cdf0c1d5Smjnelson# Using it directly is probably not *officially* supported, so we'll
275*cdf0c1d5Smjnelson# have a pointer to the official `webrticli` command line interface
276*cdf0c1d5Smjnelson# if using a direct socket connection fails for some reason, so we
277*cdf0c1d5Smjnelson# have a fallback
278*cdf0c1d5SmjnelsonWEBRTI_HOST = 'webrti.sfbay.sun.com'
279*cdf0c1d5SmjnelsonWEBRTI_PORT = 9188
280*cdf0c1d5SmjnelsonWEBRTICLI = '/net/webrti.sfbay.sun.com/export/home/bin/webrticli'
281*cdf0c1d5Smjnelson
282*cdf0c1d5Smjnelson
283*cdf0c1d5Smjnelsonclass RtiException(Exception):
284*cdf0c1d5Smjnelson	def __init__(self, data=''):
285*cdf0c1d5Smjnelson		self.data = data
286*cdf0c1d5Smjnelson		Exception.__init__(self, data)
287*cdf0c1d5Smjnelson
288*cdf0c1d5Smjnelson	def __str__(self):
289*cdf0c1d5Smjnelson		return "Unknown error: %s" % self.data
290*cdf0c1d5Smjnelson
291*cdf0c1d5Smjnelson# RtiInvalidOutput & RtiCallFailed are our "own" failures
292*cdf0c1d5Smjnelson# The other exceptions are triggered from WebRTI itself
293*cdf0c1d5Smjnelsonclass RtiInvalidOutput(RtiException):
294*cdf0c1d5Smjnelson	def __str__(self):
295*cdf0c1d5Smjnelson		return "Invalid output from WebRTI: %s" % self.data
296*cdf0c1d5Smjnelson
297*cdf0c1d5Smjnelsonclass RtiCallFailed(RtiException):
298*cdf0c1d5Smjnelson	def __str__(self):
299*cdf0c1d5Smjnelson		return "Unable to call webrti: %s" % self.data
300*cdf0c1d5Smjnelson
301*cdf0c1d5Smjnelsonclass RtiSystemProblem(RtiException):
302*cdf0c1d5Smjnelson	def __str__(self):
303*cdf0c1d5Smjnelson		return "RTI status cannot be determined: %s" % self.data
304*cdf0c1d5Smjnelson
305*cdf0c1d5Smjnelsonclass RtiIncorrectCR(RtiException):
306*cdf0c1d5Smjnelson	def __str__(self):
307*cdf0c1d5Smjnelson		return "Incorrect CR number specified: %s" % self.data
308*cdf0c1d5Smjnelson
309*cdf0c1d5Smjnelsonclass RtiNotFound(RtiException):
310*cdf0c1d5Smjnelson	def __str__(self):
311*cdf0c1d5Smjnelson		return "RTI not found: %s" % self.data
312*cdf0c1d5Smjnelson
313*cdf0c1d5Smjnelsonclass RtiNeedConsolidation(RtiException):
314*cdf0c1d5Smjnelson	def __str__(self):
315*cdf0c1d5Smjnelson		return "More than one consolidation has this CR: %s" % self.data
316*cdf0c1d5Smjnelson
317*cdf0c1d5Smjnelsonclass RtiBadGate(RtiException):
318*cdf0c1d5Smjnelson	def __str__(self):
319*cdf0c1d5Smjnelson		return "Incorrect gate name specified: %s" % self.data
320*cdf0c1d5Smjnelson
321*cdf0c1d5Smjnelsonclass RtiOffSwan(RtiException):
322*cdf0c1d5Smjnelson	def __str__(self):
323*cdf0c1d5Smjnelson		return "RTI status checks need SWAN access: %s" % self.data
324*cdf0c1d5Smjnelson
325*cdf0c1d5SmjnelsonWEBRTI_ERRORS = {
326*cdf0c1d5Smjnelson	'1': RtiSystemProblem,
327*cdf0c1d5Smjnelson	'2': RtiIncorrectCR,
328*cdf0c1d5Smjnelson	'3': RtiNotFound,
329*cdf0c1d5Smjnelson	'4': RtiNeedConsolidation,
330*cdf0c1d5Smjnelson	'5': RtiBadGate,
331*cdf0c1d5Smjnelson}
332*cdf0c1d5Smjnelson
333*cdf0c1d5Smjnelson# Our Rti object which we'll use to represent an Rti query
334*cdf0c1d5Smjnelson# It's really just a wrapper around the Rti connection, and attempts
335*cdf0c1d5Smjnelson# to establish a direct socket connection and query the webrti server
336*cdf0c1d5Smjnelson# directly (thus avoiding a system/fork/exec call).  If it fails, it
337*cdf0c1d5Smjnelson# falls back to the webrticli command line client.
338*cdf0c1d5Smjnelson
339*cdf0c1d5SmjnelsonreturnCodeRe = re.compile(r'.*RETURN_CODE=(\d+)')
340*cdf0c1d5Smjnelsonclass Rti:
341*cdf0c1d5Smjnelson	"""Lookup an RTI.
342*cdf0c1d5Smjnelson
343*cdf0c1d5Smjnelson	Usage:
344*cdf0c1d5Smjnelson	r = Rti("6640538")
345*cdf0c1d5Smjnelson	print r.rtiNumber();
346*cdf0c1d5Smjnelson	"""
347*cdf0c1d5Smjnelson
348*cdf0c1d5Smjnelson	def __init__(self, cr, gate=None, consolidation=None):
349*cdf0c1d5Smjnelson		"""Create an Rti object for the specified change request.
350*cdf0c1d5Smjnelson
351*cdf0c1d5Smjnelson		Argument:
352*cdf0c1d5Smjnelson		cr: change request id
353*cdf0c1d5Smjnelson
354*cdf0c1d5Smjnelson		Keyword arguments, to limit scope of RTI search:
355*cdf0c1d5Smjnelson		gate: path to gate workspace (default=None)
356*cdf0c1d5Smjnelson		consolidation: consolidation name (default=None)
357*cdf0c1d5Smjnelson		"""
358*cdf0c1d5Smjnelson
359*cdf0c1d5Smjnelson		bufSz = 1024
360*cdf0c1d5Smjnelson		addr = (WEBRTI_HOST, WEBRTI_PORT)
361*cdf0c1d5Smjnelson		# If the passed 'cr' was given as an int, then wrap it
362*cdf0c1d5Smjnelson		# into a string to make our life easier
363*cdf0c1d5Smjnelson		if isinstance(cr, int):
364*cdf0c1d5Smjnelson			cr = str(cr)
365*cdf0c1d5Smjnelson		self.__queryCr = cr
366*cdf0c1d5Smjnelson		self.__queryGate = gate
367*cdf0c1d5Smjnelson		self.__queryConsolidation = consolidation
368*cdf0c1d5Smjnelson
369*cdf0c1d5Smjnelson		try:
370*cdf0c1d5Smjnelson			# try to use a direct connection to the
371*cdf0c1d5Smjnelson			# webrti server first
372*cdf0c1d5Smjnelson			sock = socket(AF_INET, SOCK_STREAM)
373*cdf0c1d5Smjnelson			sock.connect(addr)
374*cdf0c1d5Smjnelson			command = "WEBRTICLI/1.0\nRTIstatus\n%s\n" % cr
375*cdf0c1d5Smjnelson			if consolidation:
376*cdf0c1d5Smjnelson				command += "-c\n%s\n" % consolidation
377*cdf0c1d5Smjnelson			if gate:
378*cdf0c1d5Smjnelson				command += "-g\n%s\n" % gate
379*cdf0c1d5Smjnelson			command += "\n"
380*cdf0c1d5Smjnelson			sock.send(command)
381*cdf0c1d5Smjnelson			dataList = []
382*cdf0c1d5Smjnelson			# keep receiving data from the socket until the
383*cdf0c1d5Smjnelson			# server closes the connection
384*cdf0c1d5Smjnelson			stillReceiving = True
385*cdf0c1d5Smjnelson			while stillReceiving:
386*cdf0c1d5Smjnelson				dataPiece = sock.recv(bufSz)
387*cdf0c1d5Smjnelson				if dataPiece:
388*cdf0c1d5Smjnelson					dataList.append(dataPiece)
389*cdf0c1d5Smjnelson				else:
390*cdf0c1d5Smjnelson					stillReceiving = False
391*cdf0c1d5Smjnelson			# create the lines, skipping the first
392*cdf0c1d5Smjnelson			# ("WEBRTCLI/1.0\n")
393*cdf0c1d5Smjnelson			data = '\n'.join(''.join(dataList).split('\n')[1:])
394*cdf0c1d5Smjnelson		except:
395*cdf0c1d5Smjnelson			if not onSWAN():
396*cdf0c1d5Smjnelson				raise RtiOffSwan(cr)
397*cdf0c1d5Smjnelson
398*cdf0c1d5Smjnelson			if not os.path.exists(WEBRTICLI):
399*cdf0c1d5Smjnelson				raise RtiCallFailed('not found')
400*cdf0c1d5Smjnelson
401*cdf0c1d5Smjnelson			# fallback to the "supported" webrticli interface
402*cdf0c1d5Smjnelson			command = WEBRTICLI
403*cdf0c1d5Smjnelson			if consolidation:
404*cdf0c1d5Smjnelson				command += " -c " + consolidation
405*cdf0c1d5Smjnelson			if gate:
406*cdf0c1d5Smjnelson				command += " -g " + gate
407*cdf0c1d5Smjnelson			command += " RTIstatus " + cr
408*cdf0c1d5Smjnelson
409*cdf0c1d5Smjnelson			try:
410*cdf0c1d5Smjnelson				cliPipe = os.popen(command)
411*cdf0c1d5Smjnelson			except:
412*cdf0c1d5Smjnelson				# we couldn't call the webrticli for some
413*cdf0c1d5Smjnelson				# reason, so return a failure
414*cdf0c1d5Smjnelson				raise RtiCallFailed('unknown')
415*cdf0c1d5Smjnelson
416*cdf0c1d5Smjnelson			data = cliPipe.readline()
417*cdf0c1d5Smjnelson
418*cdf0c1d5Smjnelson		# parse the data to see if we got a return code
419*cdf0c1d5Smjnelson		# if we did, then that's bad.  if we didn't,
420*cdf0c1d5Smjnelson		# then our call was successfully
421*cdf0c1d5Smjnelson		m = returnCodeRe.search(data)
422*cdf0c1d5Smjnelson		if m:
423*cdf0c1d5Smjnelson			# we got a return code, set it in our
424*cdf0c1d5Smjnelson			# object, set the webRtiOutput for debugging
425*cdf0c1d5Smjnelson			# or logging, and return a failure
426*cdf0c1d5Smjnelson			if m.group(1) in WEBRTI_ERRORS:
427*cdf0c1d5Smjnelson				exc = WEBRTI_ERRORS[m.group(1)]
428*cdf0c1d5Smjnelson			else:
429*cdf0c1d5Smjnelson				exc = RtiException
430*cdf0c1d5Smjnelson			raise exc(data)
431*cdf0c1d5Smjnelson
432*cdf0c1d5Smjnelson		if data.count('\n') != 1:
433*cdf0c1d5Smjnelson			# there shouldn't be more than one line in
434*cdf0c1d5Smjnelson			# the output.  if we got more than one line,
435*cdf0c1d5Smjnelson			# then let's be paranoid, and abort.
436*cdf0c1d5Smjnelson			raise RtiInvalidOutput(data)
437*cdf0c1d5Smjnelson
438*cdf0c1d5Smjnelson		# At this point, we should have valid data
439*cdf0c1d5Smjnelson		data = data.rstrip('\r\n')
440*cdf0c1d5Smjnelson		self.__webRtiOutput = data
441*cdf0c1d5Smjnelson		self.__fields = data.split(':')
442*cdf0c1d5Smjnelson		self.__mainCR = self.__fields[0]
443*cdf0c1d5Smjnelson		self.__rtiNumber = self.__fields[1]
444*cdf0c1d5Smjnelson		self.__consolidation = self.__fields[2]
445*cdf0c1d5Smjnelson		self.__project = self.__fields[3]
446*cdf0c1d5Smjnelson		self.__status = self.__fields[4]
447*cdf0c1d5Smjnelson		self.__rtiType = self.__fields[5]
448*cdf0c1d5Smjnelson
449*cdf0c1d5Smjnelson	# accessors in case callers need the raw data
450*cdf0c1d5Smjnelson	def mainCR(self):
451*cdf0c1d5Smjnelson		return self.__mainCR
452*cdf0c1d5Smjnelson	def rtiNumber(self):
453*cdf0c1d5Smjnelson		return self.__rtiNumber
454*cdf0c1d5Smjnelson	def consolidation(self):
455*cdf0c1d5Smjnelson		return self.__consolidation
456*cdf0c1d5Smjnelson	def project(self):
457*cdf0c1d5Smjnelson		return self.__project
458*cdf0c1d5Smjnelson	def status(self):
459*cdf0c1d5Smjnelson		return self.__status
460*cdf0c1d5Smjnelson	def rtiType(self):
461*cdf0c1d5Smjnelson		return self.__rtiType
462*cdf0c1d5Smjnelson	def queryCr(self):
463*cdf0c1d5Smjnelson		return self.__queryCr
464*cdf0c1d5Smjnelson	def queryGate(self):
465*cdf0c1d5Smjnelson		return self.__queryGate
466*cdf0c1d5Smjnelson	def queryConsolidation(self):
467*cdf0c1d5Smjnelson		return self.__queryConsolidation
468*cdf0c1d5Smjnelson
469*cdf0c1d5Smjnelson	# in practice, most callers only care about the following
470*cdf0c1d5Smjnelson	def accepted(self):
471*cdf0c1d5Smjnelson		return (self.__status == "S_ACCEPTED")
472*cdf0c1d5Smjnelson
473*cdf0c1d5Smjnelson	# for logging/debugging in case the caller wants the raw webrti output
474*cdf0c1d5Smjnelson	def webRtiOutput(self):
475*cdf0c1d5Smjnelson		return self.__webRtiOutput
476*cdf0c1d5Smjnelson
477*cdf0c1d5Smjnelson
478