xref: /onnv-gate/usr/src/tools/onbld/Checks/DbLookups.py (revision 8042:54a2500a85d8)
17078Smjnelson#! /usr/bin/python
27078Smjnelson#
37078Smjnelson# CDDL HEADER START
47078Smjnelson#
57078Smjnelson# The contents of this file are subject to the terms of the
67078Smjnelson# Common Development and Distribution License (the "License").
77078Smjnelson# You may not use this file except in compliance with the License.
87078Smjnelson#
97078Smjnelson# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107078Smjnelson# or http://www.opensolaris.org/os/licensing.
117078Smjnelson# See the License for the specific language governing permissions
127078Smjnelson# and limitations under the License.
137078Smjnelson#
147078Smjnelson# When distributing Covered Code, include this CDDL HEADER in each
157078Smjnelson# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167078Smjnelson# If applicable, add the following below this CDDL HEADER, with the
177078Smjnelson# fields enclosed by brackets "[]" replaced with your own identifying
187078Smjnelson# information: Portions Copyright [yyyy] [name of copyright owner]
197078Smjnelson#
207078Smjnelson# CDDL HEADER END
217078Smjnelson#
227078Smjnelson
237078Smjnelson#
247078Smjnelson# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
257078Smjnelson# Use is subject to license terms.
267078Smjnelson#
277078Smjnelson
287078Smjnelson#
297078Smjnelson# Various database lookup classes/methods, i.e.:
307078Smjnelson#     * monaco
317078Smjnelson#     * bugs.opensolaris.org (b.o.o.)
327078Smjnelson#     * opensolaris.org/cgi/arc.py (for ARC)
337078Smjnelson#
347078Smjnelson
357078Smjnelsonimport re
367078Smjnelsonimport urllib
37*8042SJohn.Sonnenschein@Sun.COMimport urllib2
387078Smjnelsonimport htmllib
397078Smjnelsonimport os
407078Smjnelsonfrom socket import socket, AF_INET, SOCK_STREAM
417078Smjnelson
427078Smjnelsonfrom onbld.Checks import onSWAN
437078Smjnelson
447078Smjnelsonclass BugException(Exception):
457078Smjnelson	def __init__(self, data=''):
467078Smjnelson		self.data = data
477078Smjnelson		Exception.__init__(self, data)
487078Smjnelson
497078Smjnelson	def __str__(self):
507078Smjnelson		return "Unknown error: %s" % self.data
517078Smjnelson
527078Smjnelsonclass NonExistentBug(BugException):
537078Smjnelson	def __str__(self):
547078Smjnelson		return "Bug %s does not exist" % self.data
557078Smjnelson
56*8042SJohn.Sonnenschein@Sun.COMclass BugDBException(Exception):
57*8042SJohn.Sonnenschein@Sun.COM	def __init__(self, data=''):
58*8042SJohn.Sonnenschein@Sun.COM		self.data = data
59*8042SJohn.Sonnenschein@Sun.COM		Exception.__init__(self, data)
607078Smjnelson
61*8042SJohn.Sonnenschein@Sun.COM	def __str__(self):
62*8042SJohn.Sonnenschein@Sun.COM		return "Unknown bug database: %s" % self.data
637078Smjnelson
647078Smjnelsonclass BugDB(object):
657078Smjnelson	"""Lookup change requests.
667078Smjnelson
677078Smjnelson	Object can be used on or off of SWAN, using either monaco or
687078Smjnelson	bugs.opensolaris.org as a database.
697078Smjnelson
707078Smjnelson	Usage:
717078Smjnelson	bdb = BugDB()
727078Smjnelson	r = bdb.lookup("6455550")
737078Smjnelson	print r["6455550"]["synopsis"]
747078Smjnelson	r = bdb.lookup(["6455550", "6505625"])
757078Smjnelson	print r["6505625"]["synopsis"]
767078Smjnelson	"""
777078Smjnelson
78*8042SJohn.Sonnenschein@Sun.COM	def __init__(self, priority = ("bugster",), forceBoo = False):
797078Smjnelson		"""Create a BugDB object.
807078Smjnelson
817078Smjnelson		Keyword argument:
827078Smjnelson		forceBoo: use b.o.o even from SWAN (default=False)
83*8042SJohn.Sonnenschein@Sun.COM		priority: use bug databases in this order
847078Smjnelson		"""
85*8042SJohn.Sonnenschein@Sun.COM		self.__validBugDB = ["bugster"]
86*8042SJohn.Sonnenschein@Sun.COM		self.__onSWAN = not forceBoo and onSWAN()
87*8042SJohn.Sonnenschein@Sun.COM		for database in priority:
88*8042SJohn.Sonnenschein@Sun.COM			if database not in self.__validBugDB:
89*8042SJohn.Sonnenschein@Sun.COM				raise BugDBException, database
90*8042SJohn.Sonnenschein@Sun.COM		self.__priority = priority
91*8042SJohn.Sonnenschein@Sun.COM
92*8042SJohn.Sonnenschein@Sun.COM
93*8042SJohn.Sonnenschein@Sun.COM	def __boobug(self, cr):
94*8042SJohn.Sonnenschein@Sun.COM		cr = str(cr)
95*8042SJohn.Sonnenschein@Sun.COM		url = "http://bugs.opensolaris.org/view_bug.do"
96*8042SJohn.Sonnenschein@Sun.COM   		req = urllib2.Request(url, urllib.urlencode({"bug_id": cr}))
97*8042SJohn.Sonnenschein@Sun.COM		results = {}
98*8042SJohn.Sonnenschein@Sun.COM		try:
99*8042SJohn.Sonnenschein@Sun.COM			data = urllib2.urlopen(req).readlines()
100*8042SJohn.Sonnenschein@Sun.COM		except urllib2.HTTPError, e:
101*8042SJohn.Sonnenschein@Sun.COM			if e.code != 404:
102*8042SJohn.Sonnenschein@Sun.COM				print "ERROR: HTTP error at " + \
103*8042SJohn.Sonnenschein@Sun.COM					req.get_full_url() + \
104*8042SJohn.Sonnenschein@Sun.COM					" got error: " + str(e.code)
105*8042SJohn.Sonnenschein@Sun.COM				raise e
106*8042SJohn.Sonnenschein@Sun.COM			else:
107*8042SJohn.Sonnenschein@Sun.COM				raise NonExistentBug
108*8042SJohn.Sonnenschein@Sun.COM		except urllib2.URLError, e:
109*8042SJohn.Sonnenschein@Sun.COM			print "ERROR: could not connect to " + \
110*8042SJohn.Sonnenschein@Sun.COM				req.get_full_url() + \
111*8042SJohn.Sonnenschein@Sun.COM				' got error: "' + e.reason[1] + '"'
112*8042SJohn.Sonnenschein@Sun.COM			raise e
113*8042SJohn.Sonnenschein@Sun.COM		htmlParser = htmllib.HTMLParser(None)
114*8042SJohn.Sonnenschein@Sun.COM		metaHtmlRe = re.compile(r'^<meta name="([^"]+)" content="([^"]*)">$')
115*8042SJohn.Sonnenschein@Sun.COM		for line in data:
116*8042SJohn.Sonnenschein@Sun.COM			m = metaHtmlRe.search(line)
117*8042SJohn.Sonnenschein@Sun.COM			if not m:
118*8042SJohn.Sonnenschein@Sun.COM				continue
119*8042SJohn.Sonnenschein@Sun.COM			val = urllib.unquote(m.group(2))
120*8042SJohn.Sonnenschein@Sun.COM			htmlParser.save_bgn()
121*8042SJohn.Sonnenschein@Sun.COM			htmlParser.feed(val)
122*8042SJohn.Sonnenschein@Sun.COM			results[m.group(1)] = htmlParser.save_end()
123*8042SJohn.Sonnenschein@Sun.COM		htmlParser.close()
124*8042SJohn.Sonnenschein@Sun.COM
125*8042SJohn.Sonnenschein@Sun.COM		if "synopsis" not in results:
126*8042SJohn.Sonnenschein@Sun.COM			raise NonExistentBug(cr)
127*8042SJohn.Sonnenschein@Sun.COM
128*8042SJohn.Sonnenschein@Sun.COM		results["cr_number"] = cr
129*8042SJohn.Sonnenschein@Sun.COM		results["sub_category"] = results.pop("subcategory")
130*8042SJohn.Sonnenschein@Sun.COM		results["status"] = results.pop("state")
131*8042SJohn.Sonnenschein@Sun.COM		results["date_submitted"] = results.pop("submit_date")
132*8042SJohn.Sonnenschein@Sun.COM
133*8042SJohn.Sonnenschein@Sun.COM		return results
134*8042SJohn.Sonnenschein@Sun.COM
135*8042SJohn.Sonnenschein@Sun.COM
136*8042SJohn.Sonnenschein@Sun.COM	def __monaco(self, crs):
137*8042SJohn.Sonnenschein@Sun.COM		"""Return all info for requested change reports.
138*8042SJohn.Sonnenschein@Sun.COM
139*8042SJohn.Sonnenschein@Sun.COM		Argument:
140*8042SJohn.Sonnenschein@Sun.COM		crs: list of change request ids
141*8042SJohn.Sonnenschein@Sun.COM
142*8042SJohn.Sonnenschein@Sun.COM		Returns:
143*8042SJohn.Sonnenschein@Sun.COM		Dictionary, mapping CR=>dictionary, where the nested dictionary
144*8042SJohn.Sonnenschein@Sun.COM		is a mapping of field=>value
145*8042SJohn.Sonnenschein@Sun.COM		"""
146*8042SJohn.Sonnenschein@Sun.COM
147*8042SJohn.Sonnenschein@Sun.COM		#
148*8042SJohn.Sonnenschein@Sun.COM		# We request synopsis last, and split on only
149*8042SJohn.Sonnenschein@Sun.COM		# the number of separators that we expect to
150*8042SJohn.Sonnenschein@Sun.COM		# see such that a | in the synopsis doesn't
151*8042SJohn.Sonnenschein@Sun.COM		# throw us out of whack.
152*8042SJohn.Sonnenschein@Sun.COM		#
153*8042SJohn.Sonnenschein@Sun.COM		monacoFields = [ "cr_number", "category", "sub_category",
154*8042SJohn.Sonnenschein@Sun.COM			"area", "release", "build", "responsible_manager",
155*8042SJohn.Sonnenschein@Sun.COM			"responsible_engineer", "priority", "status", "sub_status",
156*8042SJohn.Sonnenschein@Sun.COM			"submitted_by", "date_submitted", "synopsis" ]
157*8042SJohn.Sonnenschein@Sun.COM		cmd = []
158*8042SJohn.Sonnenschein@Sun.COM		cmd.append("set What = cr." + ', cr.'.join(monacoFields))
159*8042SJohn.Sonnenschein@Sun.COM		cmd.append("")
160*8042SJohn.Sonnenschein@Sun.COM		cmd.append("set Which = cr.cr_number in (" + ','.join(crs) +")")
161*8042SJohn.Sonnenschein@Sun.COM		cmd.append("")
162*8042SJohn.Sonnenschein@Sun.COM		cmd.append("set FinalClauses = order by cr.cr_number")
163*8042SJohn.Sonnenschein@Sun.COM		cmd.append("")
164*8042SJohn.Sonnenschein@Sun.COM		cmd.append("doMeta genQuery cr")
165*8042SJohn.Sonnenschein@Sun.COM		url = "http://hestia.sfbay.sun.com/cgi-bin/expert?format="
166*8042SJohn.Sonnenschein@Sun.COM		url += "Pipe-delimited+text;Go=2;no_header=on;cmds="
167*8042SJohn.Sonnenschein@Sun.COM		url += urllib.quote_plus("\n".join(cmd))
168*8042SJohn.Sonnenschein@Sun.COM		results = {}
169*8042SJohn.Sonnenschein@Sun.COM		try:
170*8042SJohn.Sonnenschein@Sun.COM			data = urllib2.urlopen(url).readlines()
171*8042SJohn.Sonnenschein@Sun.COM		except urllib2.HTTPError, e:
172*8042SJohn.Sonnenschein@Sun.COM			print "ERROR: HTTP error at " + url + \
173*8042SJohn.Sonnenschein@Sun.COM				" got error: " + str(e.code)
174*8042SJohn.Sonnenschein@Sun.COM			raise e
175*8042SJohn.Sonnenschein@Sun.COM
176*8042SJohn.Sonnenschein@Sun.COM		except urllib2.URLError, e:
177*8042SJohn.Sonnenschein@Sun.COM			print "ERROR: could not connect to " + url + \
178*8042SJohn.Sonnenschein@Sun.COM				' got error: "' + e.reason[1] + '"'
179*8042SJohn.Sonnenschein@Sun.COM			raise e
180*8042SJohn.Sonnenschein@Sun.COM		for line in data:
181*8042SJohn.Sonnenschein@Sun.COM			line = line.rstrip('\n')
182*8042SJohn.Sonnenschein@Sun.COM			values = line.split('|', len(monacoFields) - 1)
183*8042SJohn.Sonnenschein@Sun.COM			v = 0
184*8042SJohn.Sonnenschein@Sun.COM			cr = values[0]
185*8042SJohn.Sonnenschein@Sun.COM			results[cr] = {}
186*8042SJohn.Sonnenschein@Sun.COM			for field in monacoFields:
187*8042SJohn.Sonnenschein@Sun.COM				results[cr][field] = values[v]
188*8042SJohn.Sonnenschein@Sun.COM				v += 1
189*8042SJohn.Sonnenschein@Sun.COM		return results
1907078Smjnelson
1917078Smjnelson	def lookup(self, crs):
1927078Smjnelson		"""Return all info for requested change reports.
1937078Smjnelson
1947078Smjnelson		Argument:
1957078Smjnelson		crs: one change request id (may be integer, string, or list),
1967078Smjnelson	             or multiple change request ids (must be a list)
1977078Smjnelson
1987078Smjnelson		Returns:
1997078Smjnelson		Dictionary, mapping CR=>dictionary, where the nested dictionary
2007078Smjnelson		is a mapping of field=>value
2017078Smjnelson		"""
202*8042SJohn.Sonnenschein@Sun.COM		results = {}
2037078Smjnelson		if not isinstance(crs, list):
2047078Smjnelson			crs = [str(crs)]
205*8042SJohn.Sonnenschein@Sun.COM		for database in self.__priority:
206*8042SJohn.Sonnenschein@Sun.COM			if database == "bugster":
207*8042SJohn.Sonnenschein@Sun.COM				if self.__onSWAN:
208*8042SJohn.Sonnenschein@Sun.COM					results.update(self.__monaco(crs))
209*8042SJohn.Sonnenschein@Sun.COM				# else we're off-swan and querying via boo, which we can
210*8042SJohn.Sonnenschein@Sun.COM				# only do one bug at a time
211*8042SJohn.Sonnenschein@Sun.COM				else:
212*8042SJohn.Sonnenschein@Sun.COM					for cr in crs:
213*8042SJohn.Sonnenschein@Sun.COM						cr = str(cr)
214*8042SJohn.Sonnenschein@Sun.COM						try:
215*8042SJohn.Sonnenschein@Sun.COM							results[cr] = self.__boobug(cr)
216*8042SJohn.Sonnenschein@Sun.COM						except NonExistentBug:
217*8042SJohn.Sonnenschein@Sun.COM							continue
2187078Smjnelson
219*8042SJohn.Sonnenschein@Sun.COM			# the CR has already been found by one bug database
220*8042SJohn.Sonnenschein@Sun.COM			# so don't bother looking it up in the others
221*8042SJohn.Sonnenschein@Sun.COM			for cr in crs:
222*8042SJohn.Sonnenschein@Sun.COM				if cr in results:
223*8042SJohn.Sonnenschein@Sun.COM					crs.remove(cr)
224*8042SJohn.Sonnenschein@Sun.COM
225*8042SJohn.Sonnenschein@Sun.COM		return results
226*8042SJohn.Sonnenschein@Sun.COM####################################################################
227*8042SJohn.Sonnenschein@Sun.COMdef ARC(arclist):
228*8042SJohn.Sonnenschein@Sun.COM	opts = {}
229*8042SJohn.Sonnenschein@Sun.COM	url = "http://opensolaris.org/cgi/arc.py"
230*8042SJohn.Sonnenschein@Sun.COM	opts["n"] = str(len(arclist))
231*8042SJohn.Sonnenschein@Sun.COM	for i, arc in enumerate(arclist):
232*8042SJohn.Sonnenschein@Sun.COM		arc, case = arc
233*8042SJohn.Sonnenschein@Sun.COM		opts["arc" + str(i)] = arc
234*8042SJohn.Sonnenschein@Sun.COM		opts["case" + str(i)] = case
235*8042SJohn.Sonnenschein@Sun.COM	req = urllib2.Request(url, urllib.urlencode(opts))
236*8042SJohn.Sonnenschein@Sun.COM	try:
237*8042SJohn.Sonnenschein@Sun.COM		data = urllib2.urlopen(req).readlines()
238*8042SJohn.Sonnenschein@Sun.COM	except urllib2.HTTPError, e:
239*8042SJohn.Sonnenschein@Sun.COM		print "ERROR: HTTP error at " + req.get_ful_url() + \
240*8042SJohn.Sonnenschein@Sun.COM			" got error: " + str(e.code)
241*8042SJohn.Sonnenschein@Sun.COM		raise e
2427078Smjnelson
243*8042SJohn.Sonnenschein@Sun.COM	except urllib2.URLError, e:
244*8042SJohn.Sonnenschein@Sun.COM		print "ERROR: could not connect to " + req.get_ful_url() + \
245*8042SJohn.Sonnenschein@Sun.COM			' got error: "' + e.reason[1] + '"'
246*8042SJohn.Sonnenschein@Sun.COM		raise e
247*8042SJohn.Sonnenschein@Sun.COM	ret = {}
248*8042SJohn.Sonnenschein@Sun.COM	for line in data:
249*8042SJohn.Sonnenschein@Sun.COM		oneline = line.rstrip('\n')
250*8042SJohn.Sonnenschein@Sun.COM		fields = oneline.split('|')
251*8042SJohn.Sonnenschein@Sun.COM		# check if each is valid ( fields[0]::validity )
252*8042SJohn.Sonnenschein@Sun.COM		if fields[0] != "0":
253*8042SJohn.Sonnenschein@Sun.COM			continue
254*8042SJohn.Sonnenschein@Sun.COM		arc, case = fields[1].split(" ")
255*8042SJohn.Sonnenschein@Sun.COM		ret[(arc, case)] = fields[2]
256*8042SJohn.Sonnenschein@Sun.COM	return ret
2577078Smjnelson
2587078Smjnelson####################################################################
2597078Smjnelson
2607078Smjnelson# Pointers to the webrti server hostname & port to use
2617078Smjnelson# Using it directly is probably not *officially* supported, so we'll
2627078Smjnelson# have a pointer to the official `webrticli` command line interface
2637078Smjnelson# if using a direct socket connection fails for some reason, so we
2647078Smjnelson# have a fallback
2657078SmjnelsonWEBRTI_HOST = 'webrti.sfbay.sun.com'
2667078SmjnelsonWEBRTI_PORT = 9188
2677764SJohn.Sonnenschein@Sun.COMWEBRTICLI = '/net/onnv.sfbay.sun.com/export/onnv-gate/public/bin/webrticli'
2687078Smjnelson
2697078Smjnelson
2707078Smjnelsonclass RtiException(Exception):
2717078Smjnelson	def __init__(self, data=''):
2727078Smjnelson		self.data = data
2737078Smjnelson		Exception.__init__(self, data)
2747078Smjnelson
2757078Smjnelson	def __str__(self):
2767078Smjnelson		return "Unknown error: %s" % self.data
2777078Smjnelson
2787078Smjnelsonclass RtiCallFailed(RtiException):
2797078Smjnelson	def __str__(self):
2807078Smjnelson		return "Unable to call webrti: %s" % self.data
2817078Smjnelson
2827078Smjnelsonclass RtiSystemProblem(RtiException):
2837078Smjnelson	def __str__(self):
2847078Smjnelson		return "RTI status cannot be determined: %s" % self.data
2857078Smjnelson
2867078Smjnelsonclass RtiIncorrectCR(RtiException):
2877078Smjnelson	def __str__(self):
2887078Smjnelson		return "Incorrect CR number specified: %s" % self.data
2897078Smjnelson
2907078Smjnelsonclass RtiNotFound(RtiException):
2917078Smjnelson	def __str__(self):
2927078Smjnelson		return "RTI not found: %s" % self.data
2937078Smjnelson
2947078Smjnelsonclass RtiNeedConsolidation(RtiException):
2957078Smjnelson	def __str__(self):
2967078Smjnelson		return "More than one consolidation has this CR: %s" % self.data
2977078Smjnelson
2987078Smjnelsonclass RtiBadGate(RtiException):
2997078Smjnelson	def __str__(self):
3007078Smjnelson		return "Incorrect gate name specified: %s" % self.data
3017078Smjnelson
3027078Smjnelsonclass RtiOffSwan(RtiException):
3037078Smjnelson	def __str__(self):
3047078Smjnelson		return "RTI status checks need SWAN access: %s" % self.data
3057078Smjnelson
3067078SmjnelsonWEBRTI_ERRORS = {
3077078Smjnelson	'1': RtiSystemProblem,
3087078Smjnelson	'2': RtiIncorrectCR,
3097078Smjnelson	'3': RtiNotFound,
3107078Smjnelson	'4': RtiNeedConsolidation,
3117078Smjnelson	'5': RtiBadGate,
3127078Smjnelson}
3137078Smjnelson
3147078Smjnelson# Our Rti object which we'll use to represent an Rti query
3157078Smjnelson# It's really just a wrapper around the Rti connection, and attempts
3167078Smjnelson# to establish a direct socket connection and query the webrti server
3177078Smjnelson# directly (thus avoiding a system/fork/exec call).  If it fails, it
3187078Smjnelson# falls back to the webrticli command line client.
3197078Smjnelson
3207078SmjnelsonreturnCodeRe = re.compile(r'.*RETURN_CODE=(\d+)')
3217078Smjnelsonclass Rti:
3227078Smjnelson	"""Lookup an RTI.
3237078Smjnelson
3247078Smjnelson	Usage:
3257078Smjnelson	r = Rti("6640538")
3267078Smjnelson	print r.rtiNumber();
3277078Smjnelson	"""
3287078Smjnelson
3297078Smjnelson	def __init__(self, cr, gate=None, consolidation=None):
3307078Smjnelson		"""Create an Rti object for the specified change request.
3317078Smjnelson
3327078Smjnelson		Argument:
3337078Smjnelson		cr: change request id
3347078Smjnelson
3357078Smjnelson		Keyword arguments, to limit scope of RTI search:
3367078Smjnelson		gate: path to gate workspace (default=None)
3377078Smjnelson		consolidation: consolidation name (default=None)
3387078Smjnelson		"""
3397078Smjnelson
3407078Smjnelson		bufSz = 1024
3417078Smjnelson		addr = (WEBRTI_HOST, WEBRTI_PORT)
3427078Smjnelson		# If the passed 'cr' was given as an int, then wrap it
3437078Smjnelson		# into a string to make our life easier
3447078Smjnelson		if isinstance(cr, int):
3457078Smjnelson			cr = str(cr)
3467078Smjnelson		self.__queryCr = cr
3477078Smjnelson		self.__queryGate = gate
3487078Smjnelson		self.__queryConsolidation = consolidation
3497078Smjnelson
3507764SJohn.Sonnenschein@Sun.COM		self.__webRtiOutput = []
3517764SJohn.Sonnenschein@Sun.COM		self.__mainCR = []
3527764SJohn.Sonnenschein@Sun.COM		self.__rtiNumber = []
3537764SJohn.Sonnenschein@Sun.COM		self.__consolidation = []
3547764SJohn.Sonnenschein@Sun.COM		self.__project = []
3557764SJohn.Sonnenschein@Sun.COM		self.__status = []
3567764SJohn.Sonnenschein@Sun.COM		self.__rtiType = []
3577078Smjnelson		try:
3587078Smjnelson			# try to use a direct connection to the
3597078Smjnelson			# webrti server first
3607078Smjnelson			sock = socket(AF_INET, SOCK_STREAM)
3617078Smjnelson			sock.connect(addr)
3627078Smjnelson			command = "WEBRTICLI/1.0\nRTIstatus\n%s\n" % cr
3637078Smjnelson			if consolidation:
3647078Smjnelson				command += "-c\n%s\n" % consolidation
3657078Smjnelson			if gate:
3667078Smjnelson				command += "-g\n%s\n" % gate
3677078Smjnelson			command += "\n"
3687078Smjnelson			sock.send(command)
3697078Smjnelson			dataList = []
3707078Smjnelson			# keep receiving data from the socket until the
3717078Smjnelson			# server closes the connection
3727078Smjnelson			stillReceiving = True
3737078Smjnelson			while stillReceiving:
3747078Smjnelson				dataPiece = sock.recv(bufSz)
3757078Smjnelson				if dataPiece:
3767078Smjnelson					dataList.append(dataPiece)
3777078Smjnelson				else:
3787078Smjnelson					stillReceiving = False
3797078Smjnelson			# create the lines, skipping the first
3807078Smjnelson			# ("WEBRTCLI/1.0\n")
3817078Smjnelson			data = '\n'.join(''.join(dataList).split('\n')[1:])
3827078Smjnelson		except:
3837078Smjnelson			if not onSWAN():
3847078Smjnelson				raise RtiOffSwan(cr)
3857078Smjnelson
3867078Smjnelson			if not os.path.exists(WEBRTICLI):
3877078Smjnelson				raise RtiCallFailed('not found')
3887078Smjnelson
3897078Smjnelson			# fallback to the "supported" webrticli interface
3907078Smjnelson			command = WEBRTICLI
3917078Smjnelson			if consolidation:
3927078Smjnelson				command += " -c " + consolidation
3937078Smjnelson			if gate:
3947078Smjnelson				command += " -g " + gate
3957078Smjnelson			command += " RTIstatus " + cr
3967078Smjnelson
3977078Smjnelson			try:
3987078Smjnelson				cliPipe = os.popen(command)
3997078Smjnelson			except:
4007078Smjnelson				# we couldn't call the webrticli for some
4017078Smjnelson				# reason, so return a failure
4027078Smjnelson				raise RtiCallFailed('unknown')
4037078Smjnelson
4047078Smjnelson			data = cliPipe.readline()
4057078Smjnelson
4067078Smjnelson		# parse the data to see if we got a return code
4077078Smjnelson		# if we did, then that's bad.  if we didn't,
4087078Smjnelson		# then our call was successfully
4097078Smjnelson		m = returnCodeRe.search(data)
4107078Smjnelson		if m:
4117078Smjnelson			# we got a return code, set it in our
4127078Smjnelson			# object, set the webRtiOutput for debugging
4137078Smjnelson			# or logging, and return a failure
4147078Smjnelson			if m.group(1) in WEBRTI_ERRORS:
4157078Smjnelson				exc = WEBRTI_ERRORS[m.group(1)]
4167078Smjnelson			else:
4177078Smjnelson				exc = RtiException
4187078Smjnelson			raise exc(data)
4197078Smjnelson
4207764SJohn.Sonnenschein@Sun.COM		data = data.splitlines()
4217078Smjnelson		# At this point, we should have valid data
4227764SJohn.Sonnenschein@Sun.COM		for line in data:
4237764SJohn.Sonnenschein@Sun.COM			line = line.rstrip('\r\n')
4247764SJohn.Sonnenschein@Sun.COM			self.__webRtiOutput.append(line)
4257764SJohn.Sonnenschein@Sun.COM			fields = line.split(':')
4267764SJohn.Sonnenschein@Sun.COM			self.__mainCR.append(fields[0])
4277764SJohn.Sonnenschein@Sun.COM			self.__rtiNumber.append(fields[1])
4287764SJohn.Sonnenschein@Sun.COM			self.__consolidation.append(fields[2])
4297764SJohn.Sonnenschein@Sun.COM			self.__project.append(fields[3])
4307764SJohn.Sonnenschein@Sun.COM			self.__status.append(fields[4])
4317764SJohn.Sonnenschein@Sun.COM			self.__rtiType.append(fields[5])
4327078Smjnelson
4337078Smjnelson	# accessors in case callers need the raw data
4347078Smjnelson	def mainCR(self):
4357078Smjnelson		return self.__mainCR
4367078Smjnelson	def rtiNumber(self):
4377078Smjnelson		return self.__rtiNumber
4387078Smjnelson	def consolidation(self):
4397078Smjnelson		return self.__consolidation
4407078Smjnelson	def project(self):
4417078Smjnelson		return self.__project
4427078Smjnelson	def status(self):
4437078Smjnelson		return self.__status
4447078Smjnelson	def rtiType(self):
4457078Smjnelson		return self.__rtiType
4467078Smjnelson	def queryCr(self):
4477078Smjnelson		return self.__queryCr
4487078Smjnelson	def queryGate(self):
4497078Smjnelson		return self.__queryGate
4507078Smjnelson	def queryConsolidation(self):
4517078Smjnelson		return self.__queryConsolidation
4527078Smjnelson
4537078Smjnelson	# in practice, most callers only care about the following
4547078Smjnelson	def accepted(self):
4557764SJohn.Sonnenschein@Sun.COM		for status in self.__status:
4567764SJohn.Sonnenschein@Sun.COM			if status != "S_ACCEPTED":
4577764SJohn.Sonnenschein@Sun.COM				return False
4587764SJohn.Sonnenschein@Sun.COM		return True
4597078Smjnelson
4607078Smjnelson	# for logging/debugging in case the caller wants the raw webrti output
4617078Smjnelson	def webRtiOutput(self):
4627078Smjnelson		return self.__webRtiOutput
4637078Smjnelson
464