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*84bb51dbSMark J. Nelson# Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. 25cdf0c1d5Smjnelson# 26cdf0c1d5Smjnelson 27cdf0c1d5Smjnelson# 28cdf0c1d5Smjnelson# Various database lookup classes/methods, i.e.: 29cdf0c1d5Smjnelson# * monaco 30cdf0c1d5Smjnelson# * bugs.opensolaris.org (b.o.o.) 31*84bb51dbSMark J. Nelson# * arc.opensolaris.org/cgi-bin/arc.cgi (for ARC off SWAN) 32*84bb51dbSMark J. Nelson# * candi.sfbay.sun.com/cgi-bin/arc.cgi (for ARC on SWAN) 33cdf0c1d5Smjnelson# 34cdf0c1d5Smjnelson 3541a5f560SMark 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 4541a5f560SMark J. Nelsonclass NonExistentBug(Exception): 46cdf0c1d5Smjnelson def __str__(self): 4741a5f560SMark J. Nelson return "Bug %s does not exist" % (Exception.__str__(self)) 48cdf0c1d5Smjnelson 49c08a253cSJohn Sonnenscheinclass BugDBException(Exception): 50c08a253cSJohn Sonnenschein def __str__(self): 5141a5f560SMark 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 # 13752ddba99SOndrej Kubecka # See if 'maxcrs' for maximal batch query size is defined 13852ddba99SOndrej Kubecka # if not, default to 200. 13952ddba99SOndrej Kubecka # This clears the 2499 chars query limit 14052ddba99SOndrej Kubecka # 14152ddba99SOndrej Kubecka try: 14252ddba99SOndrej Kubecka maxcrs 14352ddba99SOndrej Kubecka except NameError: 14452ddba99SOndrej Kubecka maxcrs = 200 14552ddba99SOndrej Kubecka 14652ddba99SOndrej Kubecka i = 0 14752ddba99SOndrej Kubecka results = {} 14852ddba99SOndrej Kubecka data = [] 14952ddba99SOndrej Kubecka 15052ddba99SOndrej Kubecka while i < len(crs): 15152ddba99SOndrej Kubecka if len(crs) < ( i + maxcrs ): 15252ddba99SOndrej Kubecka j = len(crs) 15352ddba99SOndrej Kubecka else: 15452ddba99SOndrej Kubecka j = i + maxcrs 15552ddba99SOndrej Kubecka 15652ddba99SOndrej Kubecka crstmp=crs[i:j] 15752ddba99SOndrej Kubecka 15852ddba99SOndrej Kubecka # 159c08a253cSJohn Sonnenschein # We request synopsis last, and split on only 160c08a253cSJohn Sonnenschein # the number of separators that we expect to 161c08a253cSJohn Sonnenschein # see such that a | in the synopsis doesn't 162c08a253cSJohn Sonnenschein # throw us out of whack. 163c08a253cSJohn Sonnenschein # 164c08a253cSJohn Sonnenschein monacoFields = [ "cr_number", "category", "sub_category", 165c08a253cSJohn Sonnenschein "area", "release", "build", "responsible_manager", 166c08a253cSJohn Sonnenschein "responsible_engineer", "priority", "status", "sub_status", 167c08a253cSJohn Sonnenschein "submitted_by", "date_submitted", "synopsis" ] 168c08a253cSJohn Sonnenschein cmd = [] 169c08a253cSJohn Sonnenschein cmd.append("set What = cr." + ', cr.'.join(monacoFields)) 170c08a253cSJohn Sonnenschein cmd.append("") 17152ddba99SOndrej Kubecka cmd.append("set Which = cr.cr_number in (" + ','.join(crstmp) +")") 172c08a253cSJohn Sonnenschein cmd.append("") 173c08a253cSJohn Sonnenschein cmd.append("set FinalClauses = order by cr.cr_number") 174c08a253cSJohn Sonnenschein cmd.append("") 175c08a253cSJohn Sonnenschein cmd.append("doMeta genQuery cr") 176c08a253cSJohn Sonnenschein url = "http://hestia.sfbay.sun.com/cgi-bin/expert?format=" 177c08a253cSJohn Sonnenschein url += "Pipe-delimited+text;Go=2;no_header=on;cmds=" 178c08a253cSJohn Sonnenschein url += urllib.quote_plus("\n".join(cmd)) 179c08a253cSJohn Sonnenschein try: 18052ddba99SOndrej Kubecka data += urllib2.urlopen(url).readlines() 181c08a253cSJohn Sonnenschein except urllib2.HTTPError, e: 182c08a253cSJohn Sonnenschein print "ERROR: HTTP error at " + url + \ 183c08a253cSJohn Sonnenschein " got error: " + str(e.code) 184c08a253cSJohn Sonnenschein raise e 185c08a253cSJohn Sonnenschein 186c08a253cSJohn Sonnenschein except urllib2.URLError, e: 187c08a253cSJohn Sonnenschein print "ERROR: could not connect to " + url + \ 188c08a253cSJohn Sonnenschein ' got error: "' + e.reason[1] + '"' 189c08a253cSJohn Sonnenschein raise e 19052ddba99SOndrej Kubecka 19152ddba99SOndrej Kubecka i += maxcrs 19252ddba99SOndrej Kubecka 193c08a253cSJohn Sonnenschein for line in data: 194c08a253cSJohn Sonnenschein line = line.rstrip('\n') 195c08a253cSJohn Sonnenschein values = line.split('|', len(monacoFields) - 1) 196c08a253cSJohn Sonnenschein v = 0 197c08a253cSJohn Sonnenschein cr = values[0] 198c08a253cSJohn Sonnenschein results[cr] = {} 199c08a253cSJohn Sonnenschein for field in monacoFields: 200c08a253cSJohn Sonnenschein results[cr][field] = values[v] 201c08a253cSJohn Sonnenschein v += 1 20252ddba99SOndrej Kubecka 20352ddba99SOndrej Kubecka 204c08a253cSJohn Sonnenschein return results 205cdf0c1d5Smjnelson 206cdf0c1d5Smjnelson def lookup(self, crs): 207cdf0c1d5Smjnelson """Return all info for requested change reports. 208cdf0c1d5Smjnelson 209cdf0c1d5Smjnelson Argument: 210cdf0c1d5Smjnelson crs: one change request id (may be integer, string, or list), 211cdf0c1d5Smjnelson or multiple change request ids (must be a list) 212cdf0c1d5Smjnelson 213cdf0c1d5Smjnelson Returns: 214cdf0c1d5Smjnelson Dictionary, mapping CR=>dictionary, where the nested dictionary 215cdf0c1d5Smjnelson is a mapping of field=>value 216cdf0c1d5Smjnelson """ 217c08a253cSJohn Sonnenschein results = {} 218cdf0c1d5Smjnelson if not isinstance(crs, list): 219cdf0c1d5Smjnelson crs = [str(crs)] 220c08a253cSJohn Sonnenschein for database in self.__priority: 221c08a253cSJohn Sonnenschein if database == "bugster": 222cdf0c1d5Smjnelson if self.__onSWAN: 223c08a253cSJohn Sonnenschein results.update(self.__monaco(crs)) 224cdf0c1d5Smjnelson # else we're off-swan and querying via boo, which we can 225cdf0c1d5Smjnelson # only do one bug at a time 226c08a253cSJohn Sonnenschein else: 227cdf0c1d5Smjnelson for cr in crs: 228cdf0c1d5Smjnelson cr = str(cr) 229cdf0c1d5Smjnelson try: 230c08a253cSJohn Sonnenschein results[cr] = self.__boobug(cr) 231cdf0c1d5Smjnelson except NonExistentBug: 232cdf0c1d5Smjnelson continue 233cdf0c1d5Smjnelson 234c08a253cSJohn Sonnenschein # the CR has already been found by one bug database 235c08a253cSJohn Sonnenschein # so don't bother looking it up in the others 236c08a253cSJohn Sonnenschein for cr in crs: 237c08a253cSJohn Sonnenschein if cr in results: 238c08a253cSJohn Sonnenschein crs.remove(cr) 239cdf0c1d5Smjnelson 240cdf0c1d5Smjnelson return results 241cdf0c1d5Smjnelson#################################################################### 24241a5f560SMark J. Nelsonclass ARCException(Exception): 24341a5f560SMark J. Nelson """This covers arc.cgi script failure.""" 24441a5f560SMark J. Nelson def __str__(self): 24541a5f560SMark J. Nelson return "Error retrieving ARC data: %s" % (Exception.__str__(self)) 24641a5f560SMark J. Nelson 24741a5f560SMark J. Nelsondef ARC(arclist, arcPath=None): 24841a5f560SMark J. Nelson if not arcPath: 249*84bb51dbSMark J. Nelson if onSWAN(): 250*84bb51dbSMark J. Nelson arcPath = "http://candi.sfbay.sun.com/cgi-bin/arc.cgi" 251*84bb51dbSMark J. Nelson else: 25241a5f560SMark J. Nelson arcPath = "http://arc.opensolaris.org/cgi-bin/arc.cgi" 25341a5f560SMark J. Nelson fields = ["present", "arc", "year", "case", "status", "title"] 25441a5f560SMark J. Nelson opts = [("case", "%s/%s" % (a, c)) for a, c in arclist] 25541a5f560SMark J. Nelson req = urllib2.Request(arcPath, urllib.urlencode(opts)) 256c08a253cSJohn Sonnenschein try: 257c08a253cSJohn Sonnenschein data = urllib2.urlopen(req).readlines() 258c08a253cSJohn Sonnenschein except urllib2.HTTPError, e: 2597199625bSJohn Sonnenschein print "ERROR: HTTP error at " + req.get_full_url() + \ 260c08a253cSJohn Sonnenschein " got error: " + str(e.code) 261c08a253cSJohn Sonnenschein raise e 262cdf0c1d5Smjnelson 263c08a253cSJohn Sonnenschein except urllib2.URLError, e: 2647199625bSJohn Sonnenschein print "ERROR: could not connect to " + req.get_full_url() + \ 265c08a253cSJohn Sonnenschein ' got error: "' + e.reason[1] + '"' 266c08a253cSJohn Sonnenschein raise e 267c08a253cSJohn Sonnenschein ret = {} 26841a5f560SMark J. Nelson for line in csv.DictReader(data, fields): 26941a5f560SMark J. Nelson if line["present"] == "exists": 27041a5f560SMark J. Nelson yc = "%s/%s" % (line["year"], line["case"]) 27141a5f560SMark J. Nelson ret[(line["arc"], yc)] = line["title"] 27241a5f560SMark J. Nelson elif line["present"] == "fatal": 27341a5f560SMark J. Nelson raise ARCException(line["arc"]) 27441a5f560SMark J. Nelson 275c08a253cSJohn Sonnenschein return ret 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 28681540946SJohn SonnenscheinWEBRTICLI = '/net/onnv.sfbay.sun.com/export/onnv-gate/public/bin/webrticli' 287cdf0c1d5Smjnelson 288cdf0c1d5Smjnelson 289cdf0c1d5Smjnelsonclass RtiException(Exception): 29041a5f560SMark J. Nelson pass 291cdf0c1d5Smjnelson 292cdf0c1d5Smjnelsonclass RtiCallFailed(RtiException): 293cdf0c1d5Smjnelson def __str__(self): 29441a5f560SMark J. Nelson return "Unable to call webrti: %s" % (RtiException.__str__(self)) 295cdf0c1d5Smjnelson 296cdf0c1d5Smjnelsonclass RtiSystemProblem(RtiException): 297cdf0c1d5Smjnelson def __str__(self): 29841a5f560SMark J. Nelson return "RTI status cannot be determined for CR: %s" % (RtiException.__str__(self)) 299cdf0c1d5Smjnelson 300cdf0c1d5Smjnelsonclass RtiIncorrectCR(RtiException): 301cdf0c1d5Smjnelson def __str__(self): 30241a5f560SMark J. Nelson return "Incorrect CR number specified: %s" % (RtiException.__str__(self)) 303cdf0c1d5Smjnelson 304cdf0c1d5Smjnelsonclass RtiNotFound(RtiException): 305cdf0c1d5Smjnelson def __str__(self): 30641a5f560SMark J. Nelson return "RTI not found for CR: %s" % (RtiException.__str__(self)) 307cdf0c1d5Smjnelson 308cdf0c1d5Smjnelsonclass RtiNeedConsolidation(RtiException): 309cdf0c1d5Smjnelson def __str__(self): 31041a5f560SMark J. Nelson return "More than one consolidation has this CR: %s" % (RtiException.__str__(self)) 311cdf0c1d5Smjnelson 312cdf0c1d5Smjnelsonclass RtiBadGate(RtiException): 313cdf0c1d5Smjnelson def __str__(self): 31441a5f560SMark J. Nelson return "Incorrect gate name specified: %s" % (RtiException.__str__(self)) 31541a5f560SMark J. Nelson 31641a5f560SMark J. Nelsonclass RtiUnknownException(Exception): 31741a5f560SMark J. Nelson def __str__(self): 31841a5f560SMark J. Nelson return "Unknown webrti return code: %s" % (RtiException.__str__(self)) 319cdf0c1d5Smjnelson 320cdf0c1d5Smjnelsonclass RtiOffSwan(RtiException): 321cdf0c1d5Smjnelson def __str__(self): 32241a5f560SMark J. Nelson return "RTI status checks need SWAN access: %s" % (RtiException.__str__(self)) 323cdf0c1d5Smjnelson 324cdf0c1d5SmjnelsonWEBRTI_ERRORS = { 325cdf0c1d5Smjnelson '1': RtiSystemProblem, 326cdf0c1d5Smjnelson '2': RtiIncorrectCR, 327cdf0c1d5Smjnelson '3': RtiNotFound, 328cdf0c1d5Smjnelson '4': RtiNeedConsolidation, 329cdf0c1d5Smjnelson '5': RtiBadGate, 330cdf0c1d5Smjnelson} 331cdf0c1d5Smjnelson 332cdf0c1d5Smjnelson# Our Rti object which we'll use to represent an Rti query 333cdf0c1d5Smjnelson# It's really just a wrapper around the Rti connection, and attempts 334cdf0c1d5Smjnelson# to establish a direct socket connection and query the webrti server 335cdf0c1d5Smjnelson# directly (thus avoiding a system/fork/exec call). If it fails, it 336cdf0c1d5Smjnelson# falls back to the webrticli command line client. 337cdf0c1d5Smjnelson 338cdf0c1d5SmjnelsonreturnCodeRe = re.compile(r'.*RETURN_CODE=(\d+)') 339cdf0c1d5Smjnelsonclass Rti: 340cdf0c1d5Smjnelson """Lookup an RTI. 341cdf0c1d5Smjnelson 342cdf0c1d5Smjnelson Usage: 343cdf0c1d5Smjnelson r = Rti("6640538") 344cdf0c1d5Smjnelson print r.rtiNumber(); 345cdf0c1d5Smjnelson """ 346cdf0c1d5Smjnelson 347cdf0c1d5Smjnelson def __init__(self, cr, gate=None, consolidation=None): 348cdf0c1d5Smjnelson """Create an Rti object for the specified change request. 349cdf0c1d5Smjnelson 350cdf0c1d5Smjnelson Argument: 351cdf0c1d5Smjnelson cr: change request id 352cdf0c1d5Smjnelson 353cdf0c1d5Smjnelson Keyword arguments, to limit scope of RTI search: 354cdf0c1d5Smjnelson gate: path to gate workspace (default=None) 355cdf0c1d5Smjnelson consolidation: consolidation name (default=None) 356cdf0c1d5Smjnelson """ 357cdf0c1d5Smjnelson 358cdf0c1d5Smjnelson bufSz = 1024 359cdf0c1d5Smjnelson addr = (WEBRTI_HOST, WEBRTI_PORT) 360cdf0c1d5Smjnelson # If the passed 'cr' was given as an int, then wrap it 361cdf0c1d5Smjnelson # into a string to make our life easier 362cdf0c1d5Smjnelson if isinstance(cr, int): 363cdf0c1d5Smjnelson cr = str(cr) 364cdf0c1d5Smjnelson self.__queryCr = cr 365cdf0c1d5Smjnelson self.__queryGate = gate 366cdf0c1d5Smjnelson self.__queryConsolidation = consolidation 367cdf0c1d5Smjnelson 36881540946SJohn Sonnenschein self.__webRtiOutput = [] 36981540946SJohn Sonnenschein self.__mainCR = [] 37081540946SJohn Sonnenschein self.__rtiNumber = [] 37181540946SJohn Sonnenschein self.__consolidation = [] 37281540946SJohn Sonnenschein self.__project = [] 37381540946SJohn Sonnenschein self.__status = [] 37481540946SJohn Sonnenschein self.__rtiType = [] 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, 42641a5f560SMark J. Nelson # then our call was successful 427cdf0c1d5Smjnelson m = returnCodeRe.search(data) 428cdf0c1d5Smjnelson if m: 42941a5f560SMark J. Nelson rc = m.group(1) 430cdf0c1d5Smjnelson # we got a return code, set it in our 431cdf0c1d5Smjnelson # object, set the webRtiOutput for debugging 432cdf0c1d5Smjnelson # or logging, and return a failure 43341a5f560SMark J. Nelson if rc in WEBRTI_ERRORS: 43441a5f560SMark J. Nelson exc = WEBRTI_ERRORS[rc] 43541a5f560SMark J. Nelson if exc == RtiBadGate: 43641a5f560SMark J. Nelson edata = gate 437cdf0c1d5Smjnelson else: 43841a5f560SMark J. Nelson edata = cr 43941a5f560SMark J. Nelson else: 44041a5f560SMark J. Nelson exc = RtiUnknownException 44141a5f560SMark J. Nelson edata = rc 44241a5f560SMark J. Nelson raise exc(edata) 443cdf0c1d5Smjnelson 44481540946SJohn Sonnenschein data = data.splitlines() 445cdf0c1d5Smjnelson # At this point, we should have valid data 44681540946SJohn Sonnenschein for line in data: 44781540946SJohn Sonnenschein line = line.rstrip('\r\n') 44881540946SJohn Sonnenschein self.__webRtiOutput.append(line) 44981540946SJohn Sonnenschein fields = line.split(':') 45081540946SJohn Sonnenschein self.__mainCR.append(fields[0]) 45181540946SJohn Sonnenschein self.__rtiNumber.append(fields[1]) 45281540946SJohn Sonnenschein self.__consolidation.append(fields[2]) 45381540946SJohn Sonnenschein self.__project.append(fields[3]) 45481540946SJohn Sonnenschein self.__status.append(fields[4]) 45581540946SJohn Sonnenschein self.__rtiType.append(fields[5]) 456cdf0c1d5Smjnelson 457cdf0c1d5Smjnelson # accessors in case callers need the raw data 458cdf0c1d5Smjnelson def mainCR(self): 459cdf0c1d5Smjnelson return self.__mainCR 460cdf0c1d5Smjnelson def rtiNumber(self): 461cdf0c1d5Smjnelson return self.__rtiNumber 462cdf0c1d5Smjnelson def consolidation(self): 463cdf0c1d5Smjnelson return self.__consolidation 464cdf0c1d5Smjnelson def project(self): 465cdf0c1d5Smjnelson return self.__project 466cdf0c1d5Smjnelson def status(self): 467cdf0c1d5Smjnelson return self.__status 468cdf0c1d5Smjnelson def rtiType(self): 469cdf0c1d5Smjnelson return self.__rtiType 470cdf0c1d5Smjnelson def queryCr(self): 471cdf0c1d5Smjnelson return self.__queryCr 472cdf0c1d5Smjnelson def queryGate(self): 473cdf0c1d5Smjnelson return self.__queryGate 474cdf0c1d5Smjnelson def queryConsolidation(self): 475cdf0c1d5Smjnelson return self.__queryConsolidation 476cdf0c1d5Smjnelson 477cdf0c1d5Smjnelson # in practice, most callers only care about the following 478cdf0c1d5Smjnelson def accepted(self): 47981540946SJohn Sonnenschein for status in self.__status: 48081540946SJohn Sonnenschein if status != "S_ACCEPTED": 48181540946SJohn Sonnenschein return False 48281540946SJohn Sonnenschein return True 483cdf0c1d5Smjnelson 484cdf0c1d5Smjnelson # for logging/debugging in case the caller wants the raw webrti output 485cdf0c1d5Smjnelson def webRtiOutput(self): 486cdf0c1d5Smjnelson return self.__webRtiOutput 487cdf0c1d5Smjnelson 488