github.com/danp/terraform@v0.9.5-0.20170426144147-39d740081351/builtin/providers/vsphere/resource_vsphere_virtual_disk.go (about) 1 package vsphere 2 3 import ( 4 "fmt" 5 "log" 6 7 "errors" 8 "github.com/hashicorp/terraform/helper/schema" 9 "github.com/vmware/govmomi" 10 "github.com/vmware/govmomi/find" 11 "github.com/vmware/govmomi/object" 12 "github.com/vmware/govmomi/vim25/types" 13 "golang.org/x/net/context" 14 "path" 15 ) 16 17 type virtualDisk struct { 18 size int 19 vmdkPath string 20 initType string 21 adapterType string 22 datacenter string 23 datastore string 24 } 25 26 // Define VirtualDisk args 27 func resourceVSphereVirtualDisk() *schema.Resource { 28 return &schema.Resource{ 29 Create: resourceVSphereVirtualDiskCreate, 30 Read: resourceVSphereVirtualDiskRead, 31 Delete: resourceVSphereVirtualDiskDelete, 32 33 Schema: map[string]*schema.Schema{ 34 // Size in GB 35 "size": &schema.Schema{ 36 Type: schema.TypeInt, 37 Required: true, 38 ForceNew: true, //TODO Can this be optional (resize)? 39 }, 40 41 "vmdk_path": &schema.Schema{ 42 Type: schema.TypeString, 43 Required: true, 44 ForceNew: true, //TODO Can this be optional (move)? 45 }, 46 47 "type": &schema.Schema{ 48 Type: schema.TypeString, 49 Optional: true, 50 ForceNew: true, 51 Default: "eagerZeroedThick", 52 ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) { 53 value := v.(string) 54 if value != "thin" && value != "eagerZeroedThick" && value != "lazy" { 55 errors = append(errors, fmt.Errorf( 56 "only 'thin', 'eagerZeroedThick', and 'lazy' are supported values for 'type'")) 57 } 58 return 59 }, 60 }, 61 62 "adapter_type": &schema.Schema{ 63 Type: schema.TypeString, 64 Optional: true, 65 ForceNew: true, 66 Default: "ide", 67 ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) { 68 value := v.(string) 69 if value != "ide" && value != "busLogic" && value != "lsiLogic" { 70 errors = append(errors, fmt.Errorf( 71 "only 'ide', 'busLogic', and 'lsiLogic' are supported values for 'adapter_type'")) 72 } 73 return 74 }, 75 }, 76 77 "datacenter": &schema.Schema{ 78 Type: schema.TypeString, 79 Optional: true, 80 ForceNew: true, 81 }, 82 83 "datastore": &schema.Schema{ 84 Type: schema.TypeString, 85 Optional: true, 86 ForceNew: true, 87 }, 88 }, 89 } 90 } 91 92 func resourceVSphereVirtualDiskCreate(d *schema.ResourceData, meta interface{}) error { 93 log.Printf("[INFO] Creating Virtual Disk") 94 client := meta.(*govmomi.Client) 95 96 vDisk := virtualDisk{ 97 size: d.Get("size").(int), 98 } 99 100 if v, ok := d.GetOk("vmdk_path"); ok { 101 vDisk.vmdkPath = v.(string) 102 } 103 104 if v, ok := d.GetOk("type"); ok { 105 vDisk.initType = v.(string) 106 } 107 108 if v, ok := d.GetOk("adapter_type"); ok { 109 vDisk.adapterType = v.(string) 110 } 111 112 if v, ok := d.GetOk("datacenter"); ok { 113 vDisk.datacenter = v.(string) 114 } 115 116 if v, ok := d.GetOk("datastore"); ok { 117 vDisk.datastore = v.(string) 118 } 119 120 finder := find.NewFinder(client.Client, true) 121 122 dc, err := getDatacenter(client, d.Get("datacenter").(string)) 123 if err != nil { 124 return fmt.Errorf("Error finding Datacenter: %s: %s", vDisk.datacenter, err) 125 } 126 finder = finder.SetDatacenter(dc) 127 128 ds, err := getDatastore(finder, vDisk.datastore) 129 if err != nil { 130 return fmt.Errorf("Error finding Datastore: %s: %s", vDisk.datastore, err) 131 } 132 133 err = createHardDisk(client, vDisk.size, ds.Path(vDisk.vmdkPath), vDisk.initType, vDisk.adapterType, vDisk.datacenter) 134 if err != nil { 135 return err 136 } 137 138 d.SetId(ds.Path(vDisk.vmdkPath)) 139 log.Printf("[DEBUG] Virtual Disk id: %v", ds.Path(vDisk.vmdkPath)) 140 141 return resourceVSphereVirtualDiskRead(d, meta) 142 } 143 144 func resourceVSphereVirtualDiskRead(d *schema.ResourceData, meta interface{}) error { 145 log.Printf("[DEBUG] Reading virtual disk.") 146 client := meta.(*govmomi.Client) 147 148 vDisk := virtualDisk{ 149 size: d.Get("size").(int), 150 } 151 152 if v, ok := d.GetOk("vmdk_path"); ok { 153 vDisk.vmdkPath = v.(string) 154 } 155 156 if v, ok := d.GetOk("type"); ok { 157 vDisk.initType = v.(string) 158 } 159 160 if v, ok := d.GetOk("adapter_type"); ok { 161 vDisk.adapterType = v.(string) 162 } 163 164 if v, ok := d.GetOk("datacenter"); ok { 165 vDisk.datacenter = v.(string) 166 } 167 168 if v, ok := d.GetOk("datastore"); ok { 169 vDisk.datastore = v.(string) 170 } 171 172 dc, err := getDatacenter(client, d.Get("datacenter").(string)) 173 if err != nil { 174 return err 175 } 176 177 finder := find.NewFinder(client.Client, true) 178 finder = finder.SetDatacenter(dc) 179 180 ds, err := finder.Datastore(context.TODO(), d.Get("datastore").(string)) 181 if err != nil { 182 return err 183 } 184 185 ctx := context.TODO() 186 b, err := ds.Browser(ctx) 187 if err != nil { 188 return err 189 } 190 191 // `Datastore.Stat` does not allow to query `VmDiskFileQuery`. Instead, we 192 // search the datastore manually. 193 spec := types.HostDatastoreBrowserSearchSpec{ 194 Query: []types.BaseFileQuery{&types.VmDiskFileQuery{Details: &types.VmDiskFileQueryFlags{ 195 CapacityKb: true, 196 DiskType: true, 197 }}}, 198 Details: &types.FileQueryFlags{ 199 FileSize: true, 200 FileType: true, 201 Modification: true, 202 FileOwner: types.NewBool(true), 203 }, 204 MatchPattern: []string{path.Base(vDisk.vmdkPath)}, 205 } 206 207 dsPath := ds.Path(path.Dir(vDisk.vmdkPath)) 208 task, err := b.SearchDatastore(context.TODO(), dsPath, &spec) 209 210 if err != nil { 211 log.Printf("[DEBUG] resourceVSphereVirtualDiskRead - could not search datastore for: %v", vDisk.vmdkPath) 212 return err 213 } 214 215 info, err := task.WaitForResult(context.TODO(), nil) 216 if err != nil { 217 if info == nil || info.Error != nil { 218 _, ok := info.Error.Fault.(*types.FileNotFound) 219 if ok { 220 log.Printf("[DEBUG] resourceVSphereVirtualDiskRead - could not find: %v", vDisk.vmdkPath) 221 d.SetId("") 222 return nil 223 } 224 } 225 226 log.Printf("[DEBUG] resourceVSphereVirtualDiskRead - could not search datastore for: %v", vDisk.vmdkPath) 227 return err 228 } 229 230 res := info.Result.(types.HostDatastoreBrowserSearchResults) 231 log.Printf("[DEBUG] num results: %d", len(res.File)) 232 if len(res.File) == 0 { 233 d.SetId("") 234 log.Printf("[DEBUG] resourceVSphereVirtualDiskRead - could not find: %v", vDisk.vmdkPath) 235 return nil 236 } 237 238 if len(res.File) != 1 { 239 return errors.New("Datastore search did not return exactly one result") 240 } 241 242 fileInfo := res.File[0] 243 log.Printf("[DEBUG] resourceVSphereVirtualDiskRead - fileinfo: %#v", fileInfo) 244 size := fileInfo.(*types.VmDiskFileInfo).CapacityKb / 1024 / 1024 245 246 d.SetId(vDisk.vmdkPath) 247 248 d.Set("size", size) 249 d.Set("vmdk_path", vDisk.vmdkPath) 250 d.Set("datacenter", d.Get("datacenter")) 251 d.Set("datastore", d.Get("datastore")) 252 // Todo collect and write type info 253 254 return nil 255 256 } 257 258 func resourceVSphereVirtualDiskDelete(d *schema.ResourceData, meta interface{}) error { 259 client := meta.(*govmomi.Client) 260 261 vDisk := virtualDisk{} 262 263 if v, ok := d.GetOk("vmdk_path"); ok { 264 vDisk.vmdkPath = v.(string) 265 } 266 if v, ok := d.GetOk("datastore"); ok { 267 vDisk.datastore = v.(string) 268 } 269 270 dc, err := getDatacenter(client, d.Get("datacenter").(string)) 271 if err != nil { 272 return err 273 } 274 275 finder := find.NewFinder(client.Client, true) 276 finder = finder.SetDatacenter(dc) 277 278 ds, err := getDatastore(finder, vDisk.datastore) 279 if err != nil { 280 return err 281 } 282 283 diskPath := ds.Path(vDisk.vmdkPath) 284 285 virtualDiskManager := object.NewVirtualDiskManager(client.Client) 286 287 task, err := virtualDiskManager.DeleteVirtualDisk(context.TODO(), diskPath, dc) 288 if err != nil { 289 return err 290 } 291 292 _, err = task.WaitForResult(context.TODO(), nil) 293 if err != nil { 294 log.Printf("[INFO] Failed to delete disk: %v", err) 295 return err 296 } 297 298 log.Printf("[INFO] Deleted disk: %v", diskPath) 299 d.SetId("") 300 return nil 301 } 302 303 // createHardDisk creates a new Hard Disk. 304 func createHardDisk(client *govmomi.Client, size int, diskPath string, diskType string, adapterType string, dc string) error { 305 var vDiskType string 306 switch diskType { 307 case "thin": 308 vDiskType = "thin" 309 case "eagerZeroedThick": 310 vDiskType = "eagerZeroedThick" 311 case "lazy": 312 vDiskType = "preallocated" 313 } 314 315 virtualDiskManager := object.NewVirtualDiskManager(client.Client) 316 spec := &types.FileBackedVirtualDiskSpec{ 317 VirtualDiskSpec: types.VirtualDiskSpec{ 318 AdapterType: adapterType, 319 DiskType: vDiskType, 320 }, 321 CapacityKb: int64(1024 * 1024 * size), 322 } 323 datacenter, err := getDatacenter(client, dc) 324 if err != nil { 325 return err 326 } 327 log.Printf("[DEBUG] Disk spec: %v", spec) 328 329 task, err := virtualDiskManager.CreateVirtualDisk(context.TODO(), diskPath, datacenter, spec) 330 if err != nil { 331 return err 332 } 333 334 _, err = task.WaitForResult(context.TODO(), nil) 335 if err != nil { 336 log.Printf("[INFO] Failed to create disk: %v", err) 337 return err 338 } 339 log.Printf("[INFO] Created disk.") 340 341 return nil 342 }