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 }