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