Skip to content

Commit efdc64c

Browse files
feat(compute): improve error message when instance not found in zone (#805)
# Description When `exo compute instance <action>` commands fail because the instance does not exist in the default zone, the error message previously surfaced a raw SDK message with no context: ``` "foo" not found in ListInstancesResponse: Not Found ``` This PR introduces a `findInstance` helper in `cmd/compute/instance/instance.go` that wraps `FindListInstancesResponseInstances` and enriches the not-found error with the zone that was searched and a hint to use `-z`: ``` instance "foo" not found in zone ch-gva-2 Hint: use -z <zone> to specify a different zone, or run 'exo compute instance list' to see instances across all zones ``` Changes: * Added `findInstance` helper in `cmd/compute/instance/instance.go`, wrapping `FindListInstancesResponseInstances` with zone-aware error enrichment. * Migrated all 24 call sites across the instance subcommands (`show`, `reboot`, `start`, `stop`, `scale`, `update`, `reset`, `reset-password`, `reveal-password`, `resize-disk`, `scp`, `ssh`, `snapshot create`, `snapshot revert`, `security-group add/remove`, `private-network attach/detach/update-ip`, `elastic-ip attach/detach`, `enable-tpm`, `console-url`, `delete`) to use the new helper. * Added `tests/e2e/scenarios/with-api/compute/instance_not_found_error.txtar`, an API-driven e2e scenario verifying the enriched error message on `show`, `reboot` and `stop`. Uses the testscript runner from #804. * Redirected `go test` stderr to stdout in `.github/workflows/e2e.yml` to suppress a spurious "Error" banner in the GitHub Actions UI that appeared when the test runner wrote to stderr, even though the job itself succeeded. ## Checklist (For exoscale contributors) * [x] Changelog updated (under *Unreleased* block, and add the Pull Request #number for each bit you add to the `CHANGELOG.md`) * [x] Testing ## Testing Covered by the e2e scenario above (requires API credentials, runs under `-tags=api`).
1 parent 2aa48ff commit efdc64c

29 files changed

Lines changed: 187 additions & 26 deletions

.github/workflows/e2e.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,4 +44,4 @@ jobs:
4444
EXOSCALE_ZONE: ch-gva-2
4545
run: |
4646
cd tests/e2e
47-
go test -v -tags=api -timeout 30m -run TestScriptsAPI
47+
go test -v -tags=api -timeout 30m -run TestScriptsAPI 2>&1

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@
77
- dbaas: add missing PostgreSQL configuration options (`shared-buffers-percentage`, `synchronous-replication`, `timescaledb-settings`, `variant`, `work-mem`) #808
88
- `exo compute eip list` now shows the description & the management type of the EIP #803
99
- sks: add `rotate-karpenter-credentials` command #797
10+
11+
### Improvements
12+
13+
- compute instance: enrich "not found" error with the zone searched and a hint to use -z #805
1014
- sks: add `active-nodepool-templates` command #797
1115
- new command `exo ai deployment instance-type` that allows showing what GPU is usable in which zone #809
1216

cmd/compute/instance/instance.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
package instance
22

33
import (
4+
"errors"
5+
"fmt"
6+
47
"github.com/exoscale/cli/cmd/compute"
8+
v3 "github.com/exoscale/egoscale/v3"
59
"github.com/spf13/cobra"
610
)
711

@@ -36,3 +40,21 @@ var instanceCmd = &cobra.Command{
3640
func init() {
3741
compute.ComputeCmd.AddCommand(instanceCmd)
3842
}
43+
44+
// findInstance looks up an instance by name or ID from a ListInstancesResponse
45+
// and enriches the "not found" error with the zone that was searched,
46+
// reminding the user to use -z to target a different zone.
47+
func findInstance(resp *v3.ListInstancesResponse, nameOrID, zone string) (v3.ListInstancesResponseInstances, error) {
48+
instance, err := resp.FindListInstancesResponseInstances(nameOrID)
49+
if err != nil {
50+
if errors.Is(err, v3.ErrNotFound) {
51+
return v3.ListInstancesResponseInstances{}, fmt.Errorf(
52+
"instance %q not found in zone %s\nHint: use -z <zone> to specify a different zone, or run 'exo compute instance list' to see instances across all zones",
53+
nameOrID,
54+
zone,
55+
)
56+
}
57+
return v3.ListInstancesResponseInstances{}, err
58+
}
59+
return instance, nil
60+
}

cmd/compute/instance/instance_console_url.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ func (c *instanceConsoleURLCmd) CmdRun(cmd *cobra.Command, _ []string) error {
6060
return err
6161
}
6262

63-
foundInstance, err := resp.FindListInstancesResponseInstances(c.Instance)
63+
foundInstance, err := findInstance(resp, c.Instance, string(c.Zone))
6464
if err != nil {
6565
return err
6666
}

cmd/compute/instance/instance_delete.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ func (c *instanceDeleteCmd) CmdRun(_ *cobra.Command, _ []string) error {
5454

5555
instanceToDelete := []v3.UUID{}
5656
for _, i := range c.Instances {
57-
instance, err := instances.FindListInstancesResponseInstances(i)
57+
instance, err := findInstance(instances, i, c.Zone)
5858
if err != nil {
5959
if !c.Force {
6060
return err

cmd/compute/instance/instance_elastic_ip_attach.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,9 @@ func (c *instanceEIPAttachCmd) CmdRun(_ *cobra.Command, _ []string) error {
5454
if err != nil {
5555
return err
5656
}
57-
instance, err := instancesList.FindListInstancesResponseInstances(c.Instance)
57+
instance, err := findInstance(instancesList, c.Instance, c.Zone)
5858
if err != nil {
59-
return fmt.Errorf("error retrieving Instance: %w", err)
59+
return err
6060
}
6161

6262
elasticIPs, err := client.ListElasticIPS(ctx)

cmd/compute/instance/instance_elastic_ip_detach.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ func (c *instanceEIPDetachCmd) CmdRun(_ *cobra.Command, _ []string) error {
5454
if err != nil {
5555
return err
5656
}
57-
instance, err := instancesList.FindListInstancesResponseInstances(c.Instance)
57+
instance, err := findInstance(instancesList, c.Instance, c.Zone)
5858
if err != nil {
5959
return fmt.Errorf("error retrieving Instance: %w", err)
6060
}

cmd/compute/instance/instance_enable_tpm.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ func (c *instanceEnableTPMCmd) CmdRun(_ *cobra.Command, _ []string) error {
4545
return err
4646
}
4747

48-
instance, err := resp.FindListInstancesResponseInstances(c.Instance)
48+
instance, err := findInstance(resp, c.Instance, string(c.Zone))
4949
if err != nil {
5050
return err
5151
}

cmd/compute/instance/instance_private_network_attach.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ func (c *instancePrivnetAttachCmd) CmdRun(_ *cobra.Command, _ []string) error {
5656
if err != nil {
5757
return err
5858
}
59-
instance, err := instances.FindListInstancesResponseInstances(c.Instance)
59+
instance, err := findInstance(instances, c.Instance, c.Zone)
6060
if err != nil {
6161
return err
6262
}

cmd/compute/instance/instance_private_network_detach.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ func (c *instancePrivnetDetachCmd) CmdRun(_ *cobra.Command, _ []string) error {
5454
if err != nil {
5555
return err
5656
}
57-
instance, err := instances.FindListInstancesResponseInstances(c.Instance)
57+
instance, err := findInstance(instances, c.Instance, c.Zone)
5858
if err != nil {
5959
return err
6060
}

0 commit comments

Comments
 (0)