github.com/shvar/terraform@v0.6.9-0.20151215234924-3365cd2231df/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 }