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  }