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.
## [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]
## Changed

View File

@ -1,5 +1,5 @@
"""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
region: str
flavor: Flavor
deleted: bool
deleted: Annotated[bool, Field(deprecated=True)]
deleted_at: int
deleted_by: Union[ServerDeletedBy, None]
forgotten_at: Union[datetime, None]
suspended_at: Union[datetime, None]
operating_system: str
hostname: str
autorenew: bool

View File

@ -303,38 +303,49 @@ def epoch_to_human(epoch: int) -> str:
def print_machine_info(info: "api.ServerInfo.Response") -> None:
if info.hostname != "":
typer.echo(f"Hostname: {info.hostname}")
else:
typer.echo("Hostname: (none) (No hostname set)")
from rich.console import Console
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 != "":
typer.echo(f"IPv6: {info.ipv6}")
output += f"IPv6: {info.ipv6}\n"
else:
typer.echo("IPv6: (Not yet assigned)")
output += "IPv6: (Not yet assigned)\n"
if info.ipv4 != "":
typer.echo(f"IPv4: {info.ipv4}")
output += f"IPv4: {info.ipv4}\n"
else:
typer.echo("IPv4: (Not yet assigned)")
typer.echo(f"Region: {info.region}")
typer.echo(f"Flavor: {info.flavor.slug}")
typer.echo(f"Expiration: {epoch_to_human(info.expiration)}")
typer.echo(f"Token (keep this secret!): {info.token}")
if info.deleted_at != 0 or info.deleted:
typer.echo("Server was deleted!")
if info.deleted_at != 0:
typer.echo(f"Server deleted at: {epoch_to_human(info.deleted_at)}")
output += "IPv4: (Not yet assigned)\n"
output += f"Region: {info.region}\n"
output += f"Flavor: {info.flavor.slug}\n"
output += f"Token (keep this secret!): {info.token}\n"
if info.deleted_at != 0:
output += f"Server deleted at: {epoch_to_human(info.deleted_at)}\n"
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:
typer.echo(f"Server forgotten at: {info.forgotten_at}")
output += f"Server forgotten at: {info.forgotten_at}\n"
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())
hours = time_to_live // 3600
typer.echo(f"Server will be deleted in {hours} hours.")
typer.echo(f"Autorenew: {info.autorenew}")
output += f"Server will be deleted in {hours} hours.\n"
output += f"Expiration: {epoch_to_human(info.expiration)}\n"
output += f"Autorenew: {info.autorenew}"
console.print(output)
@server_cli.command(name="list")
@ -414,6 +425,9 @@ def server_list(
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)
console.print(table)
@ -887,7 +901,9 @@ def token_info(token: Annotated[str, typer.Argument()] = DEFAULT_TOKEN) -> None:
info = client.token.info()
print(f"[bold]Token Information for {token} ({_token})[/bold]")
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(
f"Burn Rate: [red]{info.burn_rate_usd}[/red] "
"(per day of servers set to autorenew)"

View File

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

View File

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