Skip to content

Commit

Permalink
Merge pull request #7952 from dagnello/vsphere-file-copy
Browse files Browse the repository at this point in the history
vSphere file resource: extending functionality to copy files in vSphere
  • Loading branch information
jen20 authored Aug 5, 2016
2 parents f3a06c0 + 895383a commit de822d9
Show file tree
Hide file tree
Showing 3 changed files with 308 additions and 49 deletions.
167 changes: 129 additions & 38 deletions builtin/providers/vsphere/resource_vsphere_file.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package vsphere
import (
"fmt"
"log"
"strings"

"github.com/hashicorp/terraform/helper/schema"
"github.com/vmware/govmomi"
Expand All @@ -13,10 +14,14 @@ import (
)

type file struct {
datacenter string
datastore string
sourceFile string
destinationFile string
sourceDatacenter string
datacenter string
sourceDatastore string
datastore string
sourceFile string
destinationFile string
createDirectories bool
copyFile bool
}

func resourceVSphereFile() *schema.Resource {
Expand All @@ -30,10 +35,20 @@ func resourceVSphereFile() *schema.Resource {
"datacenter": {
Type: schema.TypeString,
Optional: true,
},

"source_datacenter": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
},

"datastore": {
Type: schema.TypeString,
Required: true,
},

"source_datastore": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
Expand All @@ -49,6 +64,11 @@ func resourceVSphereFile() *schema.Resource {
Type: schema.TypeString,
Required: true,
},

"create_directories": {
Type: schema.TypeBool,
Optional: true,
},
},
}
}
Expand All @@ -60,10 +80,20 @@ func resourceVSphereFileCreate(d *schema.ResourceData, meta interface{}) error {

f := file{}

if v, ok := d.GetOk("source_datacenter"); ok {
f.sourceDatacenter = v.(string)
f.copyFile = true
}

if v, ok := d.GetOk("datacenter"); ok {
f.datacenter = v.(string)
}

if v, ok := d.GetOk("source_datastore"); ok {
f.sourceDatastore = v.(string)
f.copyFile = true
}

if v, ok := d.GetOk("datastore"); ok {
f.datastore = v.(string)
} else {
Expand All @@ -82,6 +112,10 @@ func resourceVSphereFileCreate(d *schema.ResourceData, meta interface{}) error {
return fmt.Errorf("destination_file argument is required")
}

if v, ok := d.GetOk("create_directories"); ok {
f.createDirectories = v.(bool)
}

err := createFile(client, &f)
if err != nil {
return err
Expand All @@ -108,16 +142,53 @@ func createFile(client *govmomi.Client, f *file) error {
return fmt.Errorf("error %s", err)
}

dsurl, err := ds.URL(context.TODO(), dc, f.destinationFile)
if err != nil {
return err
}
if f.copyFile {
// Copying file from withing vSphere
source_dc, err := finder.Datacenter(context.TODO(), f.sourceDatacenter)
if err != nil {
return fmt.Errorf("error %s", err)
}
finder = finder.SetDatacenter(dc)

p := soap.DefaultUpload
err = client.Client.UploadFile(f.sourceFile, dsurl, &p)
if err != nil {
return fmt.Errorf("error %s", err)
source_ds, err := getDatastore(finder, f.sourceDatastore)
if err != nil {
return fmt.Errorf("error %s", err)
}

fm := object.NewFileManager(client.Client)
if f.createDirectories {
directoryPathIndex := strings.LastIndex(f.destinationFile, "/")
path := f.destinationFile[0:directoryPathIndex]
err = fm.MakeDirectory(context.TODO(), ds.Path(path), dc, true)
if err != nil {
return fmt.Errorf("error %s", err)
}
}
task, err := fm.CopyDatastoreFile(context.TODO(), source_ds.Path(f.sourceFile), source_dc, ds.Path(f.destinationFile), dc, true)

if err != nil {
return fmt.Errorf("error %s", err)
}

_, err = task.WaitForResult(context.TODO(), nil)
if err != nil {
return fmt.Errorf("error %s", err)
}

} else {
// Uploading file to vSphere
dsurl, err := ds.URL(context.TODO(), dc, f.destinationFile)
if err != nil {
return fmt.Errorf("error %s", err)
}

p := soap.DefaultUpload
err = client.Client.UploadFile(f.sourceFile, dsurl, &p)
if err != nil {
return fmt.Errorf("error %s", err)
}
}

return nil
}

Expand All @@ -126,10 +197,18 @@ func resourceVSphereFileRead(d *schema.ResourceData, meta interface{}) error {
log.Printf("[DEBUG] reading file: %#v", d)
f := file{}

if v, ok := d.GetOk("source_datacenter"); ok {
f.sourceDatacenter = v.(string)
}

if v, ok := d.GetOk("datacenter"); ok {
f.datacenter = v.(string)
}

if v, ok := d.GetOk("source_datastore"); ok {
f.sourceDatastore = v.(string)
}

if v, ok := d.GetOk("datastore"); ok {
f.datastore = v.(string)
} else {
Expand Down Expand Up @@ -179,57 +258,69 @@ func resourceVSphereFileRead(d *schema.ResourceData, meta interface{}) error {
func resourceVSphereFileUpdate(d *schema.ResourceData, meta interface{}) error {

log.Printf("[DEBUG] updating file: %#v", d)
if d.HasChange("destination_file") {
oldDestinationFile, newDestinationFile := d.GetChange("destination_file")
f := file{}

if v, ok := d.GetOk("datacenter"); ok {
f.datacenter = v.(string)
}

if v, ok := d.GetOk("datastore"); ok {
f.datastore = v.(string)
if d.HasChange("destination_file") || d.HasChange("datacenter") || d.HasChange("datastore") {
// File needs to be moved, get old and new destination changes
var oldDataceneter, newDatacenter, oldDatastore, newDatastore, oldDestinationFile, newDestinationFile string
if d.HasChange("datacenter") {
tmpOldDataceneter, tmpNewDatacenter := d.GetChange("datacenter")
oldDataceneter = tmpOldDataceneter.(string)
newDatacenter = tmpNewDatacenter.(string)
} else {
return fmt.Errorf("datastore argument is required")
if v, ok := d.GetOk("datacenter"); ok {
oldDataceneter = v.(string)
newDatacenter = oldDataceneter
}
}

if v, ok := d.GetOk("source_file"); ok {
f.sourceFile = v.(string)
if d.HasChange("datastore") {
tmpOldDatastore, tmpNewDatastore := d.GetChange("datastore")
oldDatastore = tmpOldDatastore.(string)
newDatastore = tmpNewDatastore.(string)
} else {
return fmt.Errorf("source_file argument is required")
oldDatastore = d.Get("datastore").(string)
newDatastore = oldDatastore
}

if v, ok := d.GetOk("destination_file"); ok {
f.destinationFile = v.(string)
if d.HasChange("destination_file") {
tmpOldDestinationFile, tmpNewDestinationFile := d.GetChange("destination_file")
oldDestinationFile = tmpOldDestinationFile.(string)
newDestinationFile = tmpNewDestinationFile.(string)
} else {
return fmt.Errorf("destination_file argument is required")
oldDestinationFile = d.Get("destination_file").(string)
newDestinationFile = oldDestinationFile
}

// Get old and new dataceter and datastore
client := meta.(*govmomi.Client)
dc, err := getDatacenter(client, f.datacenter)
dcOld, err := getDatacenter(client, oldDataceneter)
if err != nil {
return err
}
dcNew, err := getDatacenter(client, newDatacenter)
if err != nil {
return err
}

finder := find.NewFinder(client.Client, true)
finder = finder.SetDatacenter(dc)

ds, err := getDatastore(finder, f.datastore)
finder = finder.SetDatacenter(dcOld)
dsOld, err := getDatastore(finder, oldDatastore)
if err != nil {
return fmt.Errorf("error %s", err)
}
finder = finder.SetDatacenter(dcNew)
dsNew, err := getDatastore(finder, newDatastore)
if err != nil {
return fmt.Errorf("error %s", err)
}

// Move file between old/new dataceter, datastore and path (destination_file)
fm := object.NewFileManager(client.Client)
task, err := fm.MoveDatastoreFile(context.TODO(), ds.Path(oldDestinationFile.(string)), dc, ds.Path(newDestinationFile.(string)), dc, true)
task, err := fm.MoveDatastoreFile(context.TODO(), dsOld.Path(oldDestinationFile), dcOld, dsNew.Path(newDestinationFile), dcNew, true)
if err != nil {
return err
}

_, err = task.WaitForResult(context.TODO(), nil)
if err != nil {
return err
}

}

return nil
Expand Down
Loading

0 comments on commit de822d9

Please sign in to comment.