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