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