Skip to content

Commit 1b5e77c

Browse files
committed
scripts/python/module/PyNUT.py.in: refactor with an error-logging __send() [#3509]
Signed-off-by: Jim Klimov <jimklimov+nut@gmail.com>
1 parent 3e675fe commit 1b5e77c

1 file changed

Lines changed: 38 additions & 27 deletions

File tree

scripts/python/module/PyNUT.py.in

Lines changed: 38 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -712,10 +712,19 @@ certhost : Optional dict or list of dict/lists: {hostname: [certname, certver
712712
def __del__( self ) :
713713
""" Class destructor method """
714714
try :
715-
self.__srv_handler.send( b"LOGOUT\n" )
715+
self.__send( b"LOGOUT\n" )
716716
except :
717717
pass
718718

719+
def __send(self, data):
720+
""" Internal method to send data through the socket with error handling """
721+
try:
722+
self.__srv_handler.sendall(data)
723+
except (AttributeError, socket.error) as e:
724+
if self.__debug:
725+
print("[DEBUG] Send failed: %s" % str(e))
726+
raise e
727+
719728
def __read_until(self, finished_reading_data):
720729
data = self.__recv_leftover
721730
while True:
@@ -753,7 +762,7 @@ if something goes wrong.
753762
if self.__use_ssl :
754763
if self.__debug :
755764
print( "[DEBUG] Requesting STARTTLS" )
756-
self.__srv_handler.send( b"STARTTLS\n" )
765+
self.__send( b"STARTTLS\n" )
757766
result = self.__read_until( b"\n" )
758767
if result[:11] == b"OK STARTTLS" :
759768
if self.__debug :
@@ -806,19 +815,19 @@ if something goes wrong.
806815
self.__use_ssl = False
807816

808817
if self.__login != None :
809-
self.__srv_handler.send( ("USERNAME %s\n" % self.__login).encode('ascii') )
818+
self.__send( ("USERNAME %s\n" % self.__login).encode('ascii') )
810819
result = self.__read_until( b"\n" )
811820
if result[:2] != b"OK" :
812821
raise PyNUTError( result.replace( b"\n", b"" ).decode('ascii') )
813822

814823
if self.__password != None :
815-
self.__srv_handler.send( ("PASSWORD %s\n" % self.__password).encode('ascii') )
824+
self.__send( ("PASSWORD %s\n" % self.__password).encode('ascii') )
816825
result = self.__read_until( b"\n" )
817826
if result[:2] != b"OK" :
818827
if result == b"ERR INVALID-ARGUMENT\n" :
819828
# Quote the password (if it has whitespace etc)
820829
# TODO: Escape special chard like NUT does?
821-
self.__srv_handler.send( ("PASSWORD \"%s\"\n" % self.__password).encode('ascii') )
830+
self.__send( ("PASSWORD \"%s\"\n" % self.__password).encode('ascii') )
822831
result = self.__read_until( b"\n" )
823832
if result[:2] != b"OK" :
824833
raise PyNUTError( result.replace( b"\n", b"" ).decode('ascii') )
@@ -849,7 +858,7 @@ if something goes wrong.
849858
# TOTHINK # raise PyNUTError( "Invalid setting for TRACKING mode was requested" )
850859
return None
851860

852-
self.__srv_handler.send( ("SET TRACKING %s\n" % value).encode('ascii') )
861+
self.__send( ("SET TRACKING %s\n" % value).encode('ascii') )
853862
result = self.__read_until( b"\n" )
854863
if result == b"OK\n" :
855864
self.__tracking = value
@@ -879,7 +888,7 @@ if something goes wrong.
879888
if self.__debug :
880889
print( "[DEBUG] GetTrackingResult for %s" % tracking_id )
881890

882-
self.__srv_handler.send( ("GET TRACKING %s\n" % tracking_id).encode('ascii') )
891+
self.__send( ("GET TRACKING %s\n" % tracking_id).encode('ascii') )
883892
result = self.__read_until( b"\n" )
884893
if result in [b"PENDING\n", b"SUCCESS\n"]:
885894
return result.replace( b"\n", b"" ).decode('ascii')
@@ -929,12 +938,14 @@ if something goes wrong.
929938
"""
930939
result = None
931940
try:
932-
self.__srv_handler.send( ("PROTVER\n").encode('ascii') )
941+
self.__send( ("PROTVER\n").encode('ascii') )
933942
result = self.__read_until( b"\n" )
934943
except PyNUTError as ignored:
935944
# Deprecated and hidden, but may be what ancient NUT servers say
936945
# May throw if the error is due to (non-)connection
937-
self.__srv_handler.send( ("NETVER\n").encode('ascii') )
946+
# Here we assume that any other exceptions are due to broken
947+
# connection etc. and forward them to caller right away.
948+
self.__send( ("NETVER\n").encode('ascii') )
938949
result = self.__read_until( b"\n" )
939950

940951
# print ( "[DEBUG] isValidProtocolVersion: version_re='%s' result='%s'" % (str(version_re), str(result)))
@@ -960,7 +971,7 @@ if something goes wrong.
960971
if self.__debug :
961972
print( "[DEBUG] GetVariableType for %s / %s" % ( ups, var ) )
962973

963-
self.__srv_handler.send( ("GET TYPE %s %s\n" % ( ups, var )).encode('ascii') )
974+
self.__send( ("GET TYPE %s %s\n" % ( ups, var )).encode('ascii') )
964975
result = self.__read_until( b"\n" )
965976
if result[:4] == b"TYPE" :
966977
# TYPE <ups> <var> <type>
@@ -975,7 +986,7 @@ if something goes wrong.
975986
if self.__debug :
976987
print( "[DEBUG] GetVariableDescription for %s / %s" % ( ups, var ) )
977988

978-
self.__srv_handler.send( ("GET DESC %s %s\n" % ( ups, var )).encode('ascii') )
989+
self.__send( ("GET DESC %s %s\n" % ( ups, var )).encode('ascii') )
979990
result = self.__read_until( b"\n" )
980991
if result[:4] == b"DESC" :
981992
# DESC <ups> <var> "<description>"
@@ -990,7 +1001,7 @@ if something goes wrong.
9901001
if self.__debug :
9911002
print( "[DEBUG] GetEnumList for %s / %s" % ( ups, var ) )
9921003

993-
self.__srv_handler.send( ("LIST ENUM %s %s\n" % ( ups, var )).encode('ascii') )
1004+
self.__send( ("LIST ENUM %s %s\n" % ( ups, var )).encode('ascii') )
9941005
result = self.__read_until( b"\n" )
9951006
if result != ("BEGIN LIST ENUM %s %s\n" % ( ups, var )).encode('ascii') :
9961007
raise PyNUTError( result.replace( b"\n", b"" ).decode('ascii') )
@@ -1011,7 +1022,7 @@ if something goes wrong.
10111022
if self.__debug :
10121023
print( "[DEBUG] GetRangeList for %s / %s" % ( ups, var ) )
10131024

1014-
self.__srv_handler.send( ("LIST RANGE %s %s\n" % ( ups, var )).encode('ascii') )
1025+
self.__send( ("LIST RANGE %s %s\n" % ( ups, var )).encode('ascii') )
10151026
result = self.__read_until( b"\n" )
10161027
if result != ("BEGIN LIST RANGE %s %s\n" % ( ups, var )).encode('ascii') :
10171028
raise PyNUTError( result.replace( b"\n", b"" ).decode('ascii') )
@@ -1034,7 +1045,7 @@ if something goes wrong.
10341045
if self.__debug :
10351046
print( "[DEBUG] GetDeviceNumLogins for %s" % ups )
10361047

1037-
self.__srv_handler.send( ("GET NUMLOGINS %s\n" % ups).encode('ascii') )
1048+
self.__send( ("GET NUMLOGINS %s\n" % ups).encode('ascii') )
10381049
result = self.__read_until( b"\n" )
10391050
if result[:9] == b"NUMLOGINS" :
10401051
# NUMLOGINS <ups> <value>
@@ -1054,7 +1065,7 @@ which is of little concern for Python2 but is important in Python3
10541065
if self.__debug :
10551066
print( "[DEBUG] GetUPSList from server" )
10561067

1057-
self.__srv_handler.send( b"LIST UPS\n" )
1068+
self.__send( b"LIST UPS\n" )
10581069
result = self.__read_until( b"\n" )
10591070
if result != b"BEGIN LIST UPS\n":
10601071
raise PyNUTError( result.replace( b"\n", b"" ).decode('ascii') )
@@ -1094,7 +1105,7 @@ available vars.
10941105
if self.__debug :
10951106
print( "[DEBUG] GetUPSVars called..." )
10961107

1097-
self.__srv_handler.send( ("LIST VAR %s\n" % ups).encode('ascii') )
1108+
self.__send( ("LIST VAR %s\n" % ups).encode('ascii') )
10981109
result = self.__read_until( b"\n" )
10991110
if result != ("BEGIN LIST VAR %s\n" % ups).encode('ascii') :
11001111
raise PyNUTError( result.replace( b"\n", b"" ).decode('ascii') )
@@ -1120,7 +1131,7 @@ The result is True (reachable) or False (unreachable)
11201131
if self.__debug :
11211132
print( "[DEBUG] CheckUPSAvailable called..." )
11221133

1123-
self.__srv_handler.send( ("LIST CMD %s\n" % ups).encode('ascii') )
1134+
self.__send( ("LIST CMD %s\n" % ups).encode('ascii') )
11241135
result = self.__read_until( b"\n" )
11251136
if result != ("BEGIN LIST CMD %s\n" % ups).encode('ascii') :
11261137
return False
@@ -1137,7 +1148,7 @@ of the command as value
11371148
if self.__debug :
11381149
print( "[DEBUG] GetUPSCommands called..." )
11391150

1140-
self.__srv_handler.send( ("LIST CMD %s\n" % ups).encode('ascii') )
1151+
self.__send( ("LIST CMD %s\n" % ups).encode('ascii') )
11411152
result = self.__read_until( b"\n" )
11421153
if result != ("BEGIN LIST CMD %s\n" % ups).encode('ascii') :
11431154
raise PyNUTError( result.replace( b"\n", b"" ).decode('ascii') )
@@ -1152,7 +1163,7 @@ of the command as value
11521163

11531164
# For each var we try to get the available description
11541165
try :
1155-
self.__srv_handler.send( ("GET CMDDESC %s %s\n" % ( ups, var )).encode('ascii') )
1166+
self.__send( ("GET CMDDESC %s %s\n" % ( ups, var )).encode('ascii') )
11561167
temp = self.__read_until( b"\n" )
11571168
if temp[:7] != b"CMDDESC" :
11581169
raise PyNUTError
@@ -1208,7 +1219,7 @@ rights to set it (maybe login/password).
12081219
do_wait = True
12091220
self.EnableTrackingModeOnce()
12101221

1211-
self.__srv_handler.send( ("SET VAR %s %s %s\n" % ( ups, var, value )).encode('ascii') )
1222+
self.__send( ("SET VAR %s %s %s\n" % ( ups, var, value )).encode('ascii') )
12121223
result = self.__read_until( b"\n" )
12131224
if ( result == b"OK\n" ) :
12141225
return( "OK" )
@@ -1240,7 +1251,7 @@ Returns OK on success or raises an error
12401251
do_wait = True
12411252
self.EnableTrackingModeOnce()
12421253

1243-
self.__srv_handler.send( ("INSTCMD %s %s\n" % ( ups, command )).encode('ascii') )
1254+
self.__send( ("INSTCMD %s %s\n" % ( ups, command )).encode('ascii') )
12441255
result = self.__read_until( b"\n" )
12451256
if ( result == b"OK\n" ) :
12461257
return( "OK" )
@@ -1281,7 +1292,7 @@ of connection.
12811292
print( "[DEBUG] DeviceLogin: %s is not a valid UPS" % ups )
12821293
raise PyNUTError( "ERR UNKNOWN-UPS" )
12831294

1284-
self.__srv_handler.send( ("LOGIN %s\n" % ups).encode('ascii') )
1295+
self.__send( ("LOGIN %s\n" % ups).encode('ascii') )
12851296
result = self.__read_until( b"\n" )
12861297
if ( result.startswith( ("User %s@" % self.__login).encode('ascii')) and result.endswith (("[%s]\n" % ups).encode('ascii')) ):
12871298
# User dummy-user@127.0.0.1 logged into UPS [dummy]
@@ -1303,14 +1314,14 @@ NOTE: API changed since NUT 2.8.0 to replace MASTER with PRIMARY
13031314
if self.__debug :
13041315
print( "[DEBUG] PRIMARY called..." )
13051316

1306-
self.__srv_handler.send( ("PRIMARY %s\n" % ups).encode('ascii') )
1317+
self.__send( ("PRIMARY %s\n" % ups).encode('ascii') )
13071318
result = self.__read_until( b"\n" )
13081319
if ( result == b"OK PRIMARY-GRANTED\n" ) :
13091320
return( "OK" )
13101321

13111322
if self.__debug :
13121323
print( "[DEBUG] Retrying: MASTER called..." )
1313-
self.__srv_handler.send( ("MASTER %s\n" % ups).encode('ascii') )
1324+
self.__send( ("MASTER %s\n" % ups).encode('ascii') )
13141325
result = self.__read_until( b"\n" )
13151326
if ( result == b"OK MASTER-GRANTED\n" ) :
13161327
return( "OK" )
@@ -1331,7 +1342,7 @@ Returns OK on success or raises an error
13311342

13321343
if self.__debug :
13331344
print( "[DEBUG] FSD called..." )
1334-
self.__srv_handler.send( ("FSD %s\n" % ups).encode('ascii') )
1345+
self.__send( ("FSD %s\n" % ups).encode('ascii') )
13351346
result = self.__read_until( b"\n" )
13361347
if ( result == b"OK FSD-SET\n" ) :
13371348
return( "OK" )
@@ -1374,11 +1385,11 @@ The result is a dictionary containing 'key->val' pairs of 'UPSName' and a list o
13741385
raise PyNUTError( "ERR UNKNOWN-UPS" )
13751386

13761387
if ups:
1377-
self.__srv_handler.send( ("LIST CLIENT %s\n" % ups).encode('ascii') )
1388+
self.__send( ("LIST CLIENT %s\n" % ups).encode('ascii') )
13781389
else:
13791390
# NOTE: Currently NUT does not support just listing all clients
13801391
# (not providing an "ups" argument) => NUT_ERR_INVALID_ARGUMENT
1381-
self.__srv_handler.send( b"LIST CLIENT\n" )
1392+
self.__send( b"LIST CLIENT\n" )
13821393
result = self.__read_until( b"\n" )
13831394
if ( (ups and result != ("BEGIN LIST CLIENT %s\n" % ups).encode('ascii')) or (ups is None and result != b"BEGIN LIST CLIENT\n") ):
13841395
if ups is None and (result == b"ERR INVALID-ARGUMENT\n") :

0 commit comments

Comments
 (0)