1313import tempfile
1414from urllib .parse import urlparse
1515
16+ from rich .console import Console
17+
1618from badfish .helpers import get_now
1719from badfish .helpers .parser import parse_arguments
1820from badfish .helpers .logger import BadfishLogger
1921from badfish .helpers .http_client import HTTPClient
2022from badfish .helpers .exceptions import BadfishException
23+ from badfish .helpers .progress import polling_progress
2124
2225from logging import (
2326 DEBUG ,
3033RETRIES = 15
3134
3235
33- async def badfish_factory (_host , _username , _password , _logger = None , _retries = RETRIES , _loop = None , _insecure = False ):
36+ async def badfish_factory (
37+ _host ,
38+ _username ,
39+ _password ,
40+ _logger = None ,
41+ _retries = RETRIES ,
42+ _loop = None ,
43+ _insecure = False ,
44+ _console = None ,
45+ _progress_disabled = False ,
46+ ):
3447 if not _logger :
3548 bfl = BadfishLogger ()
3649 _logger = bfl .logger
3750
38- badfish = Badfish (_host , _username , _password , _logger , _retries , _loop , _insecure )
51+ badfish = Badfish (
52+ _host ,
53+ _username ,
54+ _password ,
55+ _logger ,
56+ _retries ,
57+ _loop ,
58+ _insecure ,
59+ _console ,
60+ _progress_disabled ,
61+ )
3962 await badfish .init ()
4063 return badfish
4164
4265
4366class Badfish :
44- def __init__ (self , _host , _username , _password , _logger , _retries , _loop = None , _insecure = False ):
67+ def __init__ (
68+ self ,
69+ _host ,
70+ _username ,
71+ _password ,
72+ _logger ,
73+ _retries ,
74+ _loop = None ,
75+ _insecure = False ,
76+ _console = None ,
77+ _progress_disabled = False ,
78+ ):
4579 self .host = _host
4680 self .username = _username
4781 self .password = _password
@@ -63,6 +97,8 @@ def __init__(self, _host, _username, _password, _logger, _retries, _loop=None, _
6397 self .session_id = None
6498 self .token = None
6599 self .vendor = None
100+ self .console = _console if _console is not None else Console ()
101+ self ._progress_disabled = _progress_disabled
66102
67103 async def __aenter__ (self ):
68104 await self .init ()
@@ -86,19 +122,6 @@ async def init(self):
86122 self .bios_uri = None
87123 self .manager_resource = await self .find_managers_resource ()
88124
89- @staticmethod
90- def progress_bar (value , end_value , state , prompt = "Host state" , bar_length = 20 ):
91- ratio = float (value ) / end_value
92- arrow = "-" * int (round (ratio * bar_length ) - 1 ) + ">"
93- spaces = " " * (bar_length - len (arrow ))
94- percent = int (round (ratio * 100 ))
95-
96- if state .lower () == "on" :
97- state = "On "
98- ret = "\r " if percent != 100 else "\n "
99- sys .stdout .write (f"\r - POLLING: [{ arrow + spaces } ] { percent } % - { prompt } : { state } { ret } " )
100- sys .stdout .flush ()
101-
102125 async def error_handler (self , _response , message = None ):
103126 try :
104127 raw = await _response .text ("utf-8" , "ignore" )
@@ -844,35 +867,38 @@ async def check_schedule_job_status(self, job_id):
844867 return False
845868
846869 async def check_job_status (self , job_id ):
847- for count in range (self .retries ):
848- _url = f"{ self .host_uri } { self .manager_resource } /Jobs/{ job_id } "
849- self .http_client .get_request .cache_clear ()
850- _response = await self .get_request (_url )
870+ with polling_progress (
871+ self .console , self .retries , "Status" , disable = self ._progress_disabled
872+ ) as (progress , task_id ):
873+ for count in range (self .retries ):
874+ _url = f"{ self .host_uri } { self .manager_resource } /Jobs/{ job_id } "
875+ self .http_client .get_request .cache_clear ()
876+ _response = await self .get_request (_url )
851877
852- status_code = _response .status
853- raw = await _response .text ("utf-8" , "ignore" )
854- data = json .loads (raw .strip ())
855- if status_code != 200 :
856- self .logger .error (f"Command failed to check job status, return code is { status_code } " )
857- self .logger .debug (f"Extended Info Message: { data } " )
858- return False
878+ status_code = _response .status
879+ raw = await _response .text ("utf-8" , "ignore" )
880+ data = json .loads (raw .strip ())
881+ if status_code != 200 :
882+ self .logger .error (f"Command failed to check job status, return code is { status_code } " )
883+ self .logger .debug (f"Extended Info Message: { data } " )
884+ return False
859885
860- if "Message" not in data :
861- self .logger .warning ("Job status response missing Message field" )
862- return False
886+ if "Message" not in data :
887+ self .logger .warning ("Job status response missing Message field" )
888+ return False
863889
864- if "Fail" in data ["Message" ] or "fail" in data ["Message" ]:
865- self .logger .debug (f"\n { job_id } job failed." )
866- return False
867- elif data ["Message" ] == "Job completed successfully." :
868- self .logger .info (f"JobID: { data [u'Id' ]} " )
869- self .logger .info (f"Name: { data [u'Name' ]} " )
870- self .logger .info (f"Message: { data [u'Message' ]} " )
871- self .logger .info (f"PercentComplete: { str (data [u'PercentComplete' ])} " )
872- break
873- else :
874- self . progress_bar ( count , self . retries , data ["Message" ], prompt = "Status" )
875- await asyncio .sleep (30 )
890+ if "Fail" in data ["Message" ] or "fail" in data ["Message" ]:
891+ self .logger .debug (f"\n { job_id } job failed." )
892+ return False
893+ elif data ["Message" ] == "Job completed successfully." :
894+ self .logger .info (f"JobID: { data [u'Id' ]} " )
895+ self .logger .info (f"Name: { data [u'Name' ]} " )
896+ self .logger .info (f"Message: { data [u'Message' ]} " )
897+ self .logger .info (f"PercentComplete: { str (data [u'PercentComplete' ])} " )
898+ break
899+ else :
900+ progress . update ( task_id , completed = count + 1 , state = data ["Message" ])
901+ await asyncio .sleep (30 )
876902
877903 def _extract_job_id_from_response (self , response , warn_on_missing = True , context = "" ):
878904 """
@@ -1293,32 +1319,38 @@ async def polling_host_state(self, state, equals=True):
12931319 state_str = "Not %s" % state if not equals else state
12941320 self .logger .info ("Polling for host state: %s" % state_str )
12951321 desired_state = False
1296- for count in range (self .retries ):
1297- current_state = await self .get_power_state ()
1298- if equals :
1299- desired_state = current_state .lower () == state .lower ()
1300- else :
1301- desired_state = current_state .lower () != state .lower ()
1302- await asyncio .sleep (5 )
1303- if desired_state :
1304- self .progress_bar (self .retries , self .retries , current_state )
1305- break
1306- self .progress_bar (count , self .retries , current_state )
1322+ with polling_progress (
1323+ self .console , self .retries , "Host state" , disable = self ._progress_disabled
1324+ ) as (progress , task_id ):
1325+ for count in range (self .retries ):
1326+ current_state = await self .get_power_state ()
1327+ if equals :
1328+ desired_state = current_state .lower () == state .lower ()
1329+ else :
1330+ desired_state = current_state .lower () != state .lower ()
1331+ await asyncio .sleep (5 )
1332+ if desired_state :
1333+ progress .update (task_id , completed = self .retries , state = current_state )
1334+ break
1335+ progress .update (task_id , completed = count + 1 , state = current_state )
13071336
13081337 return desired_state
13091338
13101339 async def poll_until_ready (self , check_func , description , sleep_interval = 5 , clear_cache = False ):
13111340 self .logger .info ("Polling for %s" % description )
1312- for count in range (self .retries ):
1313- if clear_cache :
1314- self .http_client .get_request .cache_clear ()
1315- ready = await check_func ()
1316- if ready :
1317- self .progress_bar (self .retries , self .retries , "Ready" )
1318- self .logger .info ("%s is ready." % description )
1319- return True
1320- self .progress_bar (count , self .retries , "Not Ready" )
1321- await asyncio .sleep (sleep_interval )
1341+ with polling_progress (
1342+ self .console , self .retries , "Host state" , disable = self ._progress_disabled
1343+ ) as (progress , task_id ):
1344+ for count in range (self .retries ):
1345+ if clear_cache :
1346+ self .http_client .get_request .cache_clear ()
1347+ ready = await check_func ()
1348+ if ready :
1349+ progress .update (task_id , completed = self .retries , state = "Ready" )
1350+ self .logger .info ("%s is ready." % description )
1351+ return True
1352+ progress .update (task_id , completed = count + 1 , state = "Not Ready" )
1353+ await asyncio .sleep (sleep_interval )
13221354 self .logger .warning ("%s did not become ready after %d retry attempts." % (description , self .retries ))
13231355 return False
13241356
@@ -2710,7 +2742,7 @@ async def set_nic_attribute(self, fqdd, attribute, value):
27102742 return True
27112743
27122744
2713- async def execute_badfish (_host , _args , logger , format_handler = None ):
2745+ async def execute_badfish (_host , _args , logger , format_handler = None , console = None , progress_disabled = False ):
27142746 _username = _args .get ("u" ) or os .environ .get ("BADFISH_USERNAME" )
27152747 _password = _args .get ("p" ) or os .environ .get ("BADFISH_PASSWORD" )
27162748
@@ -2793,6 +2825,8 @@ async def execute_badfish(_host, _args, logger, format_handler=None):
27932825 _logger = logger ,
27942826 _retries = retries ,
27952827 _insecure = insecure ,
2828+ _console = console ,
2829+ _progress_disabled = progress_disabled ,
27962830 )
27972831
27982832 if _args ["host_list" ] and not _args ["output" ]:
@@ -2949,6 +2983,9 @@ def main(argv=None):
29492983 output = _args ["output" ]
29502984 bfl = BadfishLogger (_args ["verbose" ], multi_host , _args ["log" ], output )
29512985
2986+ console = Console ()
2987+ progress_disabled = bool (output ) or multi_host or bool (_args ["log" ]) or not console .is_terminal
2988+
29522989 try :
29532990 loop = asyncio .get_event_loop ()
29542991 except RuntimeError :
@@ -2975,6 +3012,8 @@ def main(argv=None):
29753012 _args ,
29763013 logger ,
29773014 bfl .queue_listener .handlers [0 ] if output else None ,
3015+ console = console ,
3016+ progress_disabled = progress_disabled ,
29783017 )
29793018 tasks .append (fn )
29803019 except IOError as ex :
@@ -3004,7 +3043,14 @@ def main(argv=None):
30043043 else :
30053044 try :
30063045 _host , result = loop .run_until_complete (
3007- execute_badfish (host , _args , bfl .logger , bfl .queue_listener .handlers [0 ])
3046+ execute_badfish (
3047+ host ,
3048+ _args ,
3049+ bfl .logger ,
3050+ bfl .queue_listener .handlers [0 ],
3051+ console = console ,
3052+ progress_disabled = progress_disabled ,
3053+ )
30083054 )
30093055 except KeyboardInterrupt :
30103056 bfl .logger .warning ("Badfish terminated" )
0 commit comments