v10.2.0: Support new deleted_by and forgotten_at fields for servers

This commit is contained in:
Administrator 2023-05-03 23:24:18 +00:00
parent 7c6f57068d
commit c5c4d9797d
6 changed files with 49 additions and 25 deletions

View File

@ -8,12 +8,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## Deprecated features that will be removed in the next major version.
- `burn_rate` from `TokenInfo` is deprecated. Use `burn_rate_cents` or `burn_rate_usd` instead.
- `--no-local` will become the default for `sporestack server list`.
## [Unreleased]
- Nothing yet.
## [10.1.2]
## [10.2.0 - 2023-05-03]
## Changed
- Updated client to support new `forgotten_at` field and `deleted_by`.
## [10.1.2 - 2023-04-14]
## Fixed

View File

@ -2,4 +2,4 @@
__all__ = ["api", "api_client", "exceptions"]
__version__ = "10.1.2"
__version__ = "10.2.0"

View File

@ -1,8 +1,4 @@
"""
SporeStack API request/response models
"""
"""SporeStack API request/response models"""
from datetime import datetime
@ -21,7 +17,7 @@ class TokenAdd:
class Request(BaseModel):
currency: str
dollars: int
affiliate_token: Optional[str] = None
affiliate_token: Union[str, None] = None
class Response(BaseModel):
token: str
@ -88,6 +84,15 @@ class ServerTopup:
token: Union[str, None] = None
class ServerDeletedBy(str, Enum):
EXPIRATION = "expiration"
"""The server was deleted automatically for being expired."""
MANUAL = "manual"
"""The server was deleted before its expiration via the API."""
SPORESTACK = "sporestack"
"""The server was deleted by SporeStack, likely due to an AUP violation."""
class ServerInfo:
url = "/server/{machine_id}/info"
method = "GET"
@ -104,6 +109,8 @@ class ServerInfo:
flavor: Flavor
deleted: bool
deleted_at: int
deleted_by: Union[ServerDeletedBy, None]
forgotten_at: Union[datetime, None]
operating_system: str
hostname: str
autorenew: bool
@ -120,13 +127,8 @@ class ServerStop:
class ServerDelete:
url = "/server/{machine_id}/delete"
method = "POST"
class ServerDestroy:
url = "/server/{machine_id}/destroy"
method = "POST"
url = "/server/{machine_id}"
method = "DELETE"
class ServerForget:

View File

@ -185,13 +185,11 @@ class APIClient:
def server_delete(self, machine_id: str) -> None:
"""Delete a server."""
url = self.api_endpoint + api.ServerDelete.url.format(machine_id=machine_id)
response = self._httpx_client.post(url)
response = self._httpx_client.delete(url)
_handle_response(response)
def server_forget(self, machine_id: str) -> None:
"""
Forget about a destroyed/deleted server.
"""
"""Forget about a deleted server to hide it from view."""
url = self.api_endpoint + api.ServerForget.url.format(machine_id=machine_id)
response = self._httpx_client.post(url)
_handle_response(response)

View File

@ -279,6 +279,10 @@ def pretty_machine_info(info: Dict[str, Any]) -> str:
return msg
def epoch_to_human(epoch: int) -> str:
return time.strftime("%Y-%m-%d %H:%M:%S %z", time.localtime(epoch))
def print_machine_info(info: "api.ServerInfo.Response") -> None:
if info.hostname != "":
typer.echo(f"Hostname: {info.hostname}")
@ -296,13 +300,16 @@ def print_machine_info(info: "api.ServerInfo.Response") -> None:
typer.echo("IPv4: (Not yet assigned)")
typer.echo(f"Region: {info.region}")
typer.echo(f"Flavor: {info.flavor.slug}")
human_expiration = time.strftime(
"%Y-%m-%d %H:%M:%S %z", time.localtime(info.expiration)
)
typer.echo(f"Expiration: {info.expiration} ({human_expiration})")
typer.echo(f"Expiration: {epoch_to_human(info.expiration)}")
typer.echo(f"Token: {info.token}")
if info.deleted:
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)}")
if info.deleted_by is not None:
typer.echo(f"Server deleted by: {info.deleted_by.value}")
if info.forgotten_at is not None:
typer.echo(f"Server forgotten at: {info.forgotten_at}")
else:
typer.echo(f"Running: {info.running}")
time_to_live = info.expiration - int(time.time())
@ -317,6 +324,9 @@ def server_list(
local: bool = typer.Option(
True, help="List older servers not associated to token."
),
show_forgotten: bool = typer.Option(
False, help="Show deleted and forgotten servers."
),
) -> None:
"""List all locally known servers and all servers under the given token."""
from .api_client import APIClient
@ -339,6 +349,9 @@ def server_list(
printed_machine_ids = []
for info in server_infos:
if not show_forgotten and info.forgotten_at is not None:
continue
typer.echo()
hostname = info.hostname
@ -408,6 +421,8 @@ def _get_machine_id(machine_id: str, hostname: str, token: str) -> str:
api_client = APIClient(api_endpoint=get_api_endpoint())
for server in api_client.servers_launched_from_token(token=_token).servers:
if server.forgotten_at is not None:
continue
if server.hostname == hostname:
return server.machine_id

View File

@ -82,9 +82,11 @@ class Token:
"""Returns support messages for/from the token."""
self.api_client.token_send_message(token=self.token, message=message)
def servers(self) -> List[Server]:
def servers(self, show_forgotten: bool = False) -> List[Server]:
server_classes: List[Server] = []
for server in self.api_client.servers_launched_from_token(self.token).servers:
if not show_forgotten and server.forgotten_at is not None:
continue
server_classes.append(
Server(
machine_id=server.machine_id,