146 lines
3.6 KiB
Go
146 lines
3.6 KiB
Go
|
/*
|
||
|
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||
|
|
||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
you may not use this file except in compliance with the License.
|
||
|
You may obtain a copy of the License at
|
||
|
|
||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||
|
|
||
|
Unless required by applicable law or agreed to in writing, software
|
||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
See the License for the specific language governing permissions and
|
||
|
limitations under the License.
|
||
|
*/
|
||
|
|
||
|
package object
|
||
|
|
||
|
import (
|
||
|
"bufio"
|
||
|
"bytes"
|
||
|
"context"
|
||
|
"fmt"
|
||
|
"io"
|
||
|
"log"
|
||
|
"path"
|
||
|
"strings"
|
||
|
|
||
|
"github.com/vmware/govmomi/vim25/soap"
|
||
|
)
|
||
|
|
||
|
// DatastoreFileManager combines FileManager and VirtualDiskManager to manage files on a Datastore
|
||
|
type DatastoreFileManager struct {
|
||
|
Datacenter *Datacenter
|
||
|
Datastore *Datastore
|
||
|
FileManager *FileManager
|
||
|
VirtualDiskManager *VirtualDiskManager
|
||
|
|
||
|
Force bool
|
||
|
}
|
||
|
|
||
|
// NewFileManager creates a new instance of DatastoreFileManager
|
||
|
func (d Datastore) NewFileManager(dc *Datacenter, force bool) *DatastoreFileManager {
|
||
|
c := d.Client()
|
||
|
|
||
|
m := &DatastoreFileManager{
|
||
|
Datacenter: dc,
|
||
|
Datastore: &d,
|
||
|
FileManager: NewFileManager(c),
|
||
|
VirtualDiskManager: NewVirtualDiskManager(c),
|
||
|
Force: force,
|
||
|
}
|
||
|
|
||
|
return m
|
||
|
}
|
||
|
|
||
|
// Delete dispatches to the appropriate Delete method based on file name extension
|
||
|
func (m *DatastoreFileManager) Delete(ctx context.Context, name string) error {
|
||
|
switch path.Ext(name) {
|
||
|
case ".vmdk":
|
||
|
return m.DeleteVirtualDisk(ctx, name)
|
||
|
default:
|
||
|
return m.DeleteFile(ctx, name)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// DeleteFile calls FileManager.DeleteDatastoreFile
|
||
|
func (m *DatastoreFileManager) DeleteFile(ctx context.Context, name string) error {
|
||
|
p := m.Path(name)
|
||
|
|
||
|
task, err := m.FileManager.DeleteDatastoreFile(ctx, p.String(), m.Datacenter)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
return task.Wait(ctx)
|
||
|
}
|
||
|
|
||
|
// DeleteVirtualDisk calls VirtualDiskManager.DeleteVirtualDisk
|
||
|
// Regardless of the Datastore type, DeleteVirtualDisk will fail if 'ddb.deletable=false',
|
||
|
// so if Force=true this method attempts to set 'ddb.deletable=true' before starting the delete task.
|
||
|
func (m *DatastoreFileManager) DeleteVirtualDisk(ctx context.Context, name string) error {
|
||
|
p := m.Path(name)
|
||
|
|
||
|
var merr error
|
||
|
|
||
|
if m.Force {
|
||
|
merr = m.markDiskAsDeletable(ctx, p)
|
||
|
}
|
||
|
|
||
|
task, err := m.VirtualDiskManager.DeleteVirtualDisk(ctx, p.String(), m.Datacenter)
|
||
|
if err != nil {
|
||
|
log.Printf("markDiskAsDeletable(%s): %s", p, merr)
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
return task.Wait(ctx)
|
||
|
}
|
||
|
|
||
|
// Path converts path name to a DatastorePath
|
||
|
func (m *DatastoreFileManager) Path(name string) *DatastorePath {
|
||
|
var p DatastorePath
|
||
|
|
||
|
if !p.FromString(name) {
|
||
|
p.Path = name
|
||
|
p.Datastore = m.Datastore.Name()
|
||
|
}
|
||
|
|
||
|
return &p
|
||
|
}
|
||
|
|
||
|
func (m *DatastoreFileManager) markDiskAsDeletable(ctx context.Context, path *DatastorePath) error {
|
||
|
r, _, err := m.Datastore.Download(ctx, path.Path, &soap.DefaultDownload)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
defer r.Close()
|
||
|
|
||
|
hasFlag := false
|
||
|
buf := new(bytes.Buffer)
|
||
|
|
||
|
s := bufio.NewScanner(&io.LimitedReader{R: r, N: 2048}) // should be only a few hundred bytes, limit to be sure
|
||
|
|
||
|
for s.Scan() {
|
||
|
line := s.Text()
|
||
|
if strings.HasPrefix(line, "ddb.deletable") {
|
||
|
hasFlag = true
|
||
|
continue
|
||
|
}
|
||
|
|
||
|
fmt.Fprintln(buf, line)
|
||
|
}
|
||
|
|
||
|
if err := s.Err(); err != nil {
|
||
|
return err // any error other than EOF
|
||
|
}
|
||
|
|
||
|
if !hasFlag {
|
||
|
return nil // already deletable, so leave as-is
|
||
|
}
|
||
|
|
||
|
// rewrite the .vmdk with ddb.deletable flag removed (the default is true)
|
||
|
return m.Datastore.Upload(ctx, buf, path.Path, &soap.DefaultUpload)
|
||
|
}
|