10.7.0: Add suspended server support
ci/woodpecker/push/woodpecker Pipeline failed Details
ci/woodpecker/tag/woodpecker Pipeline failed Details

This commit is contained in:
Administrator 2023-10-31 21:14:57 +00:00
parent 190b94746c
commit ac7eb3a186
6 changed files with 57 additions and 28 deletions

View File

@ -15,6 +15,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Nothing yet. - Nothing yet.
## [10.7.0 - 2023-10-31]
## Added
- Added `suspended_at` to server info response object.
- Added `autorenew_servers` to token info response object.
- Added `suspended_servers` to token info response object.
## [10.6.3 - 2023-09-18] ## [10.6.3 - 2023-09-18]
## Changed ## Changed

View File

@ -1,5 +1,5 @@
"""SporeStack API library and CLI for launching servers with Monero or Bitcoin""" """SporeStack API library and CLI for launching servers with Monero or Bitcoin"""
__all__ = ["api", "api_client", "exceptions"] __all__ = ["api", "api_client", "client", "exceptions"]
__version__ = "10.6.3" __version__ = "10.7.0"

View File

@ -117,10 +117,11 @@ class ServerInfo:
ipv6: str ipv6: str
region: str region: str
flavor: Flavor flavor: Flavor
deleted: bool deleted: Annotated[bool, Field(deprecated=True)]
deleted_at: int deleted_at: int
deleted_by: Union[ServerDeletedBy, None] deleted_by: Union[ServerDeletedBy, None]
forgotten_at: Union[datetime, None] forgotten_at: Union[datetime, None]
suspended_at: Union[datetime, None]
operating_system: str operating_system: str
hostname: str hostname: str
autorenew: bool autorenew: bool

View File

@ -303,38 +303,49 @@ def epoch_to_human(epoch: int) -> str:
def print_machine_info(info: "api.ServerInfo.Response") -> None: def print_machine_info(info: "api.ServerInfo.Response") -> None:
if info.hostname != "": from rich.console import Console
typer.echo(f"Hostname: {info.hostname}")
else:
typer.echo("Hostname: (none) (No hostname set)")
typer.echo(f"Machine ID (keep this secret!): {info.machine_id}") console = Console(width=None if sys.stdout.isatty() else 10**9)
output = ""
if info.hostname != "":
output += f"Hostname: {info.hostname}\n"
else:
output += "Hostname: (none) (No hostname set)\n"
output += f"Machine ID (keep this secret!): {info.machine_id}\n"
if info.ipv6 != "": if info.ipv6 != "":
typer.echo(f"IPv6: {info.ipv6}") output += f"IPv6: {info.ipv6}\n"
else: else:
typer.echo("IPv6: (Not yet assigned)") output += "IPv6: (Not yet assigned)\n"
if info.ipv4 != "": if info.ipv4 != "":
typer.echo(f"IPv4: {info.ipv4}") output += f"IPv4: {info.ipv4}\n"
else: else:
typer.echo("IPv4: (Not yet assigned)") output += "IPv4: (Not yet assigned)\n"
typer.echo(f"Region: {info.region}") output += f"Region: {info.region}\n"
typer.echo(f"Flavor: {info.flavor.slug}") output += f"Flavor: {info.flavor.slug}\n"
typer.echo(f"Expiration: {epoch_to_human(info.expiration)}") output += f"Token (keep this secret!): {info.token}\n"
typer.echo(f"Token (keep this secret!): {info.token}") if info.deleted_at != 0:
if info.deleted_at != 0 or info.deleted: output += f"Server deleted at: {epoch_to_human(info.deleted_at)}\n"
typer.echo("Server was deleted!")
if info.deleted_at != 0:
typer.echo(f"Server deleted at: {epoch_to_human(info.deleted_at)}")
if info.deleted_by is not None: if info.deleted_by is not None:
typer.echo(f"Server deleted by: {info.deleted_by.value}") output += f"Server deleted by: {info.deleted_by.value}\n"
if info.forgotten_at is not None: if info.forgotten_at is not None:
typer.echo(f"Server forgotten at: {info.forgotten_at}") output += f"Server forgotten at: {info.forgotten_at}\n"
else: else:
typer.echo(f"Running: {info.running}") msg = f"Running: {info.running}\n"
if info.suspended_at is not None:
msg = (
"Running: Server is powered off because it is [bold]suspended[/bold].\n"
)
output += msg
time_to_live = info.expiration - int(time.time()) time_to_live = info.expiration - int(time.time())
hours = time_to_live // 3600 hours = time_to_live // 3600
typer.echo(f"Server will be deleted in {hours} hours.") output += f"Server will be deleted in {hours} hours.\n"
typer.echo(f"Autorenew: {info.autorenew}") output += f"Expiration: {epoch_to_human(info.expiration)}\n"
output += f"Autorenew: {info.autorenew}"
console.print(output)
@server_cli.command(name="list") @server_cli.command(name="list")
@ -414,6 +425,9 @@ def server_list(
str(info.autorenew), str(info.autorenew),
) )
if info.suspended_at != 0:
typer.echo(f"Warning: {info.machine_id} is suspended!", err=True)
printed_machine_ids.append(info.machine_id) printed_machine_ids.append(info.machine_id)
console.print(table) console.print(table)
@ -887,7 +901,9 @@ def token_info(token: Annotated[str, typer.Argument()] = DEFAULT_TOKEN) -> None:
info = client.token.info() info = client.token.info()
print(f"[bold]Token Information for {token} ({_token})[/bold]") print(f"[bold]Token Information for {token} ({_token})[/bold]")
print(f"Balance: [green]{info.balance_usd}") print(f"Balance: [green]{info.balance_usd}")
print(f"Total Servers: {info.servers}") print(f"Total Servers (not deleted): {info.servers}")
print(f"Servers set to autorenew: {info.autorenew_servers}")
print(f"Suspended servers: {info.suspended_servers}")
print( print(
f"Burn Rate: [red]{info.burn_rate_usd}[/red] " f"Burn Rate: [red]{info.burn_rate_usd}[/red] "
"(per day of servers set to autorenew)" "(per day of servers set to autorenew)"

View File

@ -62,12 +62,13 @@ class OperatingSystem(BaseModel):
class TokenInfo(BaseModel): class TokenInfo(BaseModel):
balance_cents: int balance_cents: int
balance_usd: str balance_usd: str
burn_rate: int burn_rate: Annotated[int, Field(deprecated=True)]
"""Deprecated."""
burn_rate_cents: int burn_rate_cents: int
burn_rate_usd: str burn_rate_usd: str
days_remaining: int days_remaining: int
servers: int servers: int
autorenew_servers: int
suspended_servers: int
class Region(BaseModel): class Region(BaseModel):

View File

@ -81,6 +81,8 @@ def test_token_info(respx_mock: respx.MockRouter) -> None:
"balance_cents": 0, "balance_cents": 0,
"balance_usd": "$0.00", "balance_usd": "$0.00",
"servers": 0, "servers": 0,
"autorenew_servers": 0,
"suspended_servers": 0,
"burn_rate": 0, "burn_rate": 0,
"burn_rate_usd": "$0.00", "burn_rate_usd": "$0.00",
"burn_rate_cents": 0, "burn_rate_cents": 0,
@ -133,6 +135,7 @@ def test_server_info(respx_mock: respx.MockRouter) -> None:
"deleted_at": 0, "deleted_at": 0,
"deleted_by": None, "deleted_by": None,
"forgotten_at": None, "forgotten_at": None,
"suspended_at": None,
"operating_system": "debian-11", "operating_system": "debian-11",
} }
route_response = httpx.Response(200, json=response_json) route_response = httpx.Response(200, json=response_json)