Skip to content

Commit e92db04

Browse files
committed
vcsim: Fix NFS datastore moid collision
Closes: #2767 Signed-off-by: syuparn <[email protected]>
1 parent a416445 commit e92db04

File tree

3 files changed

+100
-14
lines changed

3 files changed

+100
-14
lines changed

simulator/host_datastore_system.go

Lines changed: 35 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -60,11 +60,23 @@ func (dss *HostDatastoreSystem) add(ctx *Context, ds *Datastore) *soap.Fault {
6060
}
6161

6262
folder := ctx.Map.getEntityFolder(dss.Host, "datastore")
63-
ds.Self.Type = typeName(ds)
64-
// Datastore is the only type where create methods do not include the parent (Folder in this case),
65-
// but we need the moref to be unique per DC/datastoreFolder, but not per-HostSystem.
66-
ds.Self.Value += "@" + folder.Self.Value
67-
// TODO: name should be made unique in the case of Local ds type
63+
64+
found := false
65+
if e := ctx.Map.FindByName(ds.Name, folder.ChildEntity); e != nil {
66+
if e.Reference().Type != "Datastore" {
67+
return Fault(e.Reference().Value, &types.DuplicateName{
68+
Name: ds.Name,
69+
Object: e.Reference(),
70+
})
71+
}
72+
73+
// if datastore already exists, use current reference
74+
found = true
75+
ds.Self = e.Reference()
76+
} else {
77+
// put datastore to folder and generate reference
78+
folderPutChild(ctx, folder, ds)
79+
}
6880

6981
ds.Summary.Datastore = &ds.Self
7082
ds.Summary.Name = ds.Name
@@ -84,7 +96,8 @@ func (dss *HostDatastoreSystem) add(ctx *Context, ds *Datastore) *soap.Fault {
8496
parent := hostParent(dss.Host)
8597
ctx.Map.AddReference(ctx, parent, &parent.Datastore, ds.Self)
8698

87-
if ctx.Map.Get(ds.Self) == nil {
99+
// NOTE: browser must be created after ds is appended to dss.Datastore
100+
if !found {
88101
browser := &HostDatastoreBrowser{}
89102
browser.Datastore = dss.Datastore
90103
ds.Browser = ctx.Map.Put(browser).Reference()
@@ -95,8 +108,6 @@ func (dss *HostDatastoreSystem) add(ctx *Context, ds *Datastore) *soap.Fault {
95108
info.FreeSpace = ds.Summary.FreeSpace
96109
info.MaxMemoryFileSize = ds.Summary.Capacity
97110
info.MaxFileSize = ds.Summary.Capacity
98-
99-
folderPutChild(ctx, folder, ds)
100111
}
101112

102113
return nil
@@ -107,7 +118,6 @@ func (dss *HostDatastoreSystem) CreateLocalDatastore(ctx *Context, c *types.Crea
107118

108119
ds := &Datastore{}
109120
ds.Name = c.Name
110-
ds.Self.Value = c.Path
111121

112122
ds.Info = &types.LocalDatastoreInfo{
113123
DatastoreInfo: types.DatastoreInfo{
@@ -147,9 +157,24 @@ func (dss *HostDatastoreSystem) CreateLocalDatastore(ctx *Context, c *types.Crea
147157
func (dss *HostDatastoreSystem) CreateNasDatastore(ctx *Context, c *types.CreateNasDatastore) soap.HasFault {
148158
r := &methods.CreateNasDatastoreBody{}
149159

160+
// validate RemoteHost and RemotePath are specified
161+
if c.Spec.RemoteHost == "" {
162+
r.Fault_ = Fault(
163+
"A specified parameter was not correct: Spec.RemoteHost",
164+
&types.InvalidArgument{InvalidProperty: "RemoteHost"},
165+
)
166+
return r
167+
}
168+
if c.Spec.RemotePath == "" {
169+
r.Fault_ = Fault(
170+
"A specified parameter was not correct: Spec.RemotePath",
171+
&types.InvalidArgument{InvalidProperty: "RemotePath"},
172+
)
173+
return r
174+
}
175+
150176
ds := &Datastore{}
151177
ds.Name = path.Base(c.Spec.LocalPath)
152-
ds.Self.Value = c.Spec.RemoteHost + ":" + c.Spec.RemotePath
153178

154179
ds.Info = &types.NasDatastoreInfo{
155180
DatastoreInfo: types.DatastoreInfo{

simulator/host_datastore_system_test.go

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,3 +98,61 @@ func TestHostDatastoreSystem(t *testing.T) {
9898
}
9999
}
100100
}
101+
102+
func TestCreateNasDatastoreValidation(t *testing.T) {
103+
s := New(NewServiceInstance(SpoofContext(), esx.ServiceContent, esx.RootFolder))
104+
105+
ts := s.NewServer()
106+
defer ts.Close()
107+
108+
ctx := context.Background()
109+
110+
c, err := govmomi.NewClient(ctx, ts.URL, true)
111+
if err != nil {
112+
t.Fatal(err)
113+
}
114+
115+
host := object.NewHostSystem(c.Client, esx.HostSystem.Reference())
116+
117+
dss, err := host.ConfigManager().DatastoreSystem(ctx)
118+
if err != nil {
119+
t.Error(err)
120+
}
121+
122+
pwd, err := os.Getwd()
123+
if err != nil {
124+
t.Fatal(err)
125+
}
126+
127+
tests := []struct {
128+
name string
129+
spec types.HostNasVolumeSpec
130+
}{
131+
{
132+
"RemotePath is not specified",
133+
types.HostNasVolumeSpec{
134+
Type: string(types.HostFileSystemVolumeFileSystemTypeNFS),
135+
LocalPath: pwd,
136+
RemoteHost: "localhost",
137+
},
138+
},
139+
{
140+
"RemoteHost is not specified",
141+
types.HostNasVolumeSpec{
142+
Type: string(types.HostFileSystemVolumeFileSystemTypeNFS),
143+
LocalPath: pwd,
144+
RemotePath: pwd,
145+
},
146+
},
147+
}
148+
149+
for _, tt := range tests {
150+
t.Run(tt.name, func(t *testing.T) {
151+
_, err := dss.CreateNasDatastore(ctx, tt.spec)
152+
153+
if err == nil {
154+
t.Error("expected error")
155+
}
156+
})
157+
}
158+
}

vapi/simulator/simulator.go

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1523,10 +1523,13 @@ func (s *handler) updateFileInfo(id string) *update {
15231523

15241524
// libraryPath returns the local Datastore fs path for a Library or Item if id is specified.
15251525
func libraryPath(l *library.Library, id string) string {
1526-
// DatastoreID (moref) format is "$local-path@$ds-folder-id",
1527-
// see simulator.HostDatastoreSystem.CreateLocalDatastore
1528-
ds := strings.SplitN(l.Storage[0].DatastoreID, "@", 2)[0]
1529-
return path.Join(append([]string{ds, "contentlib-" + l.ID}, id)...)
1526+
dsref := types.ManagedObjectReference{
1527+
Type: "Datastore",
1528+
Value: l.Storage[0].DatastoreID,
1529+
}
1530+
ds := simulator.Map.Get(dsref).(*simulator.Datastore)
1531+
1532+
return path.Join(append([]string{ds.Info.GetDatastoreInfo().Url, "contentlib-" + l.ID}, id)...)
15301533
}
15311534

15321535
func (s *handler) libraryItemFileCreate(up *update, name string, body io.ReadCloser) error {

0 commit comments

Comments
 (0)