Skip to content

Feat: New pricing system #332

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 36 commits into from
Feb 18, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
e3bfcd8
Minor fixes: switch api host / sdk version for dev, fix other cmd tes…
philogicae Feb 11, 2025
6d56502
Allow to pass a comma separated list to aleph file forget
philogicae Feb 11, 2025
ed8b558
Add get_balance() and fix displayed amounts
philogicae Feb 11, 2025
0d00f58
Add pricing aggregate, displayable tables, and new cmds
philogicae Feb 11, 2025
09aa7e6
Add pricing tests
philogicae Feb 11, 2025
1a57a97
instances: add compute units, add pricing tables for regular/coco, up…
philogicae Feb 11, 2025
4378aae
Fix instance tests
philogicae Feb 11, 2025
d598d5c
Change displayed dates in local timezone after ruff fixes
philogicae Feb 11, 2025
befdb86
Fix volume prompting
philogicae Feb 11, 2025
665a741
Fix: Allow T&C for hold-tier (coco edge case)
philogicae Feb 11, 2025
c935bec
Instance: replace node list aggregate by program call
philogicae Feb 12, 2025
24091a6
Fix instance test after last commit
philogicae Feb 12, 2025
7d9ebd6
Change aggr addr, add fetch_settings, minor fixes
philogicae Feb 13, 2025
d9426e3
Add latest crn version and compatible_available_gpus filters
philogicae Feb 13, 2025
0e281be
Fix "rate limit exceeded" on github api call for CI
philogicae Feb 13, 2025
58bc5ae
Add community flow, split in 2 flows, handle legacy flows on instance…
philogicae Feb 13, 2025
f9b7e8a
Add "aleph instance gpu" cmd
philogicae Feb 13, 2025
19f893c
Move async_lru_cache and improve network.py
philogicae Feb 14, 2025
97b89ef
Imrpove pricing.py for gpu and rename cmd
philogicae Feb 14, 2025
46b2ec0
Add gpu model filter in crn table
philogicae Feb 14, 2025
0820a8f
Add complete workflow for gpu instance creation
philogicae Feb 14, 2025
8dee425
Remove gpu test for now (requires user input)
philogicae Feb 14, 2025
b635774
mypy fixes
philogicae Feb 14, 2025
e2275c3
Create found_gpus_by_model + fix typos
philogicae Feb 17, 2025
6f370d3
Fix program: add internet option + update tests
philogicae Feb 17, 2025
f590c9a
Upgrade CI actions
philogicae Feb 17, 2025
f11e460
typos
philogicae Feb 17, 2025
f8cebc7
Rework programs for new pricing system + tests
philogicae Feb 17, 2025
628a3e3
Deprecate firecracker hypervisor for instances
philogicae Feb 18, 2025
8daa602
Fix on runtime-checker
philogicae Feb 18, 2025
8736bad
Fix legacy flow handling
philogicae Feb 18, 2025
8dde221
Fix edge case if no gpu available
philogicae Feb 18, 2025
c3a8b64
Add verbose arg to pricing table and runtime-checker
philogicae Feb 18, 2025
c0c4476
Change crn for instance test
philogicae Feb 18, 2025
a51c6a2
Use CRN_URL_FOR_PROGRAMS in network.py
philogicae Feb 18, 2025
56b9817
Update pyproject after sdk release
philogicae Feb 18, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/pytest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ jobs:

- name: Set up Python for macOS
if: startsWith(matrix.os, 'macos')
uses: actions/setup-python@v2
uses: actions/setup-python@v5
with:
python-version: 3.11

Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/test-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jobs:
runs-on: ${{matrix.os}}

steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4

- name: Workaround github issue https://github.com/actions/runner-images/issues/7192
if: startsWith(matrix.os, 'ubuntu-')
Expand All @@ -35,7 +35,7 @@ jobs:

- name: Set up Python for macOS
if: startsWith(matrix.os, 'macos')
uses: actions/setup-python@v2
uses: actions/setup-python@v5
with:
python-version: 3.11

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/test-docker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
runs-on: ubuntu-22.04

steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4

# Use GitHub's Docker registry to cache intermediate layers
- run: echo ${{ secrets.GITHUB_TOKEN }} | docker login docker.pkg.github.com
Expand Down
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ dynamic = [ "version" ]
dependencies = [
"aiodns==3.2",
"aiohttp==3.11.12",
"aleph-message>=0.6",
"aleph-sdk-python>=1.3,<2",
"aleph-message>=0.6.1",
"aleph-sdk-python>=1.4,<2",
"base58==2.1.1", # Needed now as default with _load_account changement
"py-sr25519-bindings==0.2", # Needed for DOT signatures
"pygments==2.19.1",
Expand Down
2 changes: 2 additions & 0 deletions src/aleph_client/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
instance,
message,
node,
pricing,
program,
)
from aleph_client.utils import AsyncTyper
Expand All @@ -32,6 +33,7 @@
app.add_typer(domain.app, name="domain", help="Manage custom domain (DNS) on aleph.im & twentysix.cloud")
app.add_typer(node.app, name="node", help="Get node info on aleph.im & twentysix.cloud")
app.add_typer(about.app, name="about", help="Display the informations of Aleph CLI")
app.command("pricing")(pricing.prices_for_service)

if __name__ == "__main__":
app()
100 changes: 53 additions & 47 deletions src/aleph_client/commands/account.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
get_chains_with_super_token,
get_compatible_chains,
)
from aleph.sdk.utils import bytes_from_hex
from aleph.sdk.utils import bytes_from_hex, displayable_amount
from aleph_message.models import Chain
from rich.console import Console
from rich.panel import Panel
Expand Down Expand Up @@ -241,6 +241,20 @@
typer.echo("\nSignature: " + signature.hex())


async def get_balance(address: str) -> dict:
balance_data: dict = {}
uri = f"{settings.API_HOST}/api/v0/addresses/{address}/balance"
async with aiohttp.ClientSession() as session:
response = await session.get(uri)
if response.status == 200:
balance_data = await response.json()
balance_data["available_amount"] = balance_data["balance"] - balance_data["locked_amount"]
else:
error = f"Failed to retrieve balance for address {address}. Status code: {response.status}"
raise Exception(error)

Check warning on line 254 in src/aleph_client/commands/account.py

View check run for this annotation

Codecov / codecov/patch

src/aleph_client/commands/account.py#L253-L254

Added lines #L253 - L254 were not covered by tests
return balance_data


@app.command()
async def balance(
address: Optional[str] = typer.Option(None, help="Address"),
Expand All @@ -255,54 +269,46 @@
address = account.get_address()

if address:
uri = f"{settings.API_HOST}/api/v0/addresses/{address}/balance"

async with aiohttp.ClientSession() as session:
response = await session.get(uri)
if response.status == 200:
balance_data = await response.json()
balance_data["available_amount"] = balance_data["balance"] - balance_data["locked_amount"]

infos = [
Text.from_markup(f"Address: [bright_cyan]{balance_data['address']}[/bright_cyan]"),
Text.from_markup(
f"\nBalance: [bright_cyan]{balance_data['balance']:.2f}".rstrip("0").rstrip(".")
+ "[/bright_cyan]"
),
]
details = balance_data.get("details")
if details:
infos += [Text("\n ↳ Details")]
for chain_, chain_balance in details.items():
infos += [
Text.from_markup(
f"\n {chain_}: [orange3]{chain_balance:.2f}".rstrip("0").rstrip(".") + "[/orange3]"
)
]
available_color = "bright_cyan" if balance_data["available_amount"] >= 0 else "red"
infos += [
Text.from_markup(
f"\n - Locked: [bright_cyan]{balance_data['locked_amount']:.2f}".rstrip("0").rstrip(".")
+ "[/bright_cyan]"
),
Text.from_markup(
f"\n - Available: [{available_color}]{balance_data['available_amount']:.2f}".rstrip("0").rstrip(
"."
try:
balance_data = await get_balance(address)
infos = [
Text.from_markup(f"Address: [bright_cyan]{balance_data['address']}[/bright_cyan]"),
Text.from_markup(
f"\nBalance: [bright_cyan]{displayable_amount(balance_data['balance'], decimals=2)}[/bright_cyan]"
),
]
details = balance_data.get("details")
if details:
infos += [Text("\n ↳ Details")]

Check warning on line 282 in src/aleph_client/commands/account.py

View check run for this annotation

Codecov / codecov/patch

src/aleph_client/commands/account.py#L282

Added line #L282 was not covered by tests
for chain_, chain_balance in details.items():
infos += [

Check warning on line 284 in src/aleph_client/commands/account.py

View check run for this annotation

Codecov / codecov/patch

src/aleph_client/commands/account.py#L284

Added line #L284 was not covered by tests
Text.from_markup(
f"\n {chain_}: [orange3]{displayable_amount(chain_balance, decimals=2)}[/orange3]"
)
+ f"[/{available_color}]"
),
]
console.print(
Panel(
Text.assemble(*infos),
title="Account Infos",
border_style="bright_cyan",
expand=False,
title_align="left",
)
]
available_color = "bright_cyan" if balance_data["available_amount"] >= 0 else "red"
infos += [
Text.from_markup(
f"\n - Locked: [bright_cyan]{displayable_amount(balance_data['locked_amount'], decimals=2)}"
"[/bright_cyan]"
),
Text.from_markup(
f"\n - Available: [{available_color}]"
f"{displayable_amount(balance_data['available_amount'], decimals=2)}"
f"[/{available_color}]"
),
]
console.print(
Panel(
Text.assemble(*infos),
title="Account Infos",
border_style="bright_cyan",
expand=False,
title_align="left",
)
else:
typer.echo(f"Failed to retrieve balance for address {address}. Status code: {response.status}")
)
except Exception as e:
typer.echo(e)

Check warning on line 311 in src/aleph_client/commands/account.py

View check run for this annotation

Codecov / codecov/patch

src/aleph_client/commands/account.py#L310-L311

Added lines #L310 - L311 were not covered by tests
else:
typer.echo("Error: Please provide either a private key, private key file, or an address.")

Expand Down
8 changes: 6 additions & 2 deletions src/aleph_client/commands/files.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,9 @@

@app.command()
async def forget(
item_hash: str = typer.Argument(..., help="Hash to forget"),
item_hash: str = typer.Argument(
..., help="Hash(es) to forget. Must be a comma separated list. Example: `123...abc` or `123...abc,456...xyz`"
),
reason: str = typer.Argument("User deletion", help="reason to forget"),
channel: Optional[str] = typer.Option(default=settings.DEFAULT_CHANNEL, help=help_strings.CHANNEL),
private_key: Optional[str] = typer.Option(settings.PRIVATE_KEY_STRING, help=help_strings.PRIVATE_KEY),
Expand All @@ -155,8 +157,10 @@

account: AccountFromPrivateKey = _load_account(private_key, private_key_file)

hashes = [ItemHash(item_hash) for item_hash in item_hash.split(",")]

Check warning on line 160 in src/aleph_client/commands/files.py

View check run for this annotation

Codecov / codecov/patch

src/aleph_client/commands/files.py#L160

Added line #L160 was not covered by tests

async with AuthenticatedAlephHttpClient(account=account, api_server=settings.API_HOST) as client:
value = await client.forget(hashes=[ItemHash(item_hash)], reason=reason, channel=channel)
value = await client.forget(hashes=hashes, reason=reason, channel=channel)

Check warning on line 163 in src/aleph_client/commands/files.py

View check run for this annotation

Codecov / codecov/patch

src/aleph_client/commands/files.py#L163

Added line #L163 was not covered by tests
typer.echo(f"{value[0].json(indent=4)}")


Expand Down
15 changes: 9 additions & 6 deletions src/aleph_client/commands/help_strings.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,15 @@
ASK_FOR_CONFIRMATION = "Prompt user for confirmation"
IPFS_CATCH_ALL_PATH = "Choose a relative path to catch all unmatched route or a 404 error"
PAYMENT_TYPE = "Payment method, either holding tokens, NFTs, or Pay-As-You-Go via token streaming"
HYPERVISOR = "Hypervisor to use to launch your instance. Defaults to QEMU"
HYPERVISOR = "Hypervisor to use to launch your instance. Always defaults to QEMU, since Firecracker is now deprecated for instances"
INSTANCE_NAME = "Name of your new instance"
ROOTFS = (
"Hash of the rootfs to use for your instance. Defaults to Ubuntu 22. You can also create your own rootfs and pin it"
)
ROOTFS_SIZE = (
"Size of the rootfs to use for your instance. If not set, content.size of the --rootfs store message will be used"
)
COMPUTE_UNITS = "Number of compute units to allocate. Compute units correspond to a tier that includes vcpus, memory, disk and gpu presets. For reference, run: `aleph pricing --help`"
ROOTFS_SIZE = "Rootfs size in MiB to allocate"
VCPUS = "Number of virtual CPUs to allocate"
MEMORY = "Maximum memory (RAM) allocation on VM in MiB"
MEMORY = "Maximum memory (RAM) in MiB to allocate"
TIMEOUT_SECONDS = "If vm is not called after [timeout_seconds] it will shutdown"
SSH_PUBKEY_FILE = "Path to a public ssh key to be added to the instance"
CRN_HASH = "Hash of the CRN to deploy to (only applicable for confidential and/or Pay-As-You-Go instances)"
Expand All @@ -37,6 +36,7 @@
CONFIDENTIAL_FIRMWARE_HASH = "Hash of the UEFI Firmware content, to validate measure (ignored if path is provided)"
CONFIDENTIAL_FIRMWARE_PATH = "Path to the UEFI Firmware content, to validate measure (instead of the hash)"
GPU_OPTION = "Launch an instance attaching a GPU to it"
GPU_PREMIUM_OPTION = "Use Premium GPUs (VRAM > 48GiB)"
KEEP_SESSION = "Keeping the already initiated session"
VM_SECRET = "Secret password to start the VM"
CRN_URL_VM_DELETION = "Domain of the CRN where an associated VM is running. It ensures your VM will be stopped and erased on the CRN before the instance message is actually deleted"
Expand All @@ -51,15 +51,18 @@
PAYMENT_CHAIN_USED = "Chain you are using to pay for your instance"
ORIGIN_CHAIN = "Chain of origin of your private key (ensuring correct parsing)"
ADDRESS_CHAIN = "Chain for the address"
ADDRESS_PAYER = "Address of the payer. In order to delegate the payment, your account must be authorized beforehand to publish on the behalf of this address. See the docs for more info: https://docs.aleph.im/protocol/permissions/"
CREATE_REPLACE = "Overwrites private key file if it already exists"
CREATE_ACTIVE = "Loads the new private key after creation"
PROMPT_CRN_URL = "URL of the CRN (Compute node) on which the instance is running"
PROMPT_PROGRAM_CRN_URL = "URL of the CRN (Compute node) on which the program is running"
PROGRAM_PATH = "Path to your source code. Can be a directory, a .squashfs file or a .zip archive"
PROGRAM_ENTRYPOINT = "Your program entrypoint. Example: `main:app` for Python programs, else `run.sh` for a script containing your launch command"
PROGRAM_RUNTIME = "Hash of the runtime to use for your program. You can also create your own runtime and pin it. Currently defaults to `{runtime_id}` (Use `aleph program runtime-checker` to inspect it)"
PROGRAM_BETA = "If true, you will be prompted to add message subscriptions to your program"
PROGRAM_INTERNET = "Enable internet access for your program. By default, internet access is disabled"
PROGRAM_PERSISTENT = "Create your program as persistent. By default, programs are ephemeral (serverless): they only start when called and then shutdown after the defined timeout delay."
PROGRAM_UPDATABLE = "Allow program updates. By default, only the source code can be modified without requiring redeployement (same item hash). When enabled (set to True), this option allows to update any other field. However, such modifications will require a program redeployment (new item hash)"
PROGRAM_BETA = "If true, you will be prompted to add message subscriptions to your program"
PROGRAM_KEEP_CODE = "Keep the source code intact instead of deleting it"
PROGRAM_KEEP_PREV = "Keep the previous program intact instead of deleting it"
TARGET_ADDRESS = "Target address. Defaults to current account address"
Expand Down
Loading
Loading