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