github.com/vmware/govmomi@v0.51.0/simulator/datastore.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  	"net/url"
     9  	"os"
    10  	"path"
    11  	"strings"
    12  	"time"
    13  
    14  	"github.com/google/uuid"
    15  
    16  	"github.com/vmware/govmomi/internal"
    17  	"github.com/vmware/govmomi/object"
    18  	"github.com/vmware/govmomi/units"
    19  	"github.com/vmware/govmomi/vim25/methods"
    20  	"github.com/vmware/govmomi/vim25/mo"
    21  	"github.com/vmware/govmomi/vim25/soap"
    22  	"github.com/vmware/govmomi/vim25/types"
    23  )
    24  
    25  type Datastore struct {
    26  	mo.Datastore
    27  
    28  	namespace map[string]string // TODO: make thread safe
    29  }
    30  
    31  func (ds *Datastore) eventArgument() *types.DatastoreEventArgument {
    32  	return &types.DatastoreEventArgument{
    33  		Datastore:           ds.Self,
    34  		EntityEventArgument: types.EntityEventArgument{Name: ds.Name},
    35  	}
    36  }
    37  
    38  func (ds *Datastore) model(m *Model) error {
    39  	info := ds.Info.GetDatastoreInfo()
    40  	u, _ := url.Parse(info.Url)
    41  	if u.Scheme == "ds" {
    42  		// rewrite saved vmfs path to a local temp dir
    43  		u.Path = path.Clean(u.Path)
    44  		parent := strings.ReplaceAll(path.Dir(u.Path), "/", "_")
    45  		name := strings.ReplaceAll(path.Base(u.Path), ":", "_")
    46  
    47  		dir, err := m.createTempDir(parent, name)
    48  		if err != nil {
    49  			return err
    50  		}
    51  
    52  		info.Url = dir
    53  	} else {
    54  		// rewrite local path from a saved vcsim instance
    55  		dir, err := m.createTempDir(path.Base(u.Path))
    56  		if err != nil {
    57  			return err
    58  		}
    59  
    60  		info.Url = dir
    61  	}
    62  
    63  	ds.Summary.Url = info.Url
    64  
    65  	return nil
    66  }
    67  
    68  // resolve Datastore relative file path to absolute path.
    69  // vSAN top-level directories are named with its vSAN object uuid.
    70  // The directory uuid or friendlyName can be used the various FileManager,
    71  // VirtualDiskManager, etc. methods that have a Datastore path param.
    72  // Note that VirtualDevice file backing paths must use the vSAN uuid.
    73  func (ds *Datastore) resolve(ctx *Context, p string, remove ...bool) string {
    74  	if p == "" || !internal.IsDatastoreVSAN(ds.Datastore) {
    75  		return path.Join(ds.Summary.Url, p)
    76  	}
    77  
    78  	rm := len(remove) != 0 && remove[0]
    79  	unlock := ctx.Map.AcquireLock(ctx, ds.Self)
    80  	defer unlock()
    81  
    82  	if ds.namespace == nil {
    83  		ds.namespace = make(map[string]string)
    84  	}
    85  
    86  	elem := strings.Split(p, "/")
    87  	dir := elem[0]
    88  
    89  	_, err := uuid.Parse(dir)
    90  	if err != nil {
    91  		// Translate friendlyName to UUID
    92  		id, ok := ds.namespace[dir]
    93  		if !ok {
    94  			id = uuid.NewString()
    95  			ds.namespace[dir] = id
    96  		}
    97  
    98  		elem[0] = id
    99  		p = path.Join(elem...)
   100  		if rm {
   101  			delete(ds.namespace, id)
   102  		}
   103  	} else if rm {
   104  		// UUID was given
   105  		for name, id := range ds.namespace {
   106  			if p == id {
   107  				delete(ds.namespace, name)
   108  				break
   109  			}
   110  		}
   111  	}
   112  
   113  	return path.Join(ds.Summary.Url, p)
   114  }
   115  
   116  func parseDatastorePath(dsPath string) (*object.DatastorePath, types.BaseMethodFault) {
   117  	var p object.DatastorePath
   118  
   119  	if p.FromString(dsPath) {
   120  		return &p, nil
   121  	}
   122  
   123  	return nil, &types.InvalidDatastorePath{DatastorePath: dsPath}
   124  }
   125  
   126  func (ds *Datastore) RefreshDatastore(*Context, *types.RefreshDatastore) soap.HasFault {
   127  	r := &methods.RefreshDatastoreBody{}
   128  
   129  	_, err := os.Stat(ds.Info.GetDatastoreInfo().Url)
   130  	if err != nil {
   131  		r.Fault_ = Fault(err.Error(), &types.HostConfigFault{})
   132  		return r
   133  	}
   134  
   135  	ds.Summary.Capacity = int64(units.ByteSize(units.TB)) * int64(len(ds.Host))
   136  	ds.Summary.FreeSpace = ds.Summary.Capacity
   137  
   138  	info := ds.Info.GetDatastoreInfo()
   139  
   140  	info.FreeSpace = ds.Summary.FreeSpace
   141  	info.MaxMemoryFileSize = ds.Summary.Capacity
   142  	info.MaxFileSize = ds.Summary.Capacity
   143  	info.Timestamp = types.NewTime(time.Now())
   144  
   145  	r.Res = &types.RefreshDatastoreResponse{}
   146  	return r
   147  }
   148  
   149  func (ds *Datastore) DestroyTask(ctx *Context, req *types.Destroy_Task) soap.HasFault {
   150  	task := CreateTask(ds, "destroy", func(*Task) (types.AnyType, types.BaseMethodFault) {
   151  		if len(ds.Vm) != 0 {
   152  			return nil, &types.ResourceInUse{
   153  				Type: ds.Self.Type,
   154  				Name: ds.Name,
   155  			}
   156  		}
   157  
   158  		for _, mount := range ds.Host {
   159  			host := ctx.Map.Get(mount.Key).(*HostSystem)
   160  			ctx.Map.RemoveReference(ctx, host, &host.Datastore, ds.Self)
   161  			parent := hostParent(ctx, &host.HostSystem)
   162  			ctx.Map.RemoveReference(ctx, parent, &parent.Datastore, ds.Self)
   163  		}
   164  
   165  		p, _ := asFolderMO(ctx.Map.Get(*ds.Parent))
   166  		folderRemoveChild(ctx, p, ds.Self)
   167  
   168  		return nil, nil
   169  	})
   170  
   171  	return &methods.Destroy_TaskBody{
   172  		Res: &types.Destroy_TaskResponse{
   173  			Returnval: task.Run(ctx),
   174  		},
   175  	}
   176  }