Repository: vmware/govmomi (go)

Issue:
govc: import.ova into datastore cluster
Hi All,

i would like to import an OVA file into a datastore cluster. So far i can only import into a datastore.

Is it plan to implement this feature or is it already implemented and i'm just too stupid to find it?

Kind regards

Pull request description:
govc: Support Datastore Cluster in import.ova command
Similar to ovftool, the -ds option can now be a Datastore Cluster. Datastore with the most free space is chosen.

Fixes #1265


Patch:
diff --git a/cli/importx/ovf.go b/cli/importx/ovf.go
index 7a7aa7f9..0db317a8 100644
--- a/cli/importx/ovf.go
+++ b/cli/importx/ovf.go
@@ -13,8 +13,11 @@ import (
 	"github.com/vmware/govmomi/cli"
 	"github.com/vmware/govmomi/cli/flags"
 	"github.com/vmware/govmomi/fault"
+	"github.com/vmware/govmomi/find"
 	"github.com/vmware/govmomi/object"
 	"github.com/vmware/govmomi/ovf/importer"
+	"github.com/vmware/govmomi/property"
+	"github.com/vmware/govmomi/vim25/mo"
 	"github.com/vmware/govmomi/vim25/types"
 )
 
@@ -164,7 +167,7 @@ func (cmd *ovfx) Prepare(f *flag.FlagSet) (string, error) {
 		return "", err
 	}
 
-	cmd.Importer.Datastore, err = cmd.DatastoreFlag.Datastore()
+	cmd.Importer.Datastore, err = cmd.datastore()
 	if err != nil {
 		return "", err
 	}
@@ -220,3 +223,59 @@ func (cmd *ovfx) Prepare(f *flag.FlagSet) (string, error) {
 
 	return f.Arg(0), nil
 }
+
+func (f *ovfx) datastore() (*object.Datastore, error) {
+	ctx := context.Background()
+
+	ds, err := f.Datastore()
+	if err == nil {
+		return ds, nil
+	}
+	if _, ok := err.(*find.NotFoundError); !ok {
+		return nil, err
+	}
+
+	finder, err := f.DatastoreFlag.Finder()
+	if err != nil {
+		return nil, err
+	}
+
+	pod, err := finder.DatastoreCluster(ctx, f.Name)
+	if err != nil {
+		return nil, err
+	}
+
+	var folder mo.Folder
+
+	err = pod.Properties(ctx, pod.Reference(), []string{"childEntity"}, &folder)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(folder.ChildEntity) == 0 {
+		return nil, fmt.Errorf("datastore cluster %q has no datastores", f.Name)
+	}
+
+	pc := property.DefaultCollector(pod.Client())
+
+	var stores []mo.Datastore
+
+	err = pc.Retrieve(ctx, folder.ChildEntity, []string{"info.freeSpace"}, &stores)
+	if err != nil {
+		return nil, err
+	}
+
+	// choose Datastore from DatastoreCluster (StoragePod) with the most free space
+	var ref types.ManagedObjectReference
+	var max int64
+
+	for _, ds := range stores {
+		space := ds.Info.GetDatastoreInfo().FreeSpace
+		if space > max {
+			max = space
+			ref = ds.Reference()
+		}
+	}
+
+	return object.NewDatastore(pod.Client(), ref), nil
+}


Test patch:
diff --git a/govc/test/import.bats b/govc/test/import.bats
index 43257718..ec3de521 100755
--- a/govc/test/import.bats
+++ b/govc/test/import.bats
@@ -271,3 +271,20 @@ load test_helper
   assert_equal ttylinux "$name"
   assert_equal 16.1 "$version"
 }
+
+@test "import datastore cluster" {
+  vcsim_env -pod 1 -ds 3
+
+  unset GOVC_DATASTORE
+
+  pod=DC0_POD0
+
+  run govc import.ova -ds $pod "$GOVC_IMAGES/$TTYLINUX_NAME.ova"
+  assert_failure # datastore cluster "DC0_POD0" has no datastores
+
+  run govc object.mv /DC0/datastore/LocalDS_* $pod
+  assert_success
+
+  run govc import.ova -ds $pod "$GOVC_IMAGES/$TTYLINUX_NAME.ova"
+  assert_success
+}