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 }