request-vm-on-golem 0.1.53__py3-none-any.whl → 0.1.54__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: request-vm-on-golem
3
- Version: 0.1.53
3
+ Version: 0.1.54
4
4
  Summary: VM on Golem Requestor CLI - Create and manage virtual machines on the Golem Network
5
5
  Keywords: golem,vm,cloud,decentralized,cli
6
6
  Author: Phillip Jensen
@@ -1,8 +1,8 @@
1
1
  requestor/__init__.py,sha256=OqSUAh1uZBMx7GW0MoSMg967PVdmT8XdPJx3QYjwkak,116
2
2
  requestor/api/main.py,sha256=CTnaM7KyBtDwVlyclYbNDy-nGi5_xt9GTcGusRasDVY,2493
3
3
  requestor/cli/__init__.py,sha256=e3E4oEGxmGj-STPtFkQwg_qIWhR0JAiAQdw3G1hXciU,37
4
- requestor/cli/commands.py,sha256=5Nul0oxG_6n-EBqzQX3tO2N10uQpryyrmU9-HxFPovs,49539
5
- requestor/config.py,sha256=GPsr_NSj04MD40mH6xyVY5FB0ysFDwJk9FJ5h9OQuJ0,12716
4
+ requestor/cli/commands.py,sha256=fKZFsW4d60VYF5wxZnMxZLc0Tqod087P_NjfCQyDfRI,50998
5
+ requestor/config.py,sha256=FMSRKdyo3nEdn62CRonnwrw4Hsy4VGcuvvfg60aORsI,12809
6
6
  requestor/data/deployments/l2.json,sha256=XTNN2C5LkBfp4YbDKdUKfWMdp1fKnfv8D3TgcwVWxtQ,249
7
7
  requestor/db/__init__.py,sha256=Gm5DfWls6uvCZZ3HGGnyRHswbUQdeA5OGN8yPwH0hc8,88
8
8
  requestor/db/sqlite.py,sha256=l5pWbx2qlHuar1N_a0B9tVnmumLJY1w5rp3yZ7jmsC0,4146
@@ -11,7 +11,7 @@ requestor/payments/blockchain_service.py,sha256=CACvZH2ZstutX7f0L_PXl8K_V5WlIkxN
11
11
  requestor/payments/monitor.py,sha256=JtSnh2plFf-f8sJU-bkOpadhoK_R82_ULwkDRmBYSbc,6012
12
12
  requestor/provider/__init__.py,sha256=fmW23aYUVciF8-gmBZkG-PLhn22upmcDzdPfAOLHG6g,103
13
13
  requestor/provider/client.py,sha256=pfJymufYR13W4kfykHZSVvs6ikRUE5AdHp0W0DB17AE,4130
14
- requestor/run.py,sha256=GqOG6n34szt8Sp3SEqjRV6huWm737yCN6YnBqoiwI-U,1785
14
+ requestor/run.py,sha256=sR9GgylQWbYPc60wRr3rUpemlNrWqIPNFIJ8WCz6YwE,2120
15
15
  requestor/security/faucet.py,sha256=XF_13b66SKAaY0-40hNRcSgC8AZA4mD5gyXl3qaBLpQ,2320
16
16
  requestor/services/__init__.py,sha256=1qSn_6RMn0KB0A7LCnY2IW6_tC3HBQsdfkFeV-h94eM,172
17
17
  requestor/services/database_service.py,sha256=GlSrzzzd7PSYQJNup00sxkB-B2PMr1__04K8k5QSWvs,2996
@@ -20,9 +20,9 @@ requestor/services/ssh_service.py,sha256=tcOCtk2SlB9Uuv-P2ghR22e7BJ9kigQh5b4zSGd
20
20
  requestor/services/vm_service.py,sha256=1EUypRbCykdQTVJf4gYiNzkZNk66T3df32Vc51HkSMI,7983
21
21
  requestor/ssh/__init__.py,sha256=hNgSqJ5s1_AwwxVRyFjUqh_LTBpI4Hmzq0F-f_wXN9g,119
22
22
  requestor/ssh/manager.py,sha256=3jQtbbK7CVC2yD1zCO88jGXh2fBcuv3CzWEqDLuaQVk,9758
23
- requestor/utils/logging.py,sha256=oFNpO8pJboYM8Wp7g3HOU4HFyBTKypVdY15lUiz1a4I,3721
24
- requestor/utils/spinner.py,sha256=PUHJdTD9jpUHur__01_qxXy87WFfNmjQbD_sLG-KlGo,2459
25
- request_vm_on_golem-0.1.53.dist-info/METADATA,sha256=4JOUW7vkkFVjBgNv1zKVLz54hY0xWI2yVJFPc8LSI3E,15780
26
- request_vm_on_golem-0.1.53.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
27
- request_vm_on_golem-0.1.53.dist-info/entry_points.txt,sha256=Z-skRNpJ8aZcIl_En9mEm1ygkp9FKy0bzQoL3zO52-0,44
28
- request_vm_on_golem-0.1.53.dist-info/RECORD,,
23
+ requestor/utils/logging.py,sha256=lgAswzYvO9M0EOET0cFZvuAsGI4lInh_wln_6bI-fJk,4281
24
+ requestor/utils/spinner.py,sha256=X0jfPfs5ricglTS4_XmacrM2Z1DDHR7zGk2KqYZDpXg,2541
25
+ request_vm_on_golem-0.1.54.dist-info/METADATA,sha256=STyVVfE84_1K_a-HlKflEM-hZHQJhYo-vQm7vcwtbRQ,15780
26
+ request_vm_on_golem-0.1.54.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
27
+ request_vm_on_golem-0.1.54.dist-info/entry_points.txt,sha256=Z-skRNpJ8aZcIl_En9mEm1ygkp9FKy0bzQoL3zO52-0,44
28
+ request_vm_on_golem-0.1.54.dist-info/RECORD,,
requestor/cli/commands.py CHANGED
@@ -138,6 +138,8 @@ def vm():
138
138
  async def list_providers(cpu: Optional[int], memory: Optional[int], storage: Optional[int], country: Optional[str], driver: Optional[str], payments_network: Optional[str] = None, all_payments: bool = False, as_json: bool = False, network: Optional[str] = None):
139
139
  """List available providers matching requirements."""
140
140
  try:
141
+ if as_json:
142
+ os.environ["GOLEM_SILENCE_LOGS"] = "1"
141
143
  if network:
142
144
  config.network = network
143
145
  # Log search criteria if any
@@ -181,7 +183,10 @@ async def list_providers(cpu: Optional[int], memory: Optional[int], storage: Opt
181
183
 
182
184
  if not providers:
183
185
  logger.warning("No providers found matching criteria")
184
- return {"providers": []}
186
+ result = {"providers": []}
187
+ if as_json:
188
+ click.echo(json.dumps(result, indent=2))
189
+ return result
185
190
 
186
191
  # If JSON requested and full spec provided, include estimates per provider
187
192
  if as_json and cpu and memory and storage:
@@ -216,6 +221,12 @@ async def list_providers(cpu: Optional[int], memory: Optional[int], storage: Opt
216
221
  except Exception as e:
217
222
  logger.error(f"Failed to list providers: {str(e)}")
218
223
  raise click.Abort()
224
+ finally:
225
+ if as_json:
226
+ try:
227
+ del os.environ["GOLEM_SILENCE_LOGS"]
228
+ except Exception:
229
+ pass
219
230
 
220
231
 
221
232
  @vm.command(name='create')
@@ -385,6 +396,8 @@ def vm_stream():
385
396
  async def stream_list(as_json: bool):
386
397
  """List payment stream status for all known VMs."""
387
398
  try:
399
+ if as_json:
400
+ os.environ["GOLEM_SILENCE_LOGS"] = "1"
388
401
  vms = await db_service.list_vms()
389
402
  if not vms:
390
403
  logger.warning("No VMs found in local database")
@@ -461,6 +474,12 @@ async def stream_list(as_json: bool):
461
474
  except Exception as e:
462
475
  logger.error(f"Failed to list streams: {e}")
463
476
  raise click.Abort()
477
+ finally:
478
+ if as_json:
479
+ try:
480
+ del os.environ["GOLEM_SILENCE_LOGS"]
481
+ except Exception:
482
+ pass
464
483
 
465
484
 
466
485
  @vm_stream.command('open')
@@ -550,6 +569,8 @@ async def stream_topup(stream_id: int, glm: float | None, hours: int | None):
550
569
  async def stream_status(name: str, as_json: bool):
551
570
  """Show the payment stream status for a VM by name."""
552
571
  try:
572
+ if as_json:
573
+ os.environ["GOLEM_SILENCE_LOGS"] = "1"
553
574
  # Resolve VM and provider
554
575
  vm = await db_service.get_vm(name)
555
576
  if not vm:
@@ -580,6 +601,12 @@ async def stream_status(name: str, as_json: bool):
580
601
  except Exception as e:
581
602
  logger.error(f"Failed to fetch stream status: {e}")
582
603
  raise click.Abort()
604
+ finally:
605
+ if as_json:
606
+ try:
607
+ del os.environ["GOLEM_SILENCE_LOGS"]
608
+ except Exception:
609
+ pass
583
610
 
584
611
 
585
612
  @vm_stream.command('inspect')
@@ -589,6 +616,8 @@ async def stream_status(name: str, as_json: bool):
589
616
  async def stream_inspect(stream_id: int, as_json: bool):
590
617
  """Inspect a stream directly on-chain (no provider required)."""
591
618
  try:
619
+ if as_json:
620
+ os.environ["GOLEM_SILENCE_LOGS"] = "1"
592
621
  from web3 import Web3
593
622
  from golem_streaming_abi import STREAM_PAYMENT_ABI
594
623
  w3 = Web3(Web3.HTTPProvider(config.polygon_rpc_url))
@@ -632,6 +661,12 @@ async def stream_inspect(stream_id: int, as_json: bool):
632
661
  except Exception as e:
633
662
  logger.error(f"Failed to inspect stream: {e}")
634
663
  raise click.Abort()
664
+ finally:
665
+ if as_json:
666
+ try:
667
+ del os.environ["GOLEM_SILENCE_LOGS"]
668
+ except Exception:
669
+ pass
635
670
 
636
671
 
637
672
  @cli.group()
@@ -726,6 +761,8 @@ def connect_vm(name: str):
726
761
  async def info_vm(name: str, as_json: bool):
727
762
  """Show information about a VM."""
728
763
  try:
764
+ if as_json:
765
+ os.environ["GOLEM_SILENCE_LOGS"] = "1"
729
766
  logger.command(f"ℹ️ Getting info for VM '{name}'")
730
767
 
731
768
  # Initialize VM service
@@ -767,6 +804,12 @@ async def info_vm(name: str, as_json: bool):
767
804
  except Exception as e:
768
805
  logger.error(f"Failed to get VM info: {str(e)}")
769
806
  raise click.Abort()
807
+ finally:
808
+ if as_json:
809
+ try:
810
+ del os.environ["GOLEM_SILENCE_LOGS"]
811
+ except Exception:
812
+ pass
770
813
 
771
814
 
772
815
  @vm.command(name='destroy')
@@ -1054,6 +1097,8 @@ def run_api_server(host: str, port: int, reload: bool):
1054
1097
  async def list_vms(as_json: bool):
1055
1098
  """List all VMs."""
1056
1099
  try:
1100
+ if as_json:
1101
+ os.environ["GOLEM_SILENCE_LOGS"] = "1"
1057
1102
  logger.command("📋 Listing your VMs")
1058
1103
  logger.process("Fetching VM details")
1059
1104
 
@@ -1086,7 +1131,6 @@ async def list_vms(as_json: bool):
1086
1131
  tablefmt="grid"
1087
1132
  ))
1088
1133
  click.echo("\n" + "─" * 60)
1089
-
1090
1134
  return result
1091
1135
 
1092
1136
  except Exception as e:
@@ -1096,6 +1140,13 @@ async def list_vms(as_json: bool):
1096
1140
  logger.error(f"Failed to list VMs: {error_msg}")
1097
1141
  raise click.Abort()
1098
1142
 
1143
+ finally:
1144
+ if as_json:
1145
+ try:
1146
+ del os.environ["GOLEM_SILENCE_LOGS"]
1147
+ except Exception:
1148
+ pass
1149
+
1099
1150
 
1100
1151
  def main():
1101
1152
  """Entry point for the CLI."""
requestor/config.py CHANGED
@@ -4,6 +4,7 @@ import os
4
4
  from pydantic_settings import BaseSettings, SettingsConfigDict
5
5
  from pydantic import Field, field_validator, ValidationInfo
6
6
  import os
7
+ import sys
7
8
 
8
9
 
9
10
  def ensure_config() -> None:
@@ -33,7 +34,8 @@ def ensure_config() -> None:
33
34
  created = True
34
35
 
35
36
  if created:
36
- print("Using default settings run with --help to customize")
37
+ # Write to stderr so stdout stays clean for JSON outputs
38
+ print("Using default settings – run with --help to customize", file=sys.stderr)
37
39
 
38
40
 
39
41
  ensure_config()
requestor/run.py CHANGED
@@ -4,6 +4,16 @@ import sys
4
4
  from pathlib import Path
5
5
  from dotenv import load_dotenv
6
6
 
7
+ if "--json" in sys.argv:
8
+ os.environ["GOLEM_SILENCE_LOGS"] = "1"
9
+ try:
10
+ import logging as _logging
11
+ _logging.getLogger().setLevel(_logging.CRITICAL)
12
+ _logging.getLogger('rlp').setLevel(_logging.CRITICAL)
13
+ _logging.getLogger('rlp.codec').setLevel(_logging.CRITICAL)
14
+ except Exception:
15
+ pass
16
+
7
17
  from requestor.utils.logging import setup_logger
8
18
 
9
19
  # Configure logging with debug mode from environment variable
@@ -61,6 +61,8 @@ def setup_logger(name: Optional[str] = None) -> logging.Logger:
61
61
 
62
62
  # Check DEBUG environment variable
63
63
  debug = os.getenv('DEBUG', '').lower() in ('1', 'true', 'yes')
64
+ # Global silence switch for JSON/machine outputs
65
+ silence = os.getenv('GOLEM_SILENCE_LOGS', '').lower() in ('1', 'true', 'yes')
64
66
 
65
67
  # Prevent duplicate logs by removing root handlers
66
68
  root = logging.getLogger()
@@ -86,13 +88,22 @@ def setup_logger(name: Optional[str] = None) -> logging.Logger:
86
88
  style='%'
87
89
  )
88
90
  fancy_handler.setFormatter(fancy_formatter)
89
- fancy_handler.addFilter(
90
- lambda record: record.levelno != DEBUG or debug
91
- )
91
+ # Suppress DEBUG unless DEBUG=1; suppress everything if silence
92
+ def _filter(record: logging.LogRecord) -> bool:
93
+ if silence:
94
+ return False
95
+ return (record.levelno != DEBUG) or debug
96
+ fancy_handler.addFilter(_filter)
92
97
  logger.addHandler(fancy_handler)
93
98
  logger.propagate = False # Prevent propagation to avoid duplicates
94
99
 
95
- if debug:
100
+ if silence:
101
+ logger.setLevel(CRITICAL)
102
+ # Silence common libraries and root logger
103
+ logging.getLogger().setLevel(CRITICAL)
104
+ logging.getLogger('asyncio').setLevel(CRITICAL)
105
+ logging.getLogger('aiosqlite').setLevel(CRITICAL)
106
+ elif debug:
96
107
  logger.setLevel(DEBUG)
97
108
  # Enable debug logging for other libraries
98
109
  logging.getLogger('asyncio').setLevel(DEBUG)
@@ -11,26 +11,27 @@ class Spinner:
11
11
  self.busy = False
12
12
  self.spinner_visible = False
13
13
  self.message = message
14
- sys.stdout.write('\033[?25l') # Hide cursor
14
+ # Use stderr so stdout can remain machine-readable (e.g., --json outputs)
15
+ sys.stderr.write('\033[?25l') # Hide cursor
15
16
 
16
17
  def write_next(self):
17
18
  """Write the next spinner frame."""
18
19
  with self._screen_lock:
19
20
  if not self.spinner_visible:
20
- sys.stdout.write(f"\r{next(self.spinner)} {self.message}")
21
+ sys.stderr.write(f"\r{next(self.spinner)} {self.message}")
21
22
  self.spinner_visible = True
22
- sys.stdout.flush()
23
+ sys.stderr.flush()
23
24
 
24
25
  def remove_spinner(self, cleanup=False):
25
26
  """Remove the spinner from the terminal."""
26
27
  with self._screen_lock:
27
28
  if self.spinner_visible:
28
- sys.stdout.write('\r')
29
- sys.stdout.write(' ' * (len(self.message) + 2))
30
- sys.stdout.write('\r')
29
+ sys.stderr.write('\r')
30
+ sys.stderr.write(' ' * (len(self.message) + 2))
31
+ sys.stderr.write('\r')
31
32
  if cleanup:
32
- sys.stdout.write('\033[?25h') # Show cursor
33
- sys.stdout.flush()
33
+ sys.stderr.write('\033[?25h') # Show cursor
34
+ sys.stderr.flush()
34
35
  self.spinner_visible = False
35
36
 
36
37
  def spinner_task(self):
@@ -56,11 +57,11 @@ class Spinner:
56
57
  self.remove_spinner(cleanup=True)
57
58
  if exc_type is None:
58
59
  # Show checkmark on success
59
- sys.stdout.write(f"\r✓ {self.message}\n")
60
+ sys.stderr.write(f"\r✓ {self.message}\n")
60
61
  else:
61
62
  # Show X on failure
62
- sys.stdout.write(f"\r✗ {self.message}\n")
63
- sys.stdout.flush()
63
+ sys.stderr.write(f"\r✗ {self.message}\n")
64
+ sys.stderr.flush()
64
65
 
65
66
  def step(message):
66
67
  """Decorator to add a spinning progress indicator to a function."""