Skip to content

Commit b9dde90

Browse files
gwplclaude
andauthored
Auto power-on after resize and interactive disk resize option (#50)
* Auto power-on after resize and add 'nodisk' confirmation option DigitalOcean leaves droplets powered off after resize, with no API flag to auto-restart. Previously, `dropkit resize` completed silently with the droplet off — users had to discover this and run `dropkit on` manually. Now the resize command: 1. Automatically powers the droplet back on after resize completes, using the same pattern as `dropkit on` (with status polling and progress messages). 2. Offers a "nodisk" answer in the confirmation prompt when disk resize would increase disk size. This supports the common workflow of temporarily scaling up CPU/RAM for heavy builds or benchmarks and scaling back down later — which requires NOT resizing the disk (disk resize is permanent and prevents future downsizing). The prompt changes from: Are you sure? [yes/no] to: Are you sure? [yes/nodisk/no] with a tip explaining the option. The "nodisk" choice only appears when relevant (disk flag is true AND new size has larger disk). Expected terminal experience after resize: ✓ Resize completed successfully Powering on droplet... ✓ Power on action started (ID: 3105287233) Waiting for droplet to power on... ✓ Droplet powered on successfully Droplet claude-code-box has been resized to s-2vcpu-4gb and is now active Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Make disk resize an interactive option when not specified via flag Per reviewer feedback, instead of a "nodisk" escape hatch in the confirmation prompt, make --disk/--no-disk a tri-state (True/False/None). When neither flag is passed, the user is asked interactively — consistent with how region, size, and image are already handled. The interactive question only appears when the new size has a different disk size. It defaults to "no" (skip disk resize) since disk resize is permanent and prevents future downsizing. Flow with no flags: Changes: Disk: 25 GB → 80 GB (+55 GB) Disk resize is PERMANENT and cannot be undone. Skipping disk resize keeps the option to downsize later. Resize disk too? [yes/no] (no): Flow with --no-disk: skips the question, shows "not resized" Flow with --disk: skips the question, proceeds with disk resize Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Move interactive disk question before table display and drop isinstance guards Address ret2libc's review feedback: - Ask the interactive disk question BEFORE building the changes table, so the displayed disk row reflects the user's actual choice - Remove unnecessary isinstance(disk_diff, int) guards since disk_diff is always int (computed with an isinstance ternary that defaults to 0) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 9159934 commit b9dde90

1 file changed

Lines changed: 63 additions & 11 deletions

File tree

dropkit/main.py

Lines changed: 63 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3291,8 +3291,8 @@ def rename(
32913291
def resize(
32923292
droplet_name: str = typer.Argument(..., autocompletion=complete_droplet_or_snapshot_name),
32933293
size: str | None = typer.Option(None, "--size", "-s", help="New size slug (e.g., s-4vcpu-8gb)"),
3294-
disk: bool = typer.Option(
3295-
True, "--disk/--no-disk", help="Resize disk (permanent, default: True)"
3294+
disk: bool | None = typer.Option(
3295+
None, "--disk/--no-disk", help="Resize disk (permanent, asked interactively if omitted)"
32963296
),
32973297
):
32983298
"""
@@ -3493,13 +3493,36 @@ def resize(
34933493
if isinstance(new_disk, int) and isinstance(current_disk, int)
34943494
else 0
34953495
)
3496+
3497+
# If --disk/--no-disk was not explicitly passed, ask interactively
3498+
# when the new size has a different disk. This surfaces the
3499+
# permanent/irreversible nature of disk resize at decision time,
3500+
# consistent with how region/size/image are handled interactively.
3501+
# Resolved BEFORE building the table so the row reflects the choice.
3502+
if disk is None:
3503+
if disk_diff != 0:
3504+
console.print()
3505+
console.print(
3506+
"[bold yellow]Disk resize is PERMANENT and cannot be undone.[/bold yellow]"
3507+
)
3508+
console.print("[dim]Skipping disk resize keeps the option to downsize later.[/dim]")
3509+
disk_choice = Prompt.ask(
3510+
"[bold]Resize disk too?[/bold]",
3511+
choices=["yes", "no"],
3512+
default="no",
3513+
)
3514+
disk = disk_choice == "yes"
3515+
else:
3516+
# No disk change — default to True (no-op for disk)
3517+
disk = True
3518+
34963519
disk_change = f"{current_disk} GB → {new_disk} GB"
3497-
if disk and disk_diff > 0:
3520+
if disk is False:
3521+
disk_change = f"{current_disk} GB (not resized)"
3522+
elif disk_diff > 0:
34983523
disk_change += f" [green](+{disk_diff} GB)[/green]"
3499-
elif disk and disk_diff < 0:
3524+
elif disk_diff < 0:
35003525
disk_change += f" [yellow]({disk_diff} GB)[/yellow]"
3501-
elif not disk:
3502-
disk_change = f"{current_disk} GB (not resized)"
35033526
changes_table.add_row("Disk:", disk_change)
35043527

35053528
# Price
@@ -3516,16 +3539,17 @@ def resize(
35163539
# Show warnings
35173540
console.print()
35183541
console.print(
3519-
"[bold yellow]⚠ WARNING: This operation will cause downtime (droplet will be powered off)[/bold yellow]"
3542+
"[bold yellow]⚠ WARNING: This operation will cause downtime "
3543+
"(droplet will be powered off)[/bold yellow]"
35203544
)
35213545

3522-
if disk:
3546+
if disk and disk_diff > 0:
35233547
console.print(
35243548
"[bold red]⚠ WARNING: Disk resize is PERMANENT and cannot be undone![/bold red]"
35253549
)
3526-
else:
3550+
elif not disk:
35273551
console.print(
3528-
"[dim]Note: Disk will NOT be resized. You can resize it later, but it's permanent.[/dim]"
3552+
"[dim]Note: Disk will NOT be resized. You can resize back down later.[/dim]"
35293553
)
35303554

35313555
# Confirmation
@@ -3562,9 +3586,37 @@ def resize(
35623586
api.wait_for_action_complete(action_id, timeout=600) # 10 minutes
35633587

35643588
console.print("[green]✓[/green] Resize completed successfully")
3589+
3590+
# Power the droplet back on — DigitalOcean leaves it powered off
3591+
# after resize (no auto-power-on API flag exists). Since the user
3592+
# almost certainly wants their droplet running, we power it on
3593+
# automatically instead of leaving them to discover it's off.
3594+
console.print()
3595+
console.print("[dim]Powering on droplet...[/dim]")
3596+
3597+
power_action = api.power_on_droplet(droplet_id)
3598+
power_action_id = power_action.get("id")
3599+
3600+
if not power_action_id:
3601+
console.print(
3602+
"[yellow]Warning: Could not get power-on action ID. "
3603+
f"You may need to run: dropkit on {droplet_name}[/yellow]"
3604+
)
3605+
else:
3606+
console.print(
3607+
f"[green]✓[/green] Power on action started (ID: [cyan]{power_action_id}[/cyan])"
3608+
)
3609+
console.print("[dim]Waiting for droplet to power on...[/dim]")
3610+
3611+
with console.status("[cyan]Powering on...[/cyan]"):
3612+
api.wait_for_action_complete(power_action_id, timeout=120)
3613+
3614+
console.print("[green]✓[/green] Droplet powered on successfully")
3615+
35653616
console.print()
35663617
console.print(
3567-
f"[bold green]Droplet {droplet_name} has been resized to {new_size_slug}[/bold green]"
3618+
f"[bold green]Droplet {droplet_name} has been resized to "
3619+
f"{new_size_slug} and is now active[/bold green]"
35683620
)
35693621

35703622
except DigitalOceanAPIError as e:

0 commit comments

Comments
 (0)