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