github.com/danp/terraform@v0.9.5-0.20170426144147-39d740081351/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  	err := createFolder(client, &f)
    62  	if err != nil {
    63  		return err
    64  	}
    65  
    66  	d.Set("existing_path", f.existingPath)
    67  	d.SetId(fmt.Sprintf("%v/%v", f.datacenter, f.path))
    68  	log.Printf("[INFO] Created folder: %s", f.path)
    69  
    70  	return resourceVSphereFolderRead(d, meta)
    71  }
    72  
    73  func createFolder(client *govmomi.Client, f *folder) error {
    74  
    75  	finder := find.NewFinder(client.Client, true)
    76  
    77  	dc, err := finder.Datacenter(context.TODO(), f.datacenter)
    78  	if err != nil {
    79  		return fmt.Errorf("error %s", err)
    80  	}
    81  	finder = finder.SetDatacenter(dc)
    82  	si := object.NewSearchIndex(client.Client)
    83  
    84  	dcFolders, err := dc.Folders(context.TODO())
    85  	if err != nil {
    86  		return fmt.Errorf("error %s", err)
    87  	}
    88  
    89  	folder := dcFolders.VmFolder
    90  	var workingPath string
    91  
    92  	pathParts := strings.Split(f.path, "/")
    93  	for _, pathPart := range pathParts {
    94  		if len(workingPath) > 0 {
    95  			workingPath += "/"
    96  		}
    97  		workingPath += pathPart
    98  		subfolder, err := si.FindByInventoryPath(
    99  			context.TODO(), fmt.Sprintf("%v/vm/%v", f.datacenter, workingPath))
   100  
   101  		if err != nil {
   102  			return fmt.Errorf("error %s", err)
   103  		} else if subfolder == nil {
   104  			log.Printf("[DEBUG] folder not found; creating: %s", workingPath)
   105  			folder, err = folder.CreateFolder(context.TODO(), pathPart)
   106  			if err != nil {
   107  				return fmt.Errorf("Failed to create folder at %s; %s", workingPath, err)
   108  			}
   109  		} else {
   110  			log.Printf("[DEBUG] folder already exists: %s", workingPath)
   111  			f.existingPath = workingPath
   112  			folder = subfolder.(*object.Folder)
   113  		}
   114  	}
   115  	return nil
   116  }
   117  
   118  func resourceVSphereFolderRead(d *schema.ResourceData, meta interface{}) error {
   119  
   120  	log.Printf("[DEBUG] reading folder: %#v", d)
   121  	client := meta.(*govmomi.Client)
   122  
   123  	dc, err := getDatacenter(client, d.Get("datacenter").(string))
   124  	if err != nil {
   125  		return err
   126  	}
   127  
   128  	finder := find.NewFinder(client.Client, true)
   129  	finder = finder.SetDatacenter(dc)
   130  
   131  	folder, err := object.NewSearchIndex(client.Client).FindByInventoryPath(
   132  		context.TODO(), fmt.Sprintf("%v/vm/%v", d.Get("datacenter").(string),
   133  			d.Get("path").(string)))
   134  
   135  	if err != nil {
   136  		return err
   137  	}
   138  
   139  	if folder == nil {
   140  		d.SetId("")
   141  	}
   142  
   143  	return nil
   144  }
   145  
   146  func resourceVSphereFolderDelete(d *schema.ResourceData, meta interface{}) error {
   147  
   148  	f := folder{
   149  		path:         strings.TrimRight(d.Get("path").(string), "/"),
   150  		existingPath: d.Get("existing_path").(string),
   151  	}
   152  
   153  	if v, ok := d.GetOk("datacenter"); ok {
   154  		f.datacenter = v.(string)
   155  	}
   156  
   157  	client := meta.(*govmomi.Client)
   158  
   159  	err := deleteFolder(client, &f)
   160  	if err != nil {
   161  		return err
   162  	}
   163  
   164  	d.SetId("")
   165  	return nil
   166  }
   167  
   168  func deleteFolder(client *govmomi.Client, f *folder) error {
   169  	dc, err := getDatacenter(client, f.datacenter)
   170  	if err != nil {
   171  		return err
   172  	}
   173  	var folder *object.Folder
   174  	currentPath := f.path
   175  
   176  	finder := find.NewFinder(client.Client, true)
   177  	finder = finder.SetDatacenter(dc)
   178  	si := object.NewSearchIndex(client.Client)
   179  
   180  	folderRef, err := si.FindByInventoryPath(
   181  		context.TODO(), fmt.Sprintf("%v/vm/%v", f.datacenter, f.path))
   182  
   183  	if err != nil {
   184  		return fmt.Errorf("[ERROR] Could not locate folder %s: %v", f.path, err)
   185  	} else {
   186  		folder = folderRef.(*object.Folder)
   187  	}
   188  
   189  	log.Printf("[INFO] Deleting empty sub-folders of existing path: %s", f.existingPath)
   190  	for currentPath != f.existingPath {
   191  		log.Printf("[INFO] Deleting folder: %s", currentPath)
   192  		children, err := folder.Children(context.TODO())
   193  		if err != nil {
   194  			return err
   195  		}
   196  
   197  		if len(children) > 0 {
   198  			return fmt.Errorf("Folder %s is non-empty and will not be deleted", currentPath)
   199  		} else {
   200  			log.Printf("[DEBUG] current folder: %#v", folder)
   201  			currentPath = path.Dir(currentPath)
   202  			if currentPath == "." {
   203  				currentPath = ""
   204  			}
   205  			log.Printf("[INFO] parent path of %s is calculated as %s", f.path, currentPath)
   206  			task, err := folder.Destroy(context.TODO())
   207  			if err != nil {
   208  				return err
   209  			}
   210  			err = task.Wait(context.TODO())
   211  			if err != nil {
   212  				return err
   213  			}
   214  			folderRef, err = si.FindByInventoryPath(
   215  				context.TODO(), fmt.Sprintf("%v/vm/%v", f.datacenter, currentPath))
   216  
   217  			if err != nil {
   218  				return err
   219  			} else if folderRef != nil {
   220  				folder = folderRef.(*object.Folder)
   221  			}
   222  		}
   223  	}
   224  	return nil
   225  }
   226  
   227  // getDatacenter gets datacenter object
   228  func getDatacenter(c *govmomi.Client, dc string) (*object.Datacenter, error) {
   229  	finder := find.NewFinder(c.Client, true)
   230  	if dc != "" {
   231  		d, err := finder.Datacenter(context.TODO(), dc)
   232  		return d, err
   233  	} else {
   234  		d, err := finder.DefaultDatacenter(context.TODO())
   235  		return d, err
   236  	}
   237  }