github.com/danp/terraform@v0.9.5-0.20170426144147-39d740081351/builtin/providers/vsphere/resource_vsphere_file.go (about) 1 package vsphere 2 3 import ( 4 "fmt" 5 "log" 6 "strings" 7 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/soap" 13 "golang.org/x/net/context" 14 ) 15 16 type file struct { 17 sourceDatacenter string 18 datacenter string 19 sourceDatastore string 20 datastore string 21 sourceFile string 22 destinationFile string 23 createDirectories bool 24 copyFile bool 25 } 26 27 func resourceVSphereFile() *schema.Resource { 28 return &schema.Resource{ 29 Create: resourceVSphereFileCreate, 30 Read: resourceVSphereFileRead, 31 Update: resourceVSphereFileUpdate, 32 Delete: resourceVSphereFileDelete, 33 34 Schema: map[string]*schema.Schema{ 35 "datacenter": { 36 Type: schema.TypeString, 37 Optional: true, 38 }, 39 40 "source_datacenter": { 41 Type: schema.TypeString, 42 Optional: true, 43 ForceNew: true, 44 }, 45 46 "datastore": { 47 Type: schema.TypeString, 48 Required: true, 49 }, 50 51 "source_datastore": { 52 Type: schema.TypeString, 53 Optional: true, 54 ForceNew: true, 55 }, 56 57 "source_file": { 58 Type: schema.TypeString, 59 Required: true, 60 ForceNew: true, 61 }, 62 63 "destination_file": { 64 Type: schema.TypeString, 65 Required: true, 66 }, 67 68 "create_directories": { 69 Type: schema.TypeBool, 70 Optional: true, 71 }, 72 }, 73 } 74 } 75 76 func resourceVSphereFileCreate(d *schema.ResourceData, meta interface{}) error { 77 78 log.Printf("[DEBUG] creating file: %#v", d) 79 client := meta.(*govmomi.Client) 80 81 f := file{} 82 83 if v, ok := d.GetOk("source_datacenter"); ok { 84 f.sourceDatacenter = v.(string) 85 f.copyFile = true 86 } 87 88 if v, ok := d.GetOk("datacenter"); ok { 89 f.datacenter = v.(string) 90 } 91 92 if v, ok := d.GetOk("source_datastore"); ok { 93 f.sourceDatastore = v.(string) 94 f.copyFile = true 95 } 96 97 if v, ok := d.GetOk("datastore"); ok { 98 f.datastore = v.(string) 99 } else { 100 return fmt.Errorf("datastore argument is required") 101 } 102 103 if v, ok := d.GetOk("source_file"); ok { 104 f.sourceFile = v.(string) 105 } else { 106 return fmt.Errorf("source_file argument is required") 107 } 108 109 if v, ok := d.GetOk("destination_file"); ok { 110 f.destinationFile = v.(string) 111 } else { 112 return fmt.Errorf("destination_file argument is required") 113 } 114 115 if v, ok := d.GetOk("create_directories"); ok { 116 f.createDirectories = v.(bool) 117 } 118 119 err := createFile(client, &f) 120 if err != nil { 121 return err 122 } 123 124 d.SetId(fmt.Sprintf("[%v] %v/%v", f.datastore, f.datacenter, f.destinationFile)) 125 log.Printf("[INFO] Created file: %s", f.destinationFile) 126 127 return resourceVSphereFileRead(d, meta) 128 } 129 130 func createFile(client *govmomi.Client, f *file) error { 131 132 finder := find.NewFinder(client.Client, true) 133 134 dc, err := finder.Datacenter(context.TODO(), f.datacenter) 135 if err != nil { 136 return fmt.Errorf("error %s", err) 137 } 138 finder = finder.SetDatacenter(dc) 139 140 ds, err := getDatastore(finder, f.datastore) 141 if err != nil { 142 return fmt.Errorf("error %s", err) 143 } 144 145 if f.copyFile { 146 // Copying file from withing vSphere 147 source_dc, err := finder.Datacenter(context.TODO(), f.sourceDatacenter) 148 if err != nil { 149 return fmt.Errorf("error %s", err) 150 } 151 finder = finder.SetDatacenter(dc) 152 153 source_ds, err := getDatastore(finder, f.sourceDatastore) 154 if err != nil { 155 return fmt.Errorf("error %s", err) 156 } 157 158 fm := object.NewFileManager(client.Client) 159 if f.createDirectories { 160 directoryPathIndex := strings.LastIndex(f.destinationFile, "/") 161 path := f.destinationFile[0:directoryPathIndex] 162 err = fm.MakeDirectory(context.TODO(), ds.Path(path), dc, true) 163 if err != nil { 164 return fmt.Errorf("error %s", err) 165 } 166 } 167 task, err := fm.CopyDatastoreFile(context.TODO(), source_ds.Path(f.sourceFile), source_dc, ds.Path(f.destinationFile), dc, true) 168 169 if err != nil { 170 return fmt.Errorf("error %s", err) 171 } 172 173 _, err = task.WaitForResult(context.TODO(), nil) 174 if err != nil { 175 return fmt.Errorf("error %s", err) 176 } 177 178 } else { 179 // Uploading file to vSphere 180 dsurl, err := ds.URL(context.TODO(), dc, f.destinationFile) 181 if err != nil { 182 return fmt.Errorf("error %s", err) 183 } 184 185 p := soap.DefaultUpload 186 err = client.Client.UploadFile(f.sourceFile, dsurl, &p) 187 if err != nil { 188 return fmt.Errorf("error %s", err) 189 } 190 } 191 192 return nil 193 } 194 195 func resourceVSphereFileRead(d *schema.ResourceData, meta interface{}) error { 196 197 log.Printf("[DEBUG] reading file: %#v", d) 198 f := file{} 199 200 if v, ok := d.GetOk("source_datacenter"); ok { 201 f.sourceDatacenter = v.(string) 202 } 203 204 if v, ok := d.GetOk("datacenter"); ok { 205 f.datacenter = v.(string) 206 } 207 208 if v, ok := d.GetOk("source_datastore"); ok { 209 f.sourceDatastore = v.(string) 210 } 211 212 if v, ok := d.GetOk("datastore"); ok { 213 f.datastore = v.(string) 214 } else { 215 return fmt.Errorf("datastore argument is required") 216 } 217 218 if v, ok := d.GetOk("source_file"); ok { 219 f.sourceFile = v.(string) 220 } else { 221 return fmt.Errorf("source_file argument is required") 222 } 223 224 if v, ok := d.GetOk("destination_file"); ok { 225 f.destinationFile = v.(string) 226 } else { 227 return fmt.Errorf("destination_file argument is required") 228 } 229 230 client := meta.(*govmomi.Client) 231 finder := find.NewFinder(client.Client, true) 232 233 dc, err := finder.Datacenter(context.TODO(), f.datacenter) 234 if err != nil { 235 return fmt.Errorf("error %s", err) 236 } 237 finder = finder.SetDatacenter(dc) 238 239 ds, err := getDatastore(finder, f.datastore) 240 if err != nil { 241 return fmt.Errorf("error %s", err) 242 } 243 244 _, err = ds.Stat(context.TODO(), f.destinationFile) 245 if err != nil { 246 log.Printf("[DEBUG] resourceVSphereFileRead - stat failed on: %v", f.destinationFile) 247 d.SetId("") 248 249 _, ok := err.(object.DatastoreNoSuchFileError) 250 if !ok { 251 return err 252 } 253 } 254 255 return nil 256 } 257 258 func resourceVSphereFileUpdate(d *schema.ResourceData, meta interface{}) error { 259 260 log.Printf("[DEBUG] updating file: %#v", d) 261 262 if d.HasChange("destination_file") || d.HasChange("datacenter") || d.HasChange("datastore") { 263 // File needs to be moved, get old and new destination changes 264 var oldDataceneter, newDatacenter, oldDatastore, newDatastore, oldDestinationFile, newDestinationFile string 265 if d.HasChange("datacenter") { 266 tmpOldDataceneter, tmpNewDatacenter := d.GetChange("datacenter") 267 oldDataceneter = tmpOldDataceneter.(string) 268 newDatacenter = tmpNewDatacenter.(string) 269 } else { 270 if v, ok := d.GetOk("datacenter"); ok { 271 oldDataceneter = v.(string) 272 newDatacenter = oldDataceneter 273 } 274 } 275 if d.HasChange("datastore") { 276 tmpOldDatastore, tmpNewDatastore := d.GetChange("datastore") 277 oldDatastore = tmpOldDatastore.(string) 278 newDatastore = tmpNewDatastore.(string) 279 } else { 280 oldDatastore = d.Get("datastore").(string) 281 newDatastore = oldDatastore 282 } 283 if d.HasChange("destination_file") { 284 tmpOldDestinationFile, tmpNewDestinationFile := d.GetChange("destination_file") 285 oldDestinationFile = tmpOldDestinationFile.(string) 286 newDestinationFile = tmpNewDestinationFile.(string) 287 } else { 288 oldDestinationFile = d.Get("destination_file").(string) 289 newDestinationFile = oldDestinationFile 290 } 291 292 // Get old and new dataceter and datastore 293 client := meta.(*govmomi.Client) 294 dcOld, err := getDatacenter(client, oldDataceneter) 295 if err != nil { 296 return err 297 } 298 dcNew, err := getDatacenter(client, newDatacenter) 299 if err != nil { 300 return err 301 } 302 finder := find.NewFinder(client.Client, true) 303 finder = finder.SetDatacenter(dcOld) 304 dsOld, err := getDatastore(finder, oldDatastore) 305 if err != nil { 306 return fmt.Errorf("error %s", err) 307 } 308 finder = finder.SetDatacenter(dcNew) 309 dsNew, err := getDatastore(finder, newDatastore) 310 if err != nil { 311 return fmt.Errorf("error %s", err) 312 } 313 314 // Move file between old/new dataceter, datastore and path (destination_file) 315 fm := object.NewFileManager(client.Client) 316 task, err := fm.MoveDatastoreFile(context.TODO(), dsOld.Path(oldDestinationFile), dcOld, dsNew.Path(newDestinationFile), dcNew, true) 317 if err != nil { 318 return err 319 } 320 _, err = task.WaitForResult(context.TODO(), nil) 321 if err != nil { 322 return err 323 } 324 } 325 326 return nil 327 } 328 329 func resourceVSphereFileDelete(d *schema.ResourceData, meta interface{}) error { 330 331 log.Printf("[DEBUG] deleting file: %#v", d) 332 f := file{} 333 334 if v, ok := d.GetOk("datacenter"); ok { 335 f.datacenter = v.(string) 336 } 337 338 if v, ok := d.GetOk("datastore"); ok { 339 f.datastore = v.(string) 340 } else { 341 return fmt.Errorf("datastore argument is required") 342 } 343 344 if v, ok := d.GetOk("source_file"); ok { 345 f.sourceFile = v.(string) 346 } else { 347 return fmt.Errorf("source_file argument is required") 348 } 349 350 if v, ok := d.GetOk("destination_file"); ok { 351 f.destinationFile = v.(string) 352 } else { 353 return fmt.Errorf("destination_file argument is required") 354 } 355 356 client := meta.(*govmomi.Client) 357 358 err := deleteFile(client, &f) 359 if err != nil { 360 return err 361 } 362 363 d.SetId("") 364 return nil 365 } 366 367 func deleteFile(client *govmomi.Client, f *file) error { 368 369 dc, err := getDatacenter(client, f.datacenter) 370 if err != nil { 371 return err 372 } 373 374 finder := find.NewFinder(client.Client, true) 375 finder = finder.SetDatacenter(dc) 376 377 ds, err := getDatastore(finder, f.datastore) 378 if err != nil { 379 return fmt.Errorf("error %s", err) 380 } 381 382 fm := object.NewFileManager(client.Client) 383 task, err := fm.DeleteDatastoreFile(context.TODO(), ds.Path(f.destinationFile), dc) 384 if err != nil { 385 return err 386 } 387 388 _, err = task.WaitForResult(context.TODO(), nil) 389 if err != nil { 390 return err 391 } 392 return nil 393 } 394 395 // getDatastore gets datastore object 396 func getDatastore(f *find.Finder, ds string) (*object.Datastore, error) { 397 398 if ds != "" { 399 dso, err := f.Datastore(context.TODO(), ds) 400 return dso, err 401 } else { 402 dso, err := f.DefaultDatastore(context.TODO()) 403 return dso, err 404 } 405 }