From 1f914188efc08aeda4889e197866a02e3bdb0c7e Mon Sep 17 00:00:00 2001 From: Doug MacEachern Date: Thu, 19 Dec 2024 14:43:16 -0800 Subject: [PATCH] govc: add disk.ls '-a' flag Deleting an FCD file backing can create an orphan FCD. An orphaned ID is returned by the ListVStorageObject API, but calling RetrieveVStorageObject with an orphan ID results in a NotFound fault. The disk.ls command would return an error and suggest: use 'disk.ls -R' to reconcile datastore inventory The -R flag calls ReconcileDatastoreInventory, which normally cleans up such orphans, but we have seen cases where it does not. This change ignores orphans by default. The new '-a' flag will list *all* orphans (if any) and includes the disk.ls -R suggestion. Fixes #3639 Signed-off-by: Doug MacEachern --- cli/disk/ls.go | 15 ++++++++++++++- govc/USAGE.md | 1 + govc/test/disk.bats | 10 +++++++++- 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/cli/disk/ls.go b/cli/disk/ls.go index 1e9a94718..468d3c4e5 100644 --- a/cli/disk/ls.go +++ b/cli/disk/ls.go @@ -35,6 +35,7 @@ import ( type ls struct { *flags.DatastoreFlag + all bool long bool path bool r bool @@ -51,6 +52,7 @@ func (cmd *ls) Register(ctx context.Context, f *flag.FlagSet) { cmd.DatastoreFlag, ctx = flags.NewDatastoreFlag(ctx) cmd.DatastoreFlag.Register(ctx, f) + f.BoolVar(&cmd.all, "a", false, "List IDs with missing file backing") f.BoolVar(&cmd.long, "l", false, "Long listing format") f.BoolVar(&cmd.path, "L", false, "Print disk backing path instead of disk name") f.BoolVar(&cmd.r, "R", false, "Reconcile the datastore inventory info") @@ -167,7 +169,18 @@ func (cmd *ls) Run(ctx context.Context, f *flag.FlagSet) error { if err != nil { if filterNotFound && fault.Is(err, &types.NotFound{}) { // The case when an FCD is deleted by something other than DeleteVStorageObject_Task, such as VM destroy - return fmt.Errorf("%s not found: use 'disk.ls -R' to reconcile datastore inventory", id) + if cmd.all { + obj := VStorageObject{VStorageObject: types.VStorageObject{ + Config: types.VStorageObjectConfigInfo{ + BaseConfigInfo: types.BaseConfigInfo{ + Id: types.ID{Id: id}, + Name: "not found: use 'disk.ls -R' to reconcile datastore inventory", + }, + }, + }} + res.Objects = append(res.Objects, obj) + } + continue } return fmt.Errorf("retrieve %q: %s", id, err) } diff --git a/govc/USAGE.md b/govc/USAGE.md index db7e14632..9e195c61b 100644 --- a/govc/USAGE.md +++ b/govc/USAGE.md @@ -2150,6 +2150,7 @@ Options: -L=false Print disk backing path instead of disk name -R=false Reconcile the datastore inventory info -T=false List attached tags + -a=false List IDs with missing file backing -c= Query tag category -ds= Datastore [GOVC_DATASTORE] -l=false Long listing format diff --git a/govc/test/disk.bats b/govc/test/disk.bats index 530487867..6e7feca09 100755 --- a/govc/test/disk.bats +++ b/govc/test/disk.bats @@ -204,13 +204,21 @@ load test_helper run govc disk.ls assert_success + [ ${#lines[@]} -eq 2 ] path=$(govc disk.ls -json "$id" | jq -r .objects[].config.backing.filePath) run govc datastore.rm "$path" assert_success + # file backing was removed without using disk.rm, results in NotFound fault run govc disk.ls - assert_failure # file backing was removed without using disk.rm, results in NotFound fault + assert_success + [ ${#lines[@]} -eq 1 ] + + run govc disk.ls -a + assert_success + [ ${#lines[@]} -eq 2 ] + assert_matches "not found" run govc disk.ls -R assert_success