@@ -693,7 +693,9 @@ async def _init_ssh(self, init_dev_data=True, use_lock=True) -> None:
693693 self .ssh_ready .release ()
694694
695695 # Release here because init_dev_data uses this lock as well
696- if init_dev_data :
696+ # We need to be sure that devtype is set, otherwise the
697+ # _fetch_dev_data function is not implemented and will raise.
698+ if init_dev_data and self .devtype :
697699 await self ._fetch_init_dev_data ()
698700
699701 @abstractmethod
@@ -1904,13 +1906,11 @@ async def _fetch_init_dev_data(self):
19041906 password = self .password , known_hosts = None ) as conn :
19051907 async with conn .create_process () as process :
19061908 process .stdin .write ("show system info\n " )
1907- recv_chars = False
19081909 output = ""
1909- if not recv_chars :
1910- output += await process .stdout .read (1 )
1910+ output += await process .stdout .read (1 )
19111911 try :
19121912 await asyncio .wait_for (
1913- process .wait_closed (), timeout = 0.01 )
1913+ process .wait_closed (), timeout = 0.1 )
19141914 except asyncio .TimeoutError :
19151915 pass
19161916
@@ -1927,22 +1927,38 @@ async def _fetch_init_dev_data(self):
19271927 )
19281928 if self .api_key is None :
19291929 await self .get_api_key ()
1930+ except asyncssh .misc .PermissionDenied :
1931+ self .logger .error (
1932+ f'Permission denied for { self .address } :{ self .port } ' )
1933+ self ._retry -= 1
19301934 except Exception :
1931- pass
1935+ self .logger .warning (
1936+ f'Cannot parse device data from { self .address } :{ self .port } ' )
19321937
19331938 async def get_api_key (self ):
19341939 """Authenticate to get the api key needed in all cmd requests"""
19351940 url = f"https://{ self .address } :{ self .port } /api/?type=keygen&user=" \
19361941 f"{ self .username } &password={ self .password } "
19371942
19381943 async with self .cmd_pacer (self .per_cmd_auth ):
1944+ if not self ._retry :
1945+ return
19391946 async with self ._session .get (url , timeout = self .connect_timeout ) \
19401947 as response :
19411948 status , xml = response .status , await response .text ()
19421949 if status == 200 :
19431950 data = xmltodict .parse (xml )
19441951 self .api_key = data ["response" ]["result" ]["key" ]
1945- # need to manage errors
1952+ # reset retry count, just in case.
1953+ self ._retry = self ._max_retries_on_auth_fail
1954+ elif status == 403 :
1955+ self .logger .error ('Invalid credentials, could not get api '
1956+ f'key for { self .address } :{ self .port } .' )
1957+ self ._retry -= 1
1958+ else :
1959+ self .logger .error ('Unknown error, could not get '
1960+ 'api key for '
1961+ f'{ self .address } :{ self .port } .' )
19461962
19471963 async def _parse_init_dev_data (self , output , cb_token ) -> None :
19481964 """Parse the uptime command output"""
@@ -1995,6 +2011,12 @@ async def _init_rest(self):
19952011 )
19962012 if self .api_key is None :
19972013 await self .get_api_key ()
2014+ # If the api_key is still None we can't gather any data.
2015+ # Ensure that the connection pool is closed and set it to
2016+ # None so that _rest_gather can fail gracefully.
2017+ if self .api_key is None :
2018+ self ._session .close ()
2019+ self ._session = None
19982020 except Exception as e :
19992021 self .logger .error (
20002022 f'{ self .transport } ://{ self .hostname } :{ self .port } , '
@@ -2011,12 +2033,15 @@ async def _rest_gather(self, service_callback, cmd_list, cb_token,
20112033
20122034 now = int (datetime .now (tz = timezone .utc ).timestamp () * 1000 )
20132035
2014- port = self .port or 443
2015-
2016- url = f"https://{ self .address } :{ port } /api/"
2036+ url = f"https://{ self .address } :{ self .port } /api/"
20172037
20182038 status = 200 # status OK
20192039
2040+ # if there's no session we have failed to get init dev data
2041+ if not self ._session and self ._retry :
2042+ self ._fetch_init_dev_data ()
2043+
2044+ # if there's still no session, we need to create an error
20202045 if not self ._session :
20212046 for cmd in cmd_list :
20222047 result .append (self ._create_error (cmd ))
@@ -2030,19 +2055,26 @@ async def _rest_gather(self, service_callback, cmd_list, cb_token,
20302055 async with self ._session .get (
20312056 url_cmd , timeout = timeout ) as response :
20322057 status , xml = response .status , await response .text ()
2033- json_out = json .dumps (
2034- xmltodict .parse (xml ))
2035-
2036- result .append ({
2037- "status" : status ,
2038- "timestamp" : now ,
2039- "cmd" : cmd ,
2040- "devtype" : self .devtype ,
2041- "namespace" : self .nsname ,
2042- "hostname" : self .hostname ,
2043- "address" : self .address ,
2044- "data" : json_out ,
2045- })
2058+ if status == 200 :
2059+ json_out = json .dumps (
2060+ xmltodict .parse (xml ))
2061+ self .logger .info (f"{ cmd } { status } " )
2062+ result .append ({
2063+ "status" : status ,
2064+ "timestamp" : now ,
2065+ "cmd" : cmd ,
2066+ "devtype" : self .devtype ,
2067+ "namespace" : self .nsname ,
2068+ "hostname" : self .hostname ,
2069+ "address" : self .address ,
2070+ "data" : json_out ,
2071+ })
2072+ else :
2073+ result .append (self ._create_error (cmd ))
2074+ self .logger .error (
2075+ f'{ self .transport } ://{ self .hostname } :'
2076+ f'{ self .port } : Command { cmd } failed with '
2077+ f'status { response .status } ' )
20462078 except Exception as e :
20472079 self .current_exception = e
20482080 for cmd in cmd_list :
0 commit comments