Repository: vmware/govmomi (go)

Issue:
[BUG] vcsim does not answer govc find after deleting a resource pool which had a child resource pool
**Describe the bug**
A clear and concise description of what the bug is.

**To Reproduce**
Steps to reproduce the behavior:

1. `govc pool.create /DC0/host/DC0_C0/Resources/foo`
1. `govc pool.create /DC0/host/DC0_C0/Resources/foo/bar`
1. `govc find -l /DC0/host/DC0_C0/Resources`
1. `govc pool.destroy /DC0/host/DC0_C0/Resources/foo`
1. `govc find -l /DC0/host/DC0_C0/Resources`

govc command will be stuck forever and not return or exit.

**Expected behavior**
Find returns the list of still existing objects.

**Affected version**

```
❯ govc version
govc 0.36.2

❯ vcsim version
Build Version: 0.36.2
Build Commit: f2a87d75
Build Date: 2024-03-27T04:34:21Z
```

**Screenshots/Debug Output**
If applicable, add screenshots or debug output to help explain your problem.

**Additional context**

This command still works after `govc pool.destroy /DC0/host/DC0_C0/Resources/foo`:

```sh
❯ govc ls '/DC0/host/DC0_C0/Resources/*'
/DC0/host/DC0_C0/Resources/bar
```

The same happens when using `govc object.destroy`.

It does not happen for folders.

Pull request description:
fix: vcsim: re-parent children in ResourcePool.Destroy
Fixes #3396


Patch:
diff --git a/simulator/resource_pool.go b/simulator/resource_pool.go
index eeab93af..d34fa5b8 100644
--- a/simulator/resource_pool.go
+++ b/simulator/resource_pool.go
@@ -483,7 +483,11 @@ func (p *ResourcePool) DestroyTask(ctx *Context, req *types.Destroy_Task) soap.H
 			RemoveReference(&parent.ResourcePool, req.This)
 
 			// The grandchildren become children of the parent (rp)
-			parent.ResourcePool = append(parent.ResourcePool, p.ResourcePool.ResourcePool...)
+			for _, ref := range p.ResourcePool.ResourcePool {
+				child := ctx.Map.Get(ref).(*ResourcePool)
+				ctx.WithLock(child, func() { child.Parent = &parent.Self })
+				parent.ResourcePool = append(parent.ResourcePool, ref)
+			}
 		})
 
 		// And VMs move to the parent


Test patch:
diff --git a/govc/test/vcsim.bats b/govc/test/vcsim.bats
index 6f2f2f2f..3828fda5 100755
--- a/govc/test/vcsim.bats
+++ b/govc/test/vcsim.bats
@@ -239,6 +239,17 @@ EOF
   wait $pid
 }
 
+@test "vcsim issue #3396" {
+  vcsim_env
+
+  govc pool.create /DC0/host/DC0_C0/Resources/foo
+  govc pool.create /DC0/host/DC0_C0/Resources/foo/bar
+  govc find -l /DC0/host/DC0_C0/Resources
+  govc pool.destroy /DC0/host/DC0_C0/Resources/foo
+  # prior to the fix, "bar"'s Parent was still "foo", causing the following to hang
+  govc find -l /DC0/host/DC0_C0/Resources
+}
+
 @test "vcsim run container" {
   require_docker
 
diff --git a/simulator/finder_test.go b/simulator/finder_test.go
index 3a45121d..9e856c1d 100644
--- a/simulator/finder_test.go
+++ b/simulator/finder_test.go
@@ -26,6 +26,7 @@ import (
 	"github.com/vmware/govmomi"
 	"github.com/vmware/govmomi/find"
 	"github.com/vmware/govmomi/object"
+	"github.com/vmware/govmomi/vim25"
 	"github.com/vmware/govmomi/vim25/types"
 )
 
@@ -273,3 +274,36 @@ func TestFinderDefaultHostVPX(t *testing.T) {
 		t.Errorf("unexpected error type=%T", err)
 	}
 }
+
+func TestFinderDestroyedParentResourcePool(t *testing.T) {
+	Test(func(ctx context.Context, c *vim25.Client) {
+		finder := find.NewFinder(c)
+
+		rp, err := finder.ResourcePool(ctx, "/DC0/host/DC0_C0/Resources")
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		foo, err := rp.Create(ctx, "foo", types.DefaultResourceConfigSpec())
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		bar, err := foo.Create(ctx, "bar", types.DefaultResourceConfigSpec())
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		task, err := foo.Destroy(ctx)
+		if err != nil {
+			t.Fatal(err)
+		}
+		if err := task.WaitEx(ctx); err != nil {
+			t.Fatal(err)
+		}
+
+		if _, err := finder.Element(ctx, bar.Reference()); err != nil {
+			t.Fatal(err)
+		}
+	})
+}