xref: /onnv-gate/usr/src/tools/onbld/Checks/DbLookups.py (revision 12481:f23958781e92)
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#
24*12481SMark.J.Nelson@Oracle.COM# Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
257078Smjnelson#
267078Smjnelson
277078Smjnelson#
287078Smjnelson# Various database lookup classes/methods, i.e.:
297078Smjnelson#     * monaco
307078Smjnelson#     * bugs.opensolaris.org (b.o.o.)
31*12481SMark.J.Nelson@Oracle.COM#     * arc.opensolaris.org/cgi-bin/arc.cgi (for ARC off SWAN)
32*12481SMark.J.Nelson@Oracle.COM#     * candi.sfbay.sun.com/cgi-bin/arc.cgi (for ARC on SWAN)
337078Smjnelson#
347078Smjnelson
359920SMark.J.Nelson@Sun.COMimport csv
367078Smjnelsonimport re
377078Smjnelsonimport urllib
388042SJohn.Sonnenschein@Sun.COMimport urllib2
397078Smjnelsonimport htmllib
407078Smjnelsonimport os
417078Smjnelsonfrom socket import socket, AF_INET, SOCK_STREAM
427078Smjnelson
437078Smjnelsonfrom onbld.Checks import onSWAN
447078Smjnelson
459920SMark.J.Nelson@Sun.COMclass NonExistentBug(Exception):
467078Smjnelson	def __str__(self):
479920SMark.J.Nelson@Sun.COM		return "Bug %s does not exist" % (Exception.__str__(self))
487078Smjnelson
498042SJohn.Sonnenschein@Sun.COMclass BugDBException(Exception):
508042SJohn.Sonnenschein@Sun.COM	def __str__(self):
519920SMark.J.Nelson@Sun.COM		return "Unknown bug database: %s" % (Exception.__str__(self))
527078Smjnelson
537078Smjnelsonclass BugDB(object):
547078Smjnelson	"""Lookup change requests.
557078Smjnelson
567078Smjnelson	Object can be used on or off of SWAN, using either monaco or
577078Smjnelson	bugs.opensolaris.org as a database.
587078Smjnelson
597078Smjnelson	Usage:
607078Smjnelson	bdb = BugDB()
617078Smjnelson	r = bdb.lookup("6455550")
627078Smjnelson	print r["6455550"]["synopsis"]
637078Smjnelson	r = bdb.lookup(["6455550", "6505625"])
647078Smjnelson	print r["6505625"]["synopsis"]
657078Smjnelson	"""
667078Smjnelson
679920SMark.J.Nelson@Sun.COM	def __init__(self, priority = ("bugster",), forceBoo=False):
687078Smjnelson		"""Create a BugDB object.
697078Smjnelson
707078Smjnelson		Keyword argument:
717078Smjnelson		forceBoo: use b.o.o even from SWAN (default=False)
728042SJohn.Sonnenschein@Sun.COM		priority: use bug databases in this order
737078Smjnelson		"""
748042SJohn.Sonnenschein@Sun.COM		self.__validBugDB = ["bugster"]
758042SJohn.Sonnenschein@Sun.COM		self.__onSWAN = not forceBoo and onSWAN()
768042SJohn.Sonnenschein@Sun.COM		for database in priority:
778042SJohn.Sonnenschein@Sun.COM			if database not in self.__validBugDB:
788042SJohn.Sonnenschein@Sun.COM				raise BugDBException, database
798042SJohn.Sonnenschein@Sun.COM		self.__priority = priority
808042SJohn.Sonnenschein@Sun.COM
818042SJohn.Sonnenschein@Sun.COM
828042SJohn.Sonnenschein@Sun.COM	def __boobug(self, cr):
838042SJohn.Sonnenschein@Sun.COM		cr = str(cr)
848042SJohn.Sonnenschein@Sun.COM		url = "http://bugs.opensolaris.org/view_bug.do"
858042SJohn.Sonnenschein@Sun.COM   		req = urllib2.Request(url, urllib.urlencode({"bug_id": cr}))
868042SJohn.Sonnenschein@Sun.COM		results = {}
878042SJohn.Sonnenschein@Sun.COM		try:
888042SJohn.Sonnenschein@Sun.COM			data = urllib2.urlopen(req).readlines()
898042SJohn.Sonnenschein@Sun.COM		except urllib2.HTTPError, e:
908042SJohn.Sonnenschein@Sun.COM			if e.code != 404:
918042SJohn.Sonnenschein@Sun.COM				print "ERROR: HTTP error at " + \
928042SJohn.Sonnenschein@Sun.COM					req.get_full_url() + \
938042SJohn.Sonnenschein@Sun.COM					" got error: " + str(e.code)
948042SJohn.Sonnenschein@Sun.COM				raise e
958042SJohn.Sonnenschein@Sun.COM			else:
968042SJohn.Sonnenschein@Sun.COM				raise NonExistentBug
978042SJohn.Sonnenschein@Sun.COM		except urllib2.URLError, e:
988042SJohn.Sonnenschein@Sun.COM			print "ERROR: could not connect to " + \
998042SJohn.Sonnenschein@Sun.COM				req.get_full_url() + \
1008042SJohn.Sonnenschein@Sun.COM				' got error: "' + e.reason[1] + '"'
1018042SJohn.Sonnenschein@Sun.COM			raise e
1028042SJohn.Sonnenschein@Sun.COM		htmlParser = htmllib.HTMLParser(None)
1038042SJohn.Sonnenschein@Sun.COM		metaHtmlRe = re.compile(r'^<meta name="([^"]+)" content="([^"]*)">$')
1048042SJohn.Sonnenschein@Sun.COM		for line in data:
1058042SJohn.Sonnenschein@Sun.COM			m = metaHtmlRe.search(line)
1068042SJohn.Sonnenschein@Sun.COM			if not m:
1078042SJohn.Sonnenschein@Sun.COM				continue
1088042SJohn.Sonnenschein@Sun.COM			val = urllib.unquote(m.group(2))
1098042SJohn.Sonnenschein@Sun.COM			htmlParser.save_bgn()
1108042SJohn.Sonnenschein@Sun.COM			htmlParser.feed(val)
1118042SJohn.Sonnenschein@Sun.COM			results[m.group(1)] = htmlParser.save_end()
1128042SJohn.Sonnenschein@Sun.COM		htmlParser.close()
1138042SJohn.Sonnenschein@Sun.COM
1148042SJohn.Sonnenschein@Sun.COM		if "synopsis" not in results:
1158042SJohn.Sonnenschein@Sun.COM			raise NonExistentBug(cr)
1168042SJohn.Sonnenschein@Sun.COM
1178042SJohn.Sonnenschein@Sun.COM		results["cr_number"] = cr
1188042SJohn.Sonnenschein@Sun.COM		results["sub_category"] = results.pop("subcategory")
1198042SJohn.Sonnenschein@Sun.COM		results["status"] = results.pop("state")
1208042SJohn.Sonnenschein@Sun.COM		results["date_submitted"] = results.pop("submit_date")
1218042SJohn.Sonnenschein@Sun.COM
1228042SJohn.Sonnenschein@Sun.COM		return results
1238042SJohn.Sonnenschein@Sun.COM
1248042SJohn.Sonnenschein@Sun.COM
1258042SJohn.Sonnenschein@Sun.COM	def __monaco(self, crs):
1268042SJohn.Sonnenschein@Sun.COM		"""Return all info for requested change reports.
1278042SJohn.Sonnenschein@Sun.COM
1288042SJohn.Sonnenschein@Sun.COM		Argument:
1298042SJohn.Sonnenschein@Sun.COM		crs: list of change request ids
1308042SJohn.Sonnenschein@Sun.COM
1318042SJohn.Sonnenschein@Sun.COM		Returns:
1328042SJohn.Sonnenschein@Sun.COM		Dictionary, mapping CR=>dictionary, where the nested dictionary
1338042SJohn.Sonnenschein@Sun.COM		is a mapping of field=>value
1348042SJohn.Sonnenschein@Sun.COM		"""
13511308SOndrej.Kubecka@Sun.COM
1368042SJohn.Sonnenschein@Sun.COM		#
13711308SOndrej.Kubecka@Sun.COM		# See if 'maxcrs' for maximal batch query size is defined
13811308SOndrej.Kubecka@Sun.COM		# if not, default to 200.
13911308SOndrej.Kubecka@Sun.COM		# This clears the 2499 chars query limit
1408042SJohn.Sonnenschein@Sun.COM		#
14111308SOndrej.Kubecka@Sun.COM		try:
14211308SOndrej.Kubecka@Sun.COM			maxcrs
14311308SOndrej.Kubecka@Sun.COM		except NameError:
14411308SOndrej.Kubecka@Sun.COM			maxcrs = 200
14511308SOndrej.Kubecka@Sun.COM
14611308SOndrej.Kubecka@Sun.COM		i = 0
1478042SJohn.Sonnenschein@Sun.COM		results = {}
14811308SOndrej.Kubecka@Sun.COM		data = []
14911308SOndrej.Kubecka@Sun.COM
15011308SOndrej.Kubecka@Sun.COM		while i < len(crs):
15111308SOndrej.Kubecka@Sun.COM			if len(crs) < ( i + maxcrs ):
15211308SOndrej.Kubecka@Sun.COM				j = len(crs)
15311308SOndrej.Kubecka@Sun.COM			else:
15411308SOndrej.Kubecka@Sun.COM				j = i + maxcrs
15511308SOndrej.Kubecka@Sun.COM
15611308SOndrej.Kubecka@Sun.COM			crstmp=crs[i:j]
1578042SJohn.Sonnenschein@Sun.COM
15811308SOndrej.Kubecka@Sun.COM			#
15911308SOndrej.Kubecka@Sun.COM			# We request synopsis last, and split on only
16011308SOndrej.Kubecka@Sun.COM			# the number of separators that we expect to
16111308SOndrej.Kubecka@Sun.COM			# see such that a | in the synopsis doesn't
16211308SOndrej.Kubecka@Sun.COM			# throw us out of whack.
16311308SOndrej.Kubecka@Sun.COM			#
16411308SOndrej.Kubecka@Sun.COM			monacoFields = [ "cr_number", "category", "sub_category",
16511308SOndrej.Kubecka@Sun.COM				"area", "release", "build", "responsible_manager",
16611308SOndrej.Kubecka@Sun.COM				"responsible_engineer", "priority", "status", "sub_status",
16711308SOndrej.Kubecka@Sun.COM				"submitted_by", "date_submitted", "synopsis" ]
16811308SOndrej.Kubecka@Sun.COM			cmd = []
16911308SOndrej.Kubecka@Sun.COM			cmd.append("set What = cr." + ', cr.'.join(monacoFields))
17011308SOndrej.Kubecka@Sun.COM			cmd.append("")
17111308SOndrej.Kubecka@Sun.COM			cmd.append("set Which = cr.cr_number in (" + ','.join(crstmp) +")")
17211308SOndrej.Kubecka@Sun.COM			cmd.append("")
17311308SOndrej.Kubecka@Sun.COM			cmd.append("set FinalClauses = order by cr.cr_number")
17411308SOndrej.Kubecka@Sun.COM			cmd.append("")
17511308SOndrej.Kubecka@Sun.COM			cmd.append("doMeta genQuery cr")
17611308SOndrej.Kubecka@Sun.COM			url = "http://hestia.sfbay.sun.com/cgi-bin/expert?format="
17711308SOndrej.Kubecka@Sun.COM			url += "Pipe-delimited+text;Go=2;no_header=on;cmds="
17811308SOndrej.Kubecka@Sun.COM			url += urllib.quote_plus("\n".join(cmd))
17911308SOndrej.Kubecka@Sun.COM			try:
18011308SOndrej.Kubecka@Sun.COM				data += urllib2.urlopen(url).readlines()
18111308SOndrej.Kubecka@Sun.COM			except urllib2.HTTPError, e:
18211308SOndrej.Kubecka@Sun.COM				print "ERROR: HTTP error at " + url + \
18311308SOndrej.Kubecka@Sun.COM					" got error: " + str(e.code)
18411308SOndrej.Kubecka@Sun.COM				raise e
18511308SOndrej.Kubecka@Sun.COM
18611308SOndrej.Kubecka@Sun.COM			except urllib2.URLError, e:
18711308SOndrej.Kubecka@Sun.COM				print "ERROR: could not connect to " + url + \
18811308SOndrej.Kubecka@Sun.COM					' got error: "' + e.reason[1] + '"'
18911308SOndrej.Kubecka@Sun.COM				raise e
19011308SOndrej.Kubecka@Sun.COM
19111308SOndrej.Kubecka@Sun.COM			i += maxcrs
19211308SOndrej.Kubecka@Sun.COM
1938042SJohn.Sonnenschein@Sun.COM		for line in data:
1948042SJohn.Sonnenschein@Sun.COM			line = line.rstrip('\n')
1958042SJohn.Sonnenschein@Sun.COM			values = line.split('|', len(monacoFields) - 1)
1968042SJohn.Sonnenschein@Sun.COM			v = 0
1978042SJohn.Sonnenschein@Sun.COM			cr = values[0]
1988042SJohn.Sonnenschein@Sun.COM			results[cr] = {}
1998042SJohn.Sonnenschein@Sun.COM			for field in monacoFields:
2008042SJohn.Sonnenschein@Sun.COM				results[cr][field] = values[v]
2018042SJohn.Sonnenschein@Sun.COM				v += 1
20211308SOndrej.Kubecka@Sun.COM
20311308SOndrej.Kubecka@Sun.COM
2048042SJohn.Sonnenschein@Sun.COM		return results
2057078Smjnelson
2067078Smjnelson	def lookup(self, crs):
2077078Smjnelson		"""Return all info for requested change reports.
2087078Smjnelson
2097078Smjnelson		Argument:
2107078Smjnelson		crs: one change request id (may be integer, string, or list),
2117078Smjnelson	             or multiple change request ids (must be a list)
2127078Smjnelson
2137078Smjnelson		Returns:
2147078Smjnelson		Dictionary, mapping CR=>dictionary, where the nested dictionary
2157078Smjnelson		is a mapping of field=>value
2167078Smjnelson		"""
2178042SJohn.Sonnenschein@Sun.COM		results = {}
2187078Smjnelson		if not isinstance(crs, list):
2197078Smjnelson			crs = [str(crs)]
2208042SJohn.Sonnenschein@Sun.COM		for database in self.__priority:
2218042SJohn.Sonnenschein@Sun.COM			if database == "bugster":
2228042SJohn.Sonnenschein@Sun.COM				if self.__onSWAN:
2238042SJohn.Sonnenschein@Sun.COM					results.update(self.__monaco(crs))
2248042SJohn.Sonnenschein@Sun.COM				# else we're off-swan and querying via boo, which we can
2258042SJohn.Sonnenschein@Sun.COM				# only do one bug at a time
2268042SJohn.Sonnenschein@Sun.COM				else:
2278042SJohn.Sonnenschein@Sun.COM					for cr in crs:
2288042SJohn.Sonnenschein@Sun.COM						cr = str(cr)
2298042SJohn.Sonnenschein@Sun.COM						try:
2308042SJohn.Sonnenschein@Sun.COM							results[cr] = self.__boobug(cr)
2318042SJohn.Sonnenschein@Sun.COM						except NonExistentBug:
2328042SJohn.Sonnenschein@Sun.COM							continue
2337078Smjnelson
2348042SJohn.Sonnenschein@Sun.COM			# the CR has already been found by one bug database
2358042SJohn.Sonnenschein@Sun.COM			# so don't bother looking it up in the others
2368042SJohn.Sonnenschein@Sun.COM			for cr in crs:
2378042SJohn.Sonnenschein@Sun.COM				if cr in results:
2388042SJohn.Sonnenschein@Sun.COM					crs.remove(cr)
2398042SJohn.Sonnenschein@Sun.COM
2408042SJohn.Sonnenschein@Sun.COM		return results
2418042SJohn.Sonnenschein@Sun.COM####################################################################
2429920SMark.J.Nelson@Sun.COMclass ARCException(Exception):
2439920SMark.J.Nelson@Sun.COM	"""This covers arc.cgi script failure."""
2449920SMark.J.Nelson@Sun.COM	def __str__(self):
2459920SMark.J.Nelson@Sun.COM		return "Error retrieving ARC data: %s" % (Exception.__str__(self))
2469920SMark.J.Nelson@Sun.COM
2479920SMark.J.Nelson@Sun.COMdef ARC(arclist, arcPath=None):
2489920SMark.J.Nelson@Sun.COM	if not arcPath:
249*12481SMark.J.Nelson@Oracle.COM		if onSWAN():
250*12481SMark.J.Nelson@Oracle.COM			arcPath = "http://candi.sfbay.sun.com/cgi-bin/arc.cgi"
251*12481SMark.J.Nelson@Oracle.COM		else:
252*12481SMark.J.Nelson@Oracle.COM			arcPath = "http://arc.opensolaris.org/cgi-bin/arc.cgi"
2539920SMark.J.Nelson@Sun.COM	fields = ["present", "arc", "year", "case", "status", "title"]
2549920SMark.J.Nelson@Sun.COM	opts = [("case", "%s/%s" % (a, c)) for a, c in arclist]
2559920SMark.J.Nelson@Sun.COM	req = urllib2.Request(arcPath, urllib.urlencode(opts))
2568042SJohn.Sonnenschein@Sun.COM	try:
2578042SJohn.Sonnenschein@Sun.COM		data = urllib2.urlopen(req).readlines()
2588042SJohn.Sonnenschein@Sun.COM	except urllib2.HTTPError, e:
2598174SJohn.Sonnenschein@Sun.COM		print "ERROR: HTTP error at " + req.get_full_url() + \
2608042SJohn.Sonnenschein@Sun.COM			" got error: " + str(e.code)
2618042SJohn.Sonnenschein@Sun.COM		raise e
2627078Smjnelson
2638042SJohn.Sonnenschein@Sun.COM	except urllib2.URLError, e:
2648174SJohn.Sonnenschein@Sun.COM		print "ERROR: could not connect to " + req.get_full_url() + \
2658042SJohn.Sonnenschein@Sun.COM			' got error: "' + e.reason[1] + '"'
2668042SJohn.Sonnenschein@Sun.COM		raise e
2678042SJohn.Sonnenschein@Sun.COM	ret = {}
2689920SMark.J.Nelson@Sun.COM	for line in csv.DictReader(data, fields):
2699920SMark.J.Nelson@Sun.COM		if line["present"] == "exists":
2709920SMark.J.Nelson@Sun.COM			yc = "%s/%s" % (line["year"], line["case"])
2719920SMark.J.Nelson@Sun.COM			ret[(line["arc"], yc)] = line["title"]
2729920SMark.J.Nelson@Sun.COM		elif line["present"] == "fatal":
2739920SMark.J.Nelson@Sun.COM			raise ARCException(line["arc"])
2749920SMark.J.Nelson@Sun.COM
2758042SJohn.Sonnenschein@Sun.COM	return ret
2767078Smjnelson
2777078Smjnelson####################################################################
2787078Smjnelson
2797078Smjnelson# Pointers to the webrti server hostname & port to use
2807078Smjnelson# Using it directly is probably not *officially* supported, so we'll
2817078Smjnelson# have a pointer to the official `webrticli` command line interface
2827078Smjnelson# if using a direct socket connection fails for some reason, so we
2837078Smjnelson# have a fallback
2847078SmjnelsonWEBRTI_HOST = 'webrti.sfbay.sun.com'
2857078SmjnelsonWEBRTI_PORT = 9188
2867764SJohn.Sonnenschein@Sun.COMWEBRTICLI = '/net/onnv.sfbay.sun.com/export/onnv-gate/public/bin/webrticli'
2877078Smjnelson
2887078Smjnelson
2897078Smjnelsonclass RtiException(Exception):
2909920SMark.J.Nelson@Sun.COM	pass
2917078Smjnelson
2927078Smjnelsonclass RtiCallFailed(RtiException):
2937078Smjnelson	def __str__(self):
2949920SMark.J.Nelson@Sun.COM		return "Unable to call webrti: %s" % (RtiException.__str__(self))
2957078Smjnelson
2967078Smjnelsonclass RtiSystemProblem(RtiException):
2977078Smjnelson	def __str__(self):
2989920SMark.J.Nelson@Sun.COM		return "RTI status cannot be determined for CR: %s" % (RtiException.__str__(self))
2997078Smjnelson
3007078Smjnelsonclass RtiIncorrectCR(RtiException):
3017078Smjnelson	def __str__(self):
3029920SMark.J.Nelson@Sun.COM		return "Incorrect CR number specified: %s" % (RtiException.__str__(self))
3037078Smjnelson
3047078Smjnelsonclass RtiNotFound(RtiException):
3057078Smjnelson	def __str__(self):
3069920SMark.J.Nelson@Sun.COM		return "RTI not found for CR: %s" % (RtiException.__str__(self))
3077078Smjnelson
3087078Smjnelsonclass RtiNeedConsolidation(RtiException):
3097078Smjnelson	def __str__(self):
3109920SMark.J.Nelson@Sun.COM		return "More than one consolidation has this CR: %s" % (RtiException.__str__(self))
3117078Smjnelson
3127078Smjnelsonclass RtiBadGate(RtiException):
3137078Smjnelson	def __str__(self):
3149920SMark.J.Nelson@Sun.COM		return "Incorrect gate name specified: %s" % (RtiException.__str__(self))
3159920SMark.J.Nelson@Sun.COM
3169920SMark.J.Nelson@Sun.COMclass RtiUnknownException(Exception):
3179920SMark.J.Nelson@Sun.COM	def __str__(self):
3189920SMark.J.Nelson@Sun.COM		return "Unknown webrti return code: %s" % (RtiException.__str__(self))
3197078Smjnelson
3207078Smjnelsonclass RtiOffSwan(RtiException):
3217078Smjnelson	def __str__(self):
3229920SMark.J.Nelson@Sun.COM		return "RTI status checks need SWAN access: %s" % (RtiException.__str__(self))
3237078Smjnelson
3247078SmjnelsonWEBRTI_ERRORS = {
3257078Smjnelson	'1': RtiSystemProblem,
3267078Smjnelson	'2': RtiIncorrectCR,
3277078Smjnelson	'3': RtiNotFound,
3287078Smjnelson	'4': RtiNeedConsolidation,
3297078Smjnelson	'5': RtiBadGate,
3307078Smjnelson}
3317078Smjnelson
3327078Smjnelson# Our Rti object which we'll use to represent an Rti query
3337078Smjnelson# It's really just a wrapper around the Rti connection, and attempts
3347078Smjnelson# to establish a direct socket connection and query the webrti server
3357078Smjnelson# directly (thus avoiding a system/fork/exec call).  If it fails, it
3367078Smjnelson# falls back to the webrticli command line client.
3377078Smjnelson
3387078SmjnelsonreturnCodeRe = re.compile(r'.*RETURN_CODE=(\d+)')
3397078Smjnelsonclass Rti:
3407078Smjnelson	"""Lookup an RTI.
3417078Smjnelson
3427078Smjnelson	Usage:
3437078Smjnelson	r = Rti("6640538")
3447078Smjnelson	print r.rtiNumber();
3457078Smjnelson	"""
3467078Smjnelson
3477078Smjnelson	def __init__(self, cr, gate=None, consolidation=None):
3487078Smjnelson		"""Create an Rti object for the specified change request.
3497078Smjnelson
3507078Smjnelson		Argument:
3517078Smjnelson		cr: change request id
3527078Smjnelson
3537078Smjnelson		Keyword arguments, to limit scope of RTI search:
3547078Smjnelson		gate: path to gate workspace (default=None)
3557078Smjnelson		consolidation: consolidation name (default=None)
3567078Smjnelson		"""
3577078Smjnelson
3587078Smjnelson		bufSz = 1024
3597078Smjnelson		addr = (WEBRTI_HOST, WEBRTI_PORT)
3607078Smjnelson		# If the passed 'cr' was given as an int, then wrap it
3617078Smjnelson		# into a string to make our life easier
3627078Smjnelson		if isinstance(cr, int):
3637078Smjnelson			cr = str(cr)
3647078Smjnelson		self.__queryCr = cr
3657078Smjnelson		self.__queryGate = gate
3667078Smjnelson		self.__queryConsolidation = consolidation
3677078Smjnelson
3687764SJohn.Sonnenschein@Sun.COM		self.__webRtiOutput = []
3697764SJohn.Sonnenschein@Sun.COM		self.__mainCR = []
3707764SJohn.Sonnenschein@Sun.COM		self.__rtiNumber = []
3717764SJohn.Sonnenschein@Sun.COM		self.__consolidation = []
3727764SJohn.Sonnenschein@Sun.COM		self.__project = []
3737764SJohn.Sonnenschein@Sun.COM		self.__status = []
3747764SJohn.Sonnenschein@Sun.COM		self.__rtiType = []
3757078Smjnelson		try:
3767078Smjnelson			# try to use a direct connection to the
3777078Smjnelson			# webrti server first
3787078Smjnelson			sock = socket(AF_INET, SOCK_STREAM)
3797078Smjnelson			sock.connect(addr)
3807078Smjnelson			command = "WEBRTICLI/1.0\nRTIstatus\n%s\n" % cr
3817078Smjnelson			if consolidation:
3827078Smjnelson				command += "-c\n%s\n" % consolidation
3837078Smjnelson			if gate:
3847078Smjnelson				command += "-g\n%s\n" % gate
3857078Smjnelson			command += "\n"
3867078Smjnelson			sock.send(command)
3877078Smjnelson			dataList = []
3887078Smjnelson			# keep receiving data from the socket until the
3897078Smjnelson			# server closes the connection
3907078Smjnelson			stillReceiving = True
3917078Smjnelson			while stillReceiving:
3927078Smjnelson				dataPiece = sock.recv(bufSz)
3937078Smjnelson				if dataPiece:
3947078Smjnelson					dataList.append(dataPiece)
3957078Smjnelson				else:
3967078Smjnelson					stillReceiving = False
3977078Smjnelson			# create the lines, skipping the first
3987078Smjnelson			# ("WEBRTCLI/1.0\n")
3997078Smjnelson			data = '\n'.join(''.join(dataList).split('\n')[1:])
4007078Smjnelson		except:
4017078Smjnelson			if not onSWAN():
4027078Smjnelson				raise RtiOffSwan(cr)
4037078Smjnelson
4047078Smjnelson			if not os.path.exists(WEBRTICLI):
4057078Smjnelson				raise RtiCallFailed('not found')
4067078Smjnelson
4077078Smjnelson			# fallback to the "supported" webrticli interface
4087078Smjnelson			command = WEBRTICLI
4097078Smjnelson			if consolidation:
4107078Smjnelson				command += " -c " + consolidation
4117078Smjnelson			if gate:
4127078Smjnelson				command += " -g " + gate
4137078Smjnelson			command += " RTIstatus " + cr
4147078Smjnelson
4157078Smjnelson			try:
4167078Smjnelson				cliPipe = os.popen(command)
4177078Smjnelson			except:
4187078Smjnelson				# we couldn't call the webrticli for some
4197078Smjnelson				# reason, so return a failure
4207078Smjnelson				raise RtiCallFailed('unknown')
4217078Smjnelson
4227078Smjnelson			data = cliPipe.readline()
4237078Smjnelson
4247078Smjnelson		# parse the data to see if we got a return code
4257078Smjnelson		# if we did, then that's bad.  if we didn't,
4269920SMark.J.Nelson@Sun.COM		# then our call was successful
4277078Smjnelson		m = returnCodeRe.search(data)
4287078Smjnelson		if m:
4299920SMark.J.Nelson@Sun.COM			rc = m.group(1)
4307078Smjnelson			# we got a return code, set it in our
4317078Smjnelson			# object, set the webRtiOutput for debugging
4327078Smjnelson			# or logging, and return a failure
4339920SMark.J.Nelson@Sun.COM			if rc in WEBRTI_ERRORS:
4349920SMark.J.Nelson@Sun.COM				exc = WEBRTI_ERRORS[rc]
4359920SMark.J.Nelson@Sun.COM				if exc == RtiBadGate:
4369920SMark.J.Nelson@Sun.COM					edata = gate
4379920SMark.J.Nelson@Sun.COM				else:
4389920SMark.J.Nelson@Sun.COM					edata = cr
4397078Smjnelson			else:
4409920SMark.J.Nelson@Sun.COM				exc = RtiUnknownException
4419920SMark.J.Nelson@Sun.COM				edata = rc
4429920SMark.J.Nelson@Sun.COM			raise exc(edata)
4437078Smjnelson
4447764SJohn.Sonnenschein@Sun.COM		data = data.splitlines()
4457078Smjnelson		# At this point, we should have valid data
4467764SJohn.Sonnenschein@Sun.COM		for line in data:
4477764SJohn.Sonnenschein@Sun.COM			line = line.rstrip('\r\n')
4487764SJohn.Sonnenschein@Sun.COM			self.__webRtiOutput.append(line)
4497764SJohn.Sonnenschein@Sun.COM			fields = line.split(':')
4507764SJohn.Sonnenschein@Sun.COM			self.__mainCR.append(fields[0])
4517764SJohn.Sonnenschein@Sun.COM			self.__rtiNumber.append(fields[1])
4527764SJohn.Sonnenschein@Sun.COM			self.__consolidation.append(fields[2])
4537764SJohn.Sonnenschein@Sun.COM			self.__project.append(fields[3])
4547764SJohn.Sonnenschein@Sun.COM			self.__status.append(fields[4])
4557764SJohn.Sonnenschein@Sun.COM			self.__rtiType.append(fields[5])
4567078Smjnelson
4577078Smjnelson	# accessors in case callers need the raw data
4587078Smjnelson	def mainCR(self):
4597078Smjnelson		return self.__mainCR
4607078Smjnelson	def rtiNumber(self):
4617078Smjnelson		return self.__rtiNumber
4627078Smjnelson	def consolidation(self):
4637078Smjnelson		return self.__consolidation
4647078Smjnelson	def project(self):
4657078Smjnelson		return self.__project
4667078Smjnelson	def status(self):
4677078Smjnelson		return self.__status
4687078Smjnelson	def rtiType(self):
4697078Smjnelson		return self.__rtiType
4707078Smjnelson	def queryCr(self):
4717078Smjnelson		return self.__queryCr
4727078Smjnelson	def queryGate(self):
4737078Smjnelson		return self.__queryGate
4747078Smjnelson	def queryConsolidation(self):
4757078Smjnelson		return self.__queryConsolidation
4767078Smjnelson
4777078Smjnelson	# in practice, most callers only care about the following
4787078Smjnelson	def accepted(self):
4797764SJohn.Sonnenschein@Sun.COM		for status in self.__status:
4807764SJohn.Sonnenschein@Sun.COM			if status != "S_ACCEPTED":
4817764SJohn.Sonnenschein@Sun.COM				return False
4827764SJohn.Sonnenschein@Sun.COM		return True
4837078Smjnelson
4847078Smjnelson	# for logging/debugging in case the caller wants the raw webrti output
4857078Smjnelson	def webRtiOutput(self):
4867078Smjnelson		return self.__webRtiOutput
4877078Smjnelson
488