@@ -255,6 +255,74 @@ async def run_cli_monitor(config: dict):
255255
256256def _run_app (config_path , port , nodes , once , web_mode = False , cli_mode = False ):
257257 """Helper to run main application logic."""
258+ # If the user requested admin mode via --admin in argv, and the process is not elevated,
259+ # attempt to relaunch elevated (UAC on Windows, sudo on POSIX). This check is done here
260+ # to cover both top-level and subcommand usages (e.g. `health_monitor.py web --admin`).
261+ try :
262+ import sys , platform , os
263+ def _is_elevated ():
264+ try :
265+ if platform .system () == 'Windows' :
266+ import ctypes
267+ return bool (ctypes .windll .shell32 .IsUserAnAdmin ())
268+ else :
269+ return (os .geteuid () == 0 )
270+ except Exception :
271+ return False
272+
273+ if '--admin' in (sys .argv [1 :] if len (sys .argv ) > 1 else []) and not _is_elevated ():
274+ # Attempt relaunch elevated. Use ShellExecuteW on Windows, fallback to PowerShell;
275+ # on POSIX try sudo exec.
276+ try :
277+ if platform .system () == 'Windows' :
278+ try :
279+ import ctypes
280+ params = '"' + os .path .abspath (sys .argv [0 ]) + '"'
281+ other_args = [a for a in sys .argv [1 :]]
282+ if other_args :
283+ params += ' ' + ' ' .join (str (a ) for a in other_args )
284+ ret = ctypes .windll .shell32 .ShellExecuteW (None , 'runas' , sys .executable , params , None , 1 )
285+ try :
286+ ok = int (ret ) > 32
287+ except Exception :
288+ ok = False
289+ if ok :
290+ print ('Relaunching elevated, exiting original process' )
291+ try : os ._exit (0 )
292+ except Exception : pass
293+ except Exception :
294+ pass
295+
296+ # PowerShell fallback
297+ try :
298+ import subprocess
299+ def _ps_quote (s ):
300+ return "'" + str (s ).replace ("'" , "''" ) + "'"
301+ ps_args = [os .path .abspath (sys .argv [0 ])] + list (sys .argv [1 :])
302+ arglist_literal = ',' .join (_ps_quote (a ) for a in ps_args )
303+ ps_cmd = [
304+ 'powershell' , '-NoProfile' , '-NonInteractive' , '-Command' ,
305+ f"Start-Process -FilePath '{ sys .executable } ' -ArgumentList { arglist_literal } -Verb RunAs"
306+ ]
307+ proc = subprocess .run (ps_cmd , capture_output = True , text = True , timeout = 15 )
308+ if proc .returncode == 0 :
309+ try : os ._exit (0 )
310+ except Exception : pass
311+ except Exception :
312+ pass
313+
314+ else :
315+ # POSIX: try exec via sudo
316+ try :
317+ print ('Attempting to relaunch with sudo...' )
318+ os .execvp ('sudo' , ['sudo' , sys .executable , os .path .abspath (sys .argv [0 ])] + list (sys .argv [1 :]))
319+ except Exception :
320+ pass
321+ except Exception :
322+ pass
323+ except Exception :
324+ pass
325+
258326 console .print (BANNER , style = "bold cyan" )
259327
260328 # Load configuration
@@ -299,9 +367,91 @@ async def main():
299367@click .option ('--config' , '-c' , type = click .Path (), help = 'Configuration file path.' )
300368@click .option ('--port' , '-p' , type = int , help = 'Web server port (default: 8090).' )
301369@click .option ('--update' , is_flag = True , help = 'Check for and install updates.' )
370+ @click .option ('--admin' , is_flag = True , help = 'Start in administrative mode (enables privileged dashboard actions).' )
302371@click .pass_context
303- def cli (ctx , config , port , update ):
372+ def cli (ctx , config , port , update , admin ):
304373 """Cluster Health Monitor: Real-time GPU and system health monitoring."""
374+ # If the user requested admin mode, attempt to relaunch this process elevated
375+ # on platforms that support elevation (Windows -> UAC, POSIX -> sudo).
376+ def _is_elevated ():
377+ try :
378+ import platform
379+ if platform .system () == 'Windows' :
380+ import ctypes
381+ return bool (ctypes .windll .shell32 .IsUserAnAdmin ())
382+ else :
383+ import os
384+ return (os .geteuid () == 0 )
385+ except Exception :
386+ return False
387+
388+ def _relaunch_elevated ():
389+ try :
390+ import platform , sys , os , subprocess , shlex
391+ script = os .path .abspath (sys .argv [0 ])
392+ args = sys .argv [1 :]
393+ # Ensure --admin present
394+ if '--admin' not in args :
395+ args = args + ['--admin' ]
396+
397+ if platform .system () == 'Windows' :
398+ try :
399+ import ctypes
400+ params = '"' + script + '"'
401+ if args :
402+ params += ' ' + ' ' .join (str (a ) for a in args )
403+ ret = ctypes .windll .shell32 .ShellExecuteW (None , 'runas' , sys .executable , params , None , 1 )
404+ try :
405+ ok = int (ret ) > 32
406+ except Exception :
407+ ok = False
408+ if ok :
409+ # launched elevated; exit current process
410+ print ('Relaunching elevated, exiting original process' )
411+ try : os ._exit (0 )
412+ except SystemExit : raise
413+ except Exception : pass
414+ else :
415+ print ('ShellExecuteW failed to elevate (ret=' + str (ret ) + ')' )
416+ except Exception as e :
417+ print ('Windows elevation exception:' , e )
418+
419+ # PowerShell fallback
420+ try :
421+ def _ps_quote (s ):
422+ return "'" + str (s ).replace ("'" , "''" ) + "'"
423+ ps_args = [script ] + list (args )
424+ arglist_literal = ',' .join (_ps_quote (a ) for a in ps_args )
425+ ps_cmd = [
426+ 'powershell' , '-NoProfile' , '-NonInteractive' , '-Command' ,
427+ f"Start-Process -FilePath '{ sys .executable } ' -ArgumentList { arglist_literal } -Verb RunAs"
428+ ]
429+ proc = subprocess .run (ps_cmd , capture_output = True , text = True , timeout = 15 )
430+ if proc .returncode == 0 :
431+ try : os ._exit (0 )
432+ except Exception : pass
433+ else :
434+ print ('PowerShell elevation failed:' , proc .returncode , proc .stderr )
435+ except Exception as e :
436+ print ('PowerShell fallback exception:' , e )
437+
438+ else :
439+ # POSIX: try exec via sudo
440+ try :
441+ print ('Attempting to relaunch with sudo...' )
442+ os .execvp ('sudo' , ['sudo' , sys .executable , script ] + list (args ))
443+ except Exception as e :
444+ print ('sudo relaunch failed:' , e )
445+
446+ except Exception as e :
447+ print ('Relaunch elevation error:' , e )
448+
449+ # If admin requested and not already elevated, attempt to relaunch elevated
450+ try :
451+ if admin and not _is_elevated ():
452+ _relaunch_elevated ()
453+ except Exception :
454+ pass
305455 if update :
306456 from monitor .utils import check_for_updates , perform_update
307457 console .print ("\n [cyan]Checking for updates...[/cyan]" )
@@ -328,15 +478,30 @@ def cli(ctx, config, port, update):
328478 console .print ("[red]Update failed. Try again later.[/red]" )
329479 return
330480
331- ctx .obj = {'config_path' : config }
481+ ctx .obj = {'config_path' : config , 'admin' : admin }
332482 if ctx .invoked_subcommand is None :
483+ # If admin flag set, append to sys.argv so server.detect features and app.state see it
484+ if admin and '--admin' not in sys .argv :
485+ sys .argv .append ('--admin' )
333486 _run_app (config , port = port , nodes = None , once = False , web_mode = True )
334487
335488@cli .command ()
336489@click .option ('--port' , '-p' , type = int , help = 'Web server port (overrides config).' )
490+ @click .option ('--admin' , is_flag = True , help = 'Start web server in administrative mode (enables privileged actions).' )
337491@click .pass_context
338- def web (ctx , port ):
492+ def web (ctx , port , admin ):
339493 """Launch the web dashboard."""
494+ # If called as a subcommand with --admin, ensure argv contains --admin so server detection sees it
495+ import sys
496+ if admin and '--admin' not in sys .argv :
497+ sys .argv .append ('--admin' )
498+ # Also propagate admin from top-level invocation if present in ctx.obj
499+ try :
500+ if not admin and ctx and isinstance (ctx .obj , dict ) and ctx .obj .get ('admin' ):
501+ if '--admin' not in sys .argv :
502+ sys .argv .append ('--admin' )
503+ except Exception :
504+ pass
340505 _run_app (ctx .obj ['config_path' ], port , nodes = None , once = False , web_mode = True )
341506
342507@cli .command (name = "cli" )
0 commit comments