github.com/vmware/govmomi@v0.51.0/simulator/file_manager.go (about) 1 // © Broadcom. All Rights Reserved. 2 // The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. 3 // SPDX-License-Identifier: Apache-2.0 4 5 package simulator 6 7 import ( 8 "io" 9 "os" 10 "path/filepath" 11 12 "github.com/vmware/govmomi/simulator/esx" 13 "github.com/vmware/govmomi/vim25/methods" 14 "github.com/vmware/govmomi/vim25/mo" 15 "github.com/vmware/govmomi/vim25/soap" 16 "github.com/vmware/govmomi/vim25/types" 17 "github.com/vmware/govmomi/vmdk" 18 ) 19 20 type FileManager struct { 21 mo.FileManager 22 } 23 24 func (f *FileManager) findDatastore(ctx *Context, ref mo.Reference, name string) (*Datastore, types.BaseMethodFault) { 25 var refs []types.ManagedObjectReference 26 27 if d, ok := asFolderMO(ref); ok { 28 refs = d.ChildEntity 29 } 30 if p, ok := ref.(*StoragePod); ok { 31 refs = p.ChildEntity 32 } 33 34 for _, ref := range refs { 35 obj := ctx.Map.Get(ref) 36 37 if ds, ok := obj.(*Datastore); ok && ds.Name == name { 38 return ds, nil 39 } 40 if p, ok := obj.(*StoragePod); ok { 41 ds, _ := f.findDatastore(ctx, p, name) 42 if ds != nil { 43 return ds, nil 44 } 45 } 46 if d, ok := asFolderMO(obj); ok { 47 ds, _ := f.findDatastore(ctx, d, name) 48 if ds != nil { 49 return ds, nil 50 } 51 } 52 } 53 54 return nil, &types.InvalidDatastore{Name: name} 55 } 56 57 func (f *FileManager) resolve(ctx *Context, dc *types.ManagedObjectReference, name string, remove ...bool) (string, types.BaseMethodFault) { 58 p, fault := parseDatastorePath(name) 59 if fault != nil { 60 return "", fault 61 } 62 63 if dc == nil { 64 if ctx.Map.IsESX() { 65 dc = &esx.Datacenter.Self 66 } else { 67 return "", &types.InvalidArgument{InvalidProperty: "dc"} 68 } 69 } 70 71 folder := ctx.Map.Get(*dc).(*Datacenter).DatastoreFolder 72 73 ds, fault := f.findDatastore(ctx, ctx.Map.Get(folder), p.Datastore) 74 if fault != nil { 75 return "", fault 76 } 77 78 return ds.resolve(ctx, p.Path, remove...), nil 79 } 80 81 func (f *FileManager) fault(name string, err error, fault types.BaseFileFault) types.BaseMethodFault { 82 switch { 83 case os.IsNotExist(err): 84 fault = new(types.FileNotFound) 85 case os.IsExist(err): 86 fault = new(types.FileAlreadyExists) 87 } 88 89 fault.GetFileFault().File = name 90 91 return fault.(types.BaseMethodFault) 92 } 93 94 func (f *FileManager) deleteDatastoreFile(ctx *Context, req *types.DeleteDatastoreFile_Task) types.BaseMethodFault { 95 file, fault := f.resolve(ctx, req.Datacenter, req.Name, true) 96 if fault != nil { 97 return fault 98 } 99 100 _, err := os.Stat(file) 101 if err != nil { 102 if os.IsNotExist(err) { 103 return f.fault(file, err, new(types.CannotDeleteFile)) 104 } 105 } 106 107 err = os.RemoveAll(file) 108 if err != nil { 109 return f.fault(file, err, new(types.CannotDeleteFile)) 110 } 111 112 return nil 113 } 114 115 func (f *FileManager) DiskDescriptor(ctx *Context, dc *types.ManagedObjectReference, name string) (*vmdk.Descriptor, string, types.BaseMethodFault) { 116 path, fault := f.resolve(ctx, dc, name) 117 if fault != nil { 118 return nil, "", fault 119 } 120 121 file, err := os.Open(path) 122 if err != nil { 123 return nil, "", f.fault(name, err, new(types.FileFault)) 124 } 125 126 defer file.Close() 127 128 desc, err := vmdk.ParseDescriptor(file) 129 if err != nil { 130 return nil, "", f.fault(name, err, new(types.FileFault)) 131 } 132 133 return desc, path, nil 134 } 135 136 func (f *FileManager) SaveDiskDescriptor(ctx *Context, desc *vmdk.Descriptor, path string) types.BaseMethodFault { 137 file, err := os.Create(path) 138 if err != nil { 139 return f.fault(path, err, new(types.FileFault)) 140 } 141 142 if err = desc.Write(file); err != nil { 143 _ = file.Close() 144 return f.fault(path, err, new(types.FileFault)) 145 } 146 147 if err = file.Close(); err != nil { 148 return f.fault(path, err, new(types.FileFault)) 149 } 150 151 return nil 152 } 153 154 func (f *FileManager) DeleteDatastoreFileTask(ctx *Context, req *types.DeleteDatastoreFile_Task) soap.HasFault { 155 task := CreateTask(f, "deleteDatastoreFile", func(*Task) (types.AnyType, types.BaseMethodFault) { 156 return nil, f.deleteDatastoreFile(ctx, req) 157 }) 158 159 return &methods.DeleteDatastoreFile_TaskBody{ 160 Res: &types.DeleteDatastoreFile_TaskResponse{ 161 Returnval: task.Run(ctx), 162 }, 163 } 164 } 165 166 func (f *FileManager) MakeDirectory(ctx *Context, req *types.MakeDirectory) soap.HasFault { 167 body := &methods.MakeDirectoryBody{} 168 169 name, fault := f.resolve(ctx, req.Datacenter, req.Name) 170 if fault != nil { 171 body.Fault_ = Fault("", fault) 172 return body 173 } 174 175 mkdir := os.Mkdir 176 177 if isTrue(req.CreateParentDirectories) { 178 mkdir = os.MkdirAll 179 } 180 181 err := mkdir(name, 0700) 182 if err != nil { 183 fault = f.fault(req.Name, err, new(types.CannotCreateFile)) 184 body.Fault_ = Fault(err.Error(), fault) 185 return body 186 } 187 188 body.Res = new(types.MakeDirectoryResponse) 189 return body 190 } 191 192 func (f *FileManager) moveDatastoreFile(ctx *Context, req *types.MoveDatastoreFile_Task) types.BaseMethodFault { 193 src, fault := f.resolve(ctx, req.SourceDatacenter, req.SourceName) 194 if fault != nil { 195 return fault 196 } 197 198 dst, fault := f.resolve(ctx, req.DestinationDatacenter, req.DestinationName) 199 if fault != nil { 200 return fault 201 } 202 203 if !isTrue(req.Force) { 204 _, err := os.Stat(dst) 205 if err == nil { 206 return f.fault(dst, nil, new(types.FileAlreadyExists)) 207 } 208 } 209 210 err := os.Rename(src, dst) 211 if err != nil { 212 return f.fault(src, err, new(types.CannotAccessFile)) 213 } 214 215 return nil 216 } 217 218 func (f *FileManager) MoveDatastoreFileTask(ctx *Context, req *types.MoveDatastoreFile_Task) soap.HasFault { 219 task := CreateTask(f, "moveDatastoreFile", func(*Task) (types.AnyType, types.BaseMethodFault) { 220 return nil, f.moveDatastoreFile(ctx, req) 221 }) 222 223 return &methods.MoveDatastoreFile_TaskBody{ 224 Res: &types.MoveDatastoreFile_TaskResponse{ 225 Returnval: task.Run(ctx), 226 }, 227 } 228 } 229 230 func (f *FileManager) copyDatastoreFile(ctx *Context, req *types.CopyDatastoreFile_Task) types.BaseMethodFault { 231 src, fault := f.resolve(ctx, req.SourceDatacenter, req.SourceName) 232 if fault != nil { 233 return fault 234 } 235 236 dst, fault := f.resolve(ctx, req.DestinationDatacenter, req.DestinationName) 237 if fault != nil { 238 return fault 239 } 240 241 if !isTrue(req.Force) { 242 _, err := os.Stat(dst) 243 if err == nil { 244 return f.fault(dst, nil, new(types.FileAlreadyExists)) 245 } 246 } 247 248 r, err := os.Open(filepath.Clean(src)) 249 if err != nil { 250 return f.fault(dst, err, new(types.CannotAccessFile)) 251 } 252 defer r.Close() 253 254 w, err := os.Create(dst) 255 if err != nil { 256 return f.fault(dst, err, new(types.CannotCreateFile)) 257 } 258 defer w.Close() 259 260 if _, err = io.Copy(w, r); err != nil { 261 return f.fault(dst, err, new(types.CannotCreateFile)) 262 } 263 264 return nil 265 } 266 267 func (f *FileManager) CopyDatastoreFileTask(ctx *Context, req *types.CopyDatastoreFile_Task) soap.HasFault { 268 task := CreateTask(f, "copyDatastoreFile", func(*Task) (types.AnyType, types.BaseMethodFault) { 269 return nil, f.copyDatastoreFile(ctx, req) 270 }) 271 272 return &methods.CopyDatastoreFile_TaskBody{ 273 Res: &types.CopyDatastoreFile_TaskResponse{ 274 Returnval: task.Run(ctx), 275 }, 276 } 277 }