github.com/leeprovoost/terraform@v0.6.10-0.20160119085442-96f3f76118e7/builtin/providers/vsphere/resource_vsphere_folder.go (about)

     1  package vsphere
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  	"path"
     7  	"strings"
     8  
     9  	"github.com/hashicorp/terraform/helper/schema"
    10  	"github.com/vmware/govmomi"
    11  	"github.com/vmware/govmomi/find"
    12  	"github.com/vmware/govmomi/object"
    13  	"golang.org/x/net/context"
    14  )
    15  
    16  type folder struct {
    17  	datacenter   string
    18  	existingPath string
    19  	path         string
    20  }
    21  
    22  func resourceVSphereFolder() *schema.Resource {
    23  	return &schema.Resource{
    24  		Create: resourceVSphereFolderCreate,
    25  		Read:   resourceVSphereFolderRead,
    26  		Delete: resourceVSphereFolderDelete,
    27  
    28  		Schema: map[string]*schema.Schema{
    29  			"datacenter": &schema.Schema{
    30  				Type:     schema.TypeString,
    31  				Optional: true,
    32  				ForceNew: true,
    33  			},
    34  
    35  			"path": &schema.Schema{
    36  				Type:     schema.TypeString,
    37  				Required: true,
    38  				ForceNew: true,
    39  			},
    40  
    41  			"existing_path": &schema.Schema{
    42  				Type:     schema.TypeString,
    43  				Computed: true,
    44  			},
    45  		},
    46  	}
    47  }
    48  
    49  func resourceVSphereFolderCreate(d *schema.ResourceData, meta interface{}) error {
    50  
    51  	client := meta.(*govmomi.Client)
    52  
    53  	f := folder{
    54  		path: strings.TrimRight(d.Get("path").(string), "/"),
    55  	}
    56  
    57  	if v, ok := d.GetOk("datacenter"); ok {
    58  		f.datacenter = v.(string)
    59  	}
    60  
    61  	createFolder(client, &f)
    62  
    63  	d.Set("existing_path", f.existingPath)
    64  	d.SetId(fmt.Sprintf("%v/%v", f.datacenter, f.path))
    65  	log.Printf("[INFO] Created folder: %s", f.path)
    66  
    67  	return resourceVSphereFolderRead(d, meta)
    68  }
    69  
    70  func createFolder(client *govmomi.Client, f *folder) error {
    71  
    72  	finder := find.NewFinder(client.Client, true)
    73  
    74  	dc, err := finder.Datacenter(context.TODO(), f.datacenter)
    75  	if err != nil {
    76  		return fmt.Errorf("error %s", err)
    77  	}
    78  	finder = finder.SetDatacenter(dc)
    79  	si := object.NewSearchIndex(client.Client)
    80  
    81  	dcFolders, err := dc.Folders(context.TODO())
    82  	if err != nil {
    83  		return fmt.Errorf("error %s", err)
    84  	}
    85  
    86  	folder := dcFolders.VmFolder
    87  	var workingPath string
    88  
    89  	pathParts := strings.Split(f.path, "/")
    90  	for _, pathPart := range pathParts {
    91  		if len(workingPath) > 0 {
    92  			workingPath += "/"
    93  		}
    94  		workingPath += pathPart
    95  		subfolder, err := si.FindByInventoryPath(
    96  			context.TODO(), fmt.Sprintf("%v/vm/%v", f.datacenter, workingPath))
    97  
    98  		if err != nil {
    99  			return fmt.Errorf("error %s", err)
   100  		} else if subfolder == nil {
   101  			log.Printf("[DEBUG] folder not found; creating: %s", workingPath)
   102  			folder, err = folder.CreateFolder(context.TODO(), pathPart)
   103  			if err != nil {
   104  				return fmt.Errorf("Failed to create folder at %s; %s", workingPath, err)
   105  			}
   106  		} else {
   107  			log.Printf("[DEBUG] folder already exists: %s", workingPath)
   108  			f.existingPath = workingPath
   109  			folder = subfolder.(*object.Folder)
   110  		}
   111  	}
   112  	return nil
   113  }
   114  
   115  func resourceVSphereFolderRead(d *schema.ResourceData, meta interface{}) error {
   116  
   117  	log.Printf("[DEBUG] reading folder: %#v", d)
   118  	client := meta.(*govmomi.Client)
   119  
   120  	dc, err := getDatacenter(client, d.Get("datacenter").(string))
   121  	if err != nil {
   122  		return err
   123  	}
   124  
   125  	finder := find.NewFinder(client.Client, true)
   126  	finder = finder.SetDatacenter(dc)
   127  
   128  	folder, err := object.NewSearchIndex(client.Client).FindByInventoryPath(
   129  		context.TODO(), fmt.Sprintf("%v/vm/%v", d.Get("datacenter").(string),
   130  			d.Get("path").(string)))
   131  
   132  	if err != nil {
   133  		return err
   134  	}
   135  
   136  	if folder == nil {
   137  		d.SetId("")
   138  	}
   139  
   140  	return nil
   141  }
   142  
   143  func resourceVSphereFolderDelete(d *schema.ResourceData, meta interface{}) error {
   144  
   145  	f := folder{
   146  		path:         strings.TrimRight(d.Get("path").(string), "/"),
   147  		existingPath: d.Get("existing_path").(string),
   148  	}
   149  
   150  	if v, ok := d.GetOk("datacenter"); ok {
   151  		f.datacenter = v.(string)
   152  	}
   153  
   154  	client := meta.(*govmomi.Client)
   155  
   156  	deleteFolder(client, &f)
   157  
   158  	d.SetId("")
   159  	return nil
   160  }
   161  
   162  func deleteFolder(client *govmomi.Client, f *folder) error {
   163  	dc, err := getDatacenter(client, f.datacenter)
   164  	if err != nil {
   165  		return err
   166  	}
   167  	var folder *object.Folder
   168  	currentPath := f.path
   169  
   170  	finder := find.NewFinder(client.Client, true)
   171  	finder = finder.SetDatacenter(dc)
   172  	si := object.NewSearchIndex(client.Client)
   173  
   174  	folderRef, err := si.FindByInventoryPath(
   175  		context.TODO(), fmt.Sprintf("%v/vm/%v", f.datacenter, f.path))
   176  
   177  	if err != nil {
   178  		return fmt.Errorf("[ERROR] Could not locate folder %s: %v", f.path, err)
   179  	} else {
   180  		folder = folderRef.(*object.Folder)
   181  	}
   182  
   183  	log.Printf("[INFO] Deleting empty sub-folders of existing path: %s", f.existingPath)
   184  	for currentPath != f.existingPath {
   185  		log.Printf("[INFO] Deleting folder: %s", currentPath)
   186  		children, err := folder.Children(context.TODO())
   187  		if err != nil {
   188  			return err
   189  		}
   190  
   191  		if len(children) > 0 {
   192  			return fmt.Errorf("Folder %s is non-empty and will not be deleted", currentPath)
   193  		} else {
   194  			log.Printf("[DEBUG] current folder: %#v", folder)
   195  			currentPath = path.Dir(currentPath)
   196  			if currentPath == "." {
   197  				currentPath = ""
   198  			}
   199  			log.Printf("[INFO] parent path of %s is calculated as %s", f.path, currentPath)
   200  			task, err := folder.Destroy(context.TODO())
   201  			if err != nil {
   202  				return err
   203  			}
   204  			err = task.Wait(context.TODO())
   205  			if err != nil {
   206  				return err
   207  			}
   208  			folderRef, err = si.FindByInventoryPath(
   209  				context.TODO(), fmt.Sprintf("%v/vm/%v", f.datacenter, currentPath))
   210  
   211  			if err != nil {
   212  				return err
   213  			} else if folderRef != nil {
   214  				folder = folderRef.(*object.Folder)
   215  			}
   216  		}
   217  	}
   218  	return nil
   219  }
   220  
   221  // getDatacenter gets datacenter object
   222  func getDatacenter(c *govmomi.Client, dc string) (*object.Datacenter, error) {
   223  	finder := find.NewFinder(c.Client, true)
   224  	if dc != "" {
   225  		d, err := finder.Datacenter(context.TODO(), dc)
   226  		return d, err
   227  	} else {
   228  		d, err := finder.DefaultDatacenter(context.TODO())
   229  		return d, err
   230  	}
   231  }