Skip to content

Commit

Permalink
fix: Merge branch 'main' into fix/cluster-credentials
Browse files Browse the repository at this point in the history
  • Loading branch information
Ninjagod1251 committed Jan 17, 2025
2 parents a34174f + f67ea6c commit 88a6d62
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 56 deletions.
87 changes: 55 additions & 32 deletions silverback/_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@
from ape.contracts import ContractInstance
from fief_client.integrations.cli import FiefAuth

from silverback.cluster.client import ClusterClient, PlatformClient
from silverback.cluster.client import Bot, ClusterClient, PlatformClient
from silverback.cluster.types import VariableGroupInfo

LOCAL_DATETIME = "%Y-%m-%d %H:%M:%S %Z"

Expand Down Expand Up @@ -1023,7 +1024,7 @@ def new_bot(
image: str,
network: str,
account: str | None,
vargroups: list[str],
vargroups: list["VariableGroupInfo"],
registry_credentials_name: str | None,
name: str,
):
Expand All @@ -1032,7 +1033,7 @@ def new_bot(
if name in cluster.bots:
raise click.UsageError(f"Cannot use name '{name}' to create bot")

environment = [cluster.variable_groups[vg_name].get_revision("latest") for vg_name in vargroups]
vargroup = [group for group in vargroups]

registry_credentials_id = None
if registry_credentials_name:
Expand All @@ -1045,11 +1046,11 @@ def new_bot(
click.echo(f"Name: {name}")
click.echo(f"Image: {image}")
click.echo(f"Network: {network}")
if environment:
click.echo("Environment:")
click.echo(yaml.safe_dump([var for vg in environment for var in vg.variables]))
if vargroup:
click.echo("Vargroups:")
click.echo(yaml.safe_dump(vargroup))
if registry_credentials_id:
click.echo(f"registry credentials: {registry_credentials_name}")
click.echo(f"Registry credentials: {registry_credentials_name}")

if not click.confirm("Do you want to create and start running this bot?"):
return
Expand All @@ -1059,7 +1060,7 @@ def new_bot(
image,
network,
account=account,
environment=environment,
vargroup=vargroup,
registry_credentials_id=registry_credentials_id,
)
click.secho(f"Bot '{bot.name}' ({bot.id}) deploying...", fg="green", bold=True)
Expand All @@ -1070,8 +1071,29 @@ def new_bot(
def list_bots(cluster: "ClusterClient"):
"""List all bots in a CLUSTER (Regardless of status)"""

if bot_names := list(cluster.bots):
click.echo(yaml.safe_dump(bot_names))
if bot_names := cluster.bots_list():
grouped_bots: dict[str, dict[str, list[Bot]]] = {}
for bot_list in bot_names.values():
for bot in bot_list:
ecosystem, network, provider = bot.network.split("-")
network_key = f"{network}-{provider}"
grouped_bots.setdefault(ecosystem, {}).setdefault(network_key, []).append(bot)

for ecosystem in sorted(grouped_bots.keys()):
grouped_bots[ecosystem] = {
network: sorted(bots, key=lambda b: b.name)
for network, bots in sorted(grouped_bots[ecosystem].items())
}

output = ""
for ecosystem in grouped_bots:
output += f"{ecosystem}:\n"
for network in grouped_bots[ecosystem]:
output += f" {network}:\n"
for bot in grouped_bots[ecosystem][network]:
output += f" - {bot.name}\n"

click.echo(output)

else:
click.secho("No bots in this cluster", bold=True, fg="red")
Expand All @@ -1091,7 +1113,7 @@ def bot_info(cluster: "ClusterClient", bot_name: str):
exclude={
"id",
"name",
"environment",
"vargroup",
"registry_credentials_id",
"registry_credentials",
}
Expand All @@ -1102,9 +1124,9 @@ def bot_info(cluster: "ClusterClient", bot_name: str):
)

click.echo(yaml.safe_dump(bot_dump))
if bot.environment:
click.echo("environment:")
click.echo(yaml.safe_dump([var.name for var in bot.environment]))
if bot.vargroup:
click.echo("Vargroups:")
click.echo(yaml.safe_dump([var.name for var in bot.vargroup]))


@bots.command(name="update", section="Configuration Commands")
Expand All @@ -1127,7 +1149,7 @@ def update_bot(
image: str | None,
network: str | None,
account: str | None,
vargroups: list[str],
vargroups: list["VariableGroupInfo"],
registry_credentials_name: str | None,
name: str,
):
Expand Down Expand Up @@ -1160,20 +1182,20 @@ def update_bot(
redeploy_required = True
click.echo(f"Image:\n old: {bot.image}\n new: {image}")

environment = [cluster.variable_groups[vg_name].get_revision("latest") for vg_name in vargroups]
vargroup = [group for group in vargroups]

set_environment = True
set_vargroup = True

if len(environment) == 0 and bot.environment:
set_environment = click.confirm("Do you want to clear all environment variables?")
if len(vargroup) == 0 and bot.vargroup:
set_vargroup = click.confirm("Do you want to clear all variable groups?")

elif environment != bot.environment:
click.echo("old-environment:")
click.echo(yaml.safe_dump([var.name for var in bot.environment]))
click.echo("new-environment:")
click.echo(yaml.safe_dump([var for vg in environment for var in vg.variables]))
elif vargroup != bot.vargroup:
click.echo("old-vargroup:")
click.echo(yaml.safe_dump(bot.vargroup))
click.echo("new-vargroup:")
click.echo(yaml.safe_dump(vargroup))

redeploy_required |= set_environment
redeploy_required |= set_vargroup

if not click.confirm(
f"Do you want to update '{name}'?"
Expand All @@ -1187,21 +1209,22 @@ def update_bot(
image=image,
network=network,
account=account,
environment=environment if set_environment else None,
vargroup=vargroup if set_vargroup else None,
registry_credentials_id=registry_credentials_id,
)

# NOTE: Skip machine `.id`
click.echo(yaml.safe_dump(bot.model_dump(exclude={"id", "environment"})))
if bot.environment:
click.echo("environment:")
click.echo(yaml.safe_dump([var.name for var in bot.environment]))
click.echo(yaml.safe_dump(bot.model_dump(exclude={"id", "vargroup"})))
if bot.vargroup:
click.echo("Vargroups:")
click.echo(yaml.safe_dump(vargroup))


@bots.command(name="remove", section="Configuration Commands")
@click.argument("name", metavar="BOT")
@click.option("-n", "--network", required=True)
@cluster_client
def remove_bot(cluster: "ClusterClient", name: str):
def remove_bot(cluster: "ClusterClient", name: str, network: str):
"""Remove BOT from CLUSTER (Shutdown if running)"""

if not (bot := cluster.bots.get(name)):
Expand All @@ -1210,7 +1233,7 @@ def remove_bot(cluster: "ClusterClient", name: str):
elif not click.confirm(f"Do you want to shutdown and delete '{name}'?"):
return

bot.remove()
bot.remove(network)
click.secho(f"Bot '{bot.name}' removed.", fg="green", bold=True)


Expand Down
39 changes: 22 additions & 17 deletions silverback/cluster/client.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from collections import defaultdict
from datetime import datetime
from functools import cache
from typing import ClassVar, Literal
Expand Down Expand Up @@ -138,7 +139,7 @@ def update(
image: str | None = None,
network: str | None = None,
account: str | None = None,
environment: list[VariableGroupInfo] | None = None,
vargroup: list[VariableGroupInfo] | None = None,
registry_credentials_id: str | None = None,
) -> "Bot":
form: dict = dict(
Expand All @@ -148,15 +149,13 @@ def update(
network=network,
)

if environment:
form["environment"] = [
dict(id=str(env.id), revision=env.revision) for env in environment
]
if vargroup:
form["vargroup"] = vargroup

if registry_credentials_id:
form["registry_credentials_id"] = registry_credentials_id

response = self.cluster.put(f"/bots/{self.id}", json=form)
response = self.cluster.put(f"/bots/{self.name}", json=form)
handle_error_with_response(response)
return Bot.model_validate(response.json())

Expand All @@ -169,13 +168,13 @@ def health(self) -> BotHealth:
return BotHealth.model_validate(raw_health) # response.json()) TODO: Migrate this endpoint

def stop(self):
response = self.cluster.post(f"/bots/{self.id}/stop")
response = self.cluster.post(f"/bots/{self.name}/stop")
handle_error_with_response(response)

def start(self):
# response = self.cluster.post(f"/bots/{self.id}/start") TODO: Add `/start`
# NOTE: Currently, a noop PUT request will trigger a start
response = self.cluster.put(f"/bots/{self.id}", json=dict(name=self.name))
response = self.cluster.put(f"/bots/{self.name}", json=dict(name=self.name))
handle_error_with_response(response)

@computed_field # type: ignore[prop-decorator]
Expand All @@ -189,7 +188,7 @@ def registry_credentials(self) -> RegistryCredentials | None:

@property
def errors(self) -> list[str]:
response = self.cluster.get(f"/bots/{self.id}/errors")
response = self.cluster.get(f"/bots/{self.name}/errors")
handle_error_with_response(response)
return response.json()

Expand All @@ -207,16 +206,16 @@ def filter_logs(
if end_time:
query["end_time"] = end_time.isoformat()

response = self.cluster.get(f"/bots/{self.id}/logs", params=query, timeout=120)
response = self.cluster.get(f"/bots/{self.name}/logs", params=query, timeout=120)
handle_error_with_response(response)
return [BotLogEntry.model_validate(log) for log in response.json()]

@property
def logs(self) -> list[BotLogEntry]:
return self.filter_logs()

def remove(self):
response = self.cluster.delete(f"/bots/{self.id}")
def remove(self, network: str):
response = self.cluster.delete(f"/bots/{self.name}", params={"network": network})
handle_error_with_response(response)


Expand Down Expand Up @@ -306,13 +305,21 @@ def bots(self) -> dict[str, Bot]:
handle_error_with_response(response)
return {bot.name: bot for bot in map(Bot.model_validate, response.json())}

def bots_list(self) -> dict[str, list[Bot]]:
response = self.get("/bots")
handle_error_with_response(response)
bots_dict = defaultdict(list)
for bot in map(Bot.model_validate, response.json()):
bots_dict[bot.name].append(bot)
return dict(bots_dict)

def new_bot(
self,
name: str,
image: str,
network: str,
account: str | None = None,
environment: list[VariableGroupInfo] | None = None,
vargroup: list[VariableGroupInfo] | None = None,
registry_credentials_id: str | None = None,
) -> Bot:
form: dict = dict(
Expand All @@ -322,10 +329,8 @@ def new_bot(
account=account,
)

if environment is not None:
form["environment"] = [
dict(id=str(env.id), revision=env.revision) for env in environment
]
if vargroup is not None:
form["vargroup"] = vargroup

if registry_credentials_id:
form["registry_credentials_id"] = registry_credentials_id
Expand Down
8 changes: 1 addition & 7 deletions silverback/cluster/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -343,12 +343,6 @@ class VariableGroupInfo(BaseModel):
created: datetime


class EnvironmentVariable(BaseModel):
name: str
group_id: uuid.UUID
group_revision: int


class BotTaskStatus(BaseModel):
last_status: str
exit_code: int | None
Expand Down Expand Up @@ -376,7 +370,7 @@ class BotInfo(BaseModel):
revision: int
registry_credentials_id: str | None

environment: list[EnvironmentVariable] = []
vargroup: list[VariableGroupInfo] = []


class BotLogEntry(BaseModel):
Expand Down

0 comments on commit 88a6d62

Please sign in to comment.