Coverage for /Users/ajo/work/jumpstarter/jumpstarter/packages/jumpstarter-driver-power/jumpstarter_driver_power/client.py: 35%

46 statements  

« prev     ^ index     » next       coverage.py v7.8.0, created at 2025-05-06 10:21 +0200

1import time 

2from collections.abc import Generator 

3 

4import asyncclick as click 

5 

6from .common import PowerReading 

7from jumpstarter.client import DriverClient 

8 

9 

10class PowerClient(DriverClient): 

11 def on(self) -> None: 

12 self.call("on") 

13 

14 def off(self) -> None: 

15 self.call("off") 

16 

17 def cycle(self, wait: int = 2): 

18 """Power cycle the device""" 

19 self.logger.info("Starting power cycle sequence") 

20 self.off() 

21 self.logger.info(f"Waiting {wait} seconds...") 

22 time.sleep(wait) 

23 self.on() 

24 self.logger.info("Power cycle sequence complete") 

25 

26 def read(self) -> Generator[PowerReading, None, None]: 

27 for v in self.streamingcall("read"): 

28 yield PowerReading.model_validate(v, strict=True) 

29 

30 def cli(self): 

31 @click.group 

32 def base(): 

33 """Generic power""" 

34 pass 

35 

36 @base.command() 

37 def on(): 

38 """Power on""" 

39 self.on() 

40 

41 @base.command() 

42 def off(): 

43 """Power off""" 

44 self.off() 

45 

46 @base.command() 

47 @click.option("--wait", "-w", default=2, help="Wait time in seconds between off and on") 

48 def cycle(wait): 

49 """Power cycle""" 

50 click.echo(f"Power cycling with {wait} seconds wait time...") 

51 self.cycle(wait) 

52 

53 return base 

54 

55 

56class VirtualPowerClient(PowerClient): 

57 def off(self, destroy: bool = False) -> None: 

58 self.call('off', destroy) 

59 

60 def cli(self): 

61 parent = super().cli() 

62 

63 @parent.command(name='off') 

64 @click.option('--destroy', is_flag=True, help='destroy the instance after powering it off') 

65 def off(destroy: bool): 

66 """Power off""" 

67 self.off(destroy) 

68 

69 return parent