diff --git a/object/namespace_manager_test.go b/object/namespace_manager_test.go new file mode 100644 index 000000000..a9a3eee54 --- /dev/null +++ b/object/namespace_manager_test.go @@ -0,0 +1,61 @@ +// © Broadcom. All Rights Reserved. +// The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. +// SPDX-License-Identifier: Apache-2.0 + +package object_test + +import ( + "context" + "testing" + + "github.com/vmware/govmomi/fault" + "github.com/vmware/govmomi/find" + "github.com/vmware/govmomi/object" + "github.com/vmware/govmomi/simulator" + "github.com/vmware/govmomi/vim25" + "github.com/vmware/govmomi/vim25/types" +) + +func TestDatastoreNamespaceManager(t *testing.T) { + simulator.Test(func(ctx context.Context, c *vim25.Client) { + m := object.NewDatastoreNamespaceManager(c) + + finder := find.NewFinder(c) + dc, err := finder.DefaultDatacenter(ctx) + if err != nil { + t.Fatal(err) + } + + ds, err := finder.DefaultDatastore(ctx) + if err != nil { + t.Fatal(err) + } + + store := simulator.Map.Get(ds.Reference()).(*simulator.Datastore) + + name := "foo" + + dir, err := m.CreateDirectory(ctx, ds, name, "") + if !fault.Is(err, &types.CannotCreateFile{}) { + t.Errorf("err=%v", err) + } + + store.Summary.Type = string(types.HostFileSystemVolumeFileSystemTypeVsan) + store.Capability.TopLevelDirectoryCreateSupported = types.NewBool(true) + + dir, err = m.CreateDirectory(ctx, ds, name, "") + if err != nil { + t.Errorf("err=%v", err) + } + + err = m.DeleteDirectory(ctx, dc, name) + if !fault.Is(err, &types.InvalidDatastorePath{}) { + t.Errorf("err=%v", err) + } + + err = m.DeleteDirectory(ctx, dc, dir) + if err != nil { + t.Errorf("delete %s, err=%v", dir, err) + } + }) +} diff --git a/simulator/datastore_namespace_manager.go b/simulator/datastore_namespace_manager.go index 2c642896b..a230737c8 100644 --- a/simulator/datastore_namespace_manager.go +++ b/simulator/datastore_namespace_manager.go @@ -1,25 +1,15 @@ -/* -Copyright (c) 2024-2024 VMware, Inc. All Rights Reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ +// © Broadcom. All Rights Reserved. +// The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. +// SPDX-License-Identifier: Apache-2.0 package simulator import ( + "path" "strings" "github.com/vmware/govmomi/internal" + "github.com/vmware/govmomi/object" "github.com/vmware/govmomi/vim25/methods" "github.com/vmware/govmomi/vim25/mo" "github.com/vmware/govmomi/vim25/soap" @@ -38,7 +28,11 @@ func (m *DatastoreNamespaceManager) ConvertNamespacePathToUuidPath(ctx *Context, return body } - dc := ctx.Map.Get(*req.Datacenter).(*Datacenter) + dc, ok := ctx.Map.Get(*req.Datacenter).(*Datacenter) + if !ok { + body.Fault_ = Fault("", &types.ManagedObjectNotFound{Obj: *req.Datacenter}) + return body + } var ds *Datastore for _, ref := range dc.Datastore { @@ -65,3 +59,116 @@ func (m *DatastoreNamespaceManager) ConvertNamespacePathToUuidPath(ctx *Context, return body } + +func (m *DatastoreNamespaceManager) CreateDirectory(ctx *Context, req *types.CreateDirectory) soap.HasFault { + body := new(methods.CreateDirectoryBody) + + ds, ok := ctx.Map.Get(req.Datastore).(*Datastore) + if !ok { + body.Fault_ = Fault("", &types.ManagedObjectNotFound{Obj: req.Datastore}) + return body + } + + if !internal.IsDatastoreVSAN(ds.Datastore) { + body.Fault_ = Fault("", &types.CannotCreateFile{ + FileFault: types.FileFault{ + File: "Datastore not supported for directory creation by DatastoreNamespaceManager", + }, + }) + return body + } + + if !isValidFileName(req.DisplayName) { + body.Fault_ = Fault("", &types.InvalidDatastorePath{DatastorePath: req.DisplayName}) + return body + } + + p := object.DatastorePath{ + Datastore: ds.Name, + Path: req.DisplayName, + } + + dc := ctx.Map.getEntityDatacenter(ds) + + fm := ctx.Map.FileManager() + + fault := fm.MakeDirectory(&types.MakeDirectory{ + This: fm.Self, + Name: p.String(), + Datacenter: &dc.Self, + }) + + if fault.Fault() != nil { + body.Fault_ = fault.Fault() + } else { + dir := ds.Info.GetDatastoreInfo().Url + + body.Res = &types.CreateDirectoryResponse{ + Returnval: path.Join(dir, req.DisplayName), + } + } + + return body +} + +func (m *DatastoreNamespaceManager) DeleteDirectory(ctx *Context, req *types.DeleteDirectory) soap.HasFault { + body := new(methods.DeleteDirectoryBody) + + if req.Datacenter == nil { + body.Fault_ = Fault("", &types.InvalidArgument{InvalidProperty: "datacenterRef"}) + return body + } + + dc, ok := ctx.Map.Get(*req.Datacenter).(*Datacenter) + if !ok { + body.Fault_ = Fault("", &types.ManagedObjectNotFound{Obj: *req.Datacenter}) + return body + } + + var ds *Datastore + for _, ref := range dc.Datastore { + ds = ctx.Map.Get(ref).(*Datastore) + if strings.HasPrefix(req.DatastorePath, ds.Summary.Url) { + break + } + ds = nil + } + + if ds == nil || strings.Contains(req.DatastorePath, "..") { + body.Fault_ = Fault("", &types.InvalidDatastorePath{DatastorePath: req.DatastorePath}) + return body + } + + if !internal.IsDatastoreVSAN(ds.Datastore) { + body.Fault_ = Fault("", &types.FileFault{ + File: "Datastore not supported for directory deletion by DatastoreNamespaceManager", + }) + return body + } + + name := &object.DatastorePath{ + Datastore: ds.Name, + Path: path.Base(req.DatastorePath), + } + + fm := ctx.Map.FileManager() + + fault := fm.deleteDatastoreFile(&types.DeleteDatastoreFile_Task{ + Name: name.String(), + Datacenter: req.Datacenter, + }) + + if fault != nil { + body.Fault_ = Fault("", fault) + } else { + body.Res = new(types.DeleteDirectoryResponse) + } + + return body +} + +func isValidFileName(s string) bool { + return !strings.Contains(s, "/") && + !strings.Contains(s, "\\") && + !strings.Contains(s, "..") +} diff --git a/simulator/esx/datacenter.go b/simulator/esx/datacenter.go index 374cd9518..412c4c291 100644 --- a/simulator/esx/datacenter.go +++ b/simulator/esx/datacenter.go @@ -1,18 +1,6 @@ -/* -Copyright (c) 2017-2023 VMware, Inc. All Rights Reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ +// © Broadcom. All Rights Reserved. +// The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. +// SPDX-License-Identifier: Apache-2.0 package esx @@ -50,9 +38,7 @@ var Datacenter = mo.Datacenter{ HostFolder: types.ManagedObjectReference{Type: "Folder", Value: "ha-folder-host"}, DatastoreFolder: types.ManagedObjectReference{Type: "Folder", Value: "ha-folder-datastore"}, NetworkFolder: types.ManagedObjectReference{Type: "Folder", Value: "ha-folder-network"}, - Datastore: []types.ManagedObjectReference{ - {Type: "Datastore", Value: "57089c25-85e3ccd4-17b6-000c29d0beb3"}, - }, + Datastore: nil, Network: []types.ManagedObjectReference{ {Type: "Network", Value: "HaNetwork-VM Network"}, },