@@ -18,12 +18,12 @@ package finder
18
18
19
19
import (
20
20
"context"
21
+ "errors"
21
22
"fmt"
22
23
"net/url"
23
24
"path"
24
25
"strings"
25
26
26
- "github.com/vmware/govmomi/internal"
27
27
"github.com/vmware/govmomi/object"
28
28
"github.com/vmware/govmomi/property"
29
29
"github.com/vmware/govmomi/vapi/library"
@@ -135,79 +135,126 @@ func (f *PathFinder) datastoreName(ctx context.Context, id string) (string, erro
135
135
return name , nil
136
136
}
137
137
138
- func (f * PathFinder ) convertPath (ctx context.Context , b * mo.Datastore , path string ) (string , error ) {
139
- if ! internal .IsDatastoreVSAN (* b ) {
138
+ func (f * PathFinder ) convertPath (
139
+ ctx context.Context ,
140
+ dc * object.Datacenter ,
141
+ ds mo.Datastore ,
142
+ path string ) (string , error ) {
143
+
144
+ if v := ds .Capability .TopLevelDirectoryCreateSupported ; v != nil && * v {
140
145
return path , nil
141
146
}
142
147
143
- var dc * object.Datacenter
144
-
145
- entities , err := mo .Ancestors (ctx , f .c , f .c .ServiceContent .PropertyCollector , b .Self )
146
- if err != nil {
147
- return "" , err
148
+ if dc == nil {
149
+ entities , err := mo .Ancestors (
150
+ ctx ,
151
+ f .c ,
152
+ f .c .ServiceContent .PropertyCollector ,
153
+ ds .Self )
154
+ if err != nil {
155
+ return "" , fmt .Errorf ("failed to find ancestors: %w" , err )
156
+ }
157
+ for _ , entity := range entities {
158
+ if entity .Self .Type == "Datacenter" {
159
+ dc = object .NewDatacenter (f .c , entity .Self )
160
+ break
161
+ }
162
+ }
148
163
}
149
164
150
- for _ , entity := range entities {
151
- if entity .Self .Type == "Datacenter" {
152
- dc = object .NewDatacenter (f .c , entity .Self )
153
- break
154
- }
165
+ if dc == nil {
166
+ return "" , errors .New ("failed to find datacenter" )
155
167
}
156
168
157
169
m := object .NewDatastoreNamespaceManager (f .c )
158
170
return m .ConvertNamespacePathToUuidPath (ctx , dc , path )
159
171
}
160
172
161
- // ResolveLibraryItemStorage transforms StorageURIs Datastore url (uuid) to Datastore name.
162
- func (f * PathFinder ) ResolveLibraryItemStorage (ctx context.Context , storage []library.Storage ) error {
173
+ // ResolveLibraryItemStorage transforms the StorageURIs field in the provided
174
+ // storage items from a datastore URL, ex.
175
+ // "ds:///vmfs/volumes/DATASTORE_UUID/contentlib-LIB_UUID/ITEM_UUID/file.vmdk",
176
+ // to the format that includes the datastore name, ex.
177
+ // "[DATASTORE_NAME] contentlib-LIB_UUID/ITEM_UUID/file.vmdk".
178
+ //
179
+ // If a storage item resides on a datastore that does not support the creation
180
+ // of top-level directories, then this means the datastore is vSAN and the
181
+ // storage item path needs to be further converted. If this occurs, then the
182
+ // datacenter to which the datastore belongs is required. If the datacenter
183
+ // parameter is non-nil, it is used, otherwise the datacenter for each datastore
184
+ // is resolved as needed. It is much more efficient to send in the datacenter if
185
+ // it is known ahead of time that the content library is stored on a vSAN
186
+ // datastore.
187
+ func (f * PathFinder ) ResolveLibraryItemStorage (
188
+ ctx context.Context ,
189
+ datacenter * object.Datacenter ,
190
+ storage []library.Storage ) error {
191
+
163
192
// TODO:
164
193
// - reuse PathFinder.cache
165
- // - the transform here isn't Content Library specific, but is currently the only known use case
166
- backing := map [string ]* mo.Datastore {}
167
- var ids []types.ManagedObjectReference
168
-
169
- // don't think we can have more than 1 Datastore backing currently, future proof anyhow
194
+ // - the transform here isn't Content Library specific, but is currently
195
+ // the only known use case
196
+ var (
197
+ ids []types.ManagedObjectReference
198
+ datastoreMap = map [string ]mo.Datastore {}
199
+ )
200
+
201
+ // Currently ContentLibrary only supports a single storage backing, but this
202
+ // future proofs things.
170
203
for _ , item := range storage {
171
204
id := item .StorageBacking .DatastoreID
172
- if _ , ok := backing [id ]; ok {
205
+ if _ , ok := datastoreMap [id ]; ok {
173
206
continue
174
207
}
175
- backing [id ] = nil
176
- ids = append (ids , types.ManagedObjectReference {Type : "Datastore" , Value : id })
208
+ datastoreMap [id ] = mo.Datastore {}
209
+ ids = append (
210
+ ids ,
211
+ types.ManagedObjectReference {Type : "Datastore" , Value : id })
177
212
}
178
213
179
- var ds []mo.Datastore
180
- pc := property .DefaultCollector (f .c )
181
- props := []string {"name" , "summary.url" , "summary.type" }
182
- if err := pc .Retrieve (ctx , ids , props , & ds ); err != nil {
214
+ var (
215
+ datastores []mo.Datastore
216
+ pc = property .DefaultCollector (f .c )
217
+ props = []string {
218
+ "name" ,
219
+ "summary.url" ,
220
+ "capability.topLevelDirectoryCreateSupported" ,
221
+ }
222
+ )
223
+
224
+ if err := pc .Retrieve (ctx , ids , props , & datastores ); err != nil {
183
225
return err
184
226
}
185
227
186
- for i := range ds {
187
- backing [ ds [i ].Self .Value ] = & ds [i ]
228
+ for i := range datastores {
229
+ datastoreMap [ datastores [i ].Self .Value ] = datastores [i ]
188
230
}
189
231
190
232
for _ , item := range storage {
191
- b := backing [item .StorageBacking .DatastoreID ]
192
- dsurl := b .Summary .Url
233
+ ds := datastoreMap [item .StorageBacking .DatastoreID ]
234
+ dsURL := ds .Summary .Url
193
235
194
236
for i := range item .StorageURIs {
195
- uri , err := url .Parse (item .StorageURIs [i ])
237
+ szURI := item .StorageURIs [i ]
238
+ uri , err := url .Parse (szURI )
196
239
if err != nil {
197
- return err
240
+ return fmt .Errorf (
241
+ "failed to parse storage URI %q: %w" , szURI , err )
198
242
}
243
+
199
244
uri .OmitHost = false // `ds://` required for ConvertNamespacePathToUuidPath()
200
245
uri .Path = path .Clean (uri .Path ) // required for ConvertNamespacePathToUuidPath()
201
246
uri .RawQuery = ""
202
- u , err := f .convertPath (ctx , b , uri .String ())
247
+
248
+ uriPath := uri .String ()
249
+ u , err := f .convertPath (ctx , datacenter , ds , uriPath )
203
250
if err != nil {
204
- return err
251
+ return fmt . Errorf ( "failed to convert path %q: %w" , uriPath , err )
205
252
}
206
- u = strings .TrimPrefix (u , dsurl )
253
+ u = strings .TrimPrefix (u , dsURL )
207
254
u = strings .TrimPrefix (u , "/" )
208
255
209
256
item .StorageURIs [i ] = (& object.DatastorePath {
210
- Datastore : b .Name ,
257
+ Datastore : ds .Name ,
211
258
Path : u ,
212
259
}).String ()
213
260
}
0 commit comments