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 }