github.com/vtorhonen/terraform@v0.9.0-beta2.0.20170307220345-5d894e4ffda7/builtin/providers/google/resource_compute_instance_template.go (about) 1 package google 2 3 import ( 4 "fmt" 5 "log" 6 "strings" 7 8 "github.com/hashicorp/terraform/helper/resource" 9 "github.com/hashicorp/terraform/helper/schema" 10 "google.golang.org/api/compute/v1" 11 "google.golang.org/api/googleapi" 12 ) 13 14 func resourceComputeInstanceTemplate() *schema.Resource { 15 return &schema.Resource{ 16 Create: resourceComputeInstanceTemplateCreate, 17 Read: resourceComputeInstanceTemplateRead, 18 Delete: resourceComputeInstanceTemplateDelete, 19 Importer: &schema.ResourceImporter{ 20 State: schema.ImportStatePassthrough, 21 }, 22 23 Schema: map[string]*schema.Schema{ 24 "name": &schema.Schema{ 25 Type: schema.TypeString, 26 Optional: true, 27 Computed: true, 28 ForceNew: true, 29 ConflictsWith: []string{"name_prefix"}, 30 ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) { 31 // https://cloud.google.com/compute/docs/reference/latest/instanceTemplates#resource 32 value := v.(string) 33 if len(value) > 63 { 34 errors = append(errors, fmt.Errorf( 35 "%q cannot be longer than 63 characters", k)) 36 } 37 return 38 }, 39 }, 40 41 "name_prefix": &schema.Schema{ 42 Type: schema.TypeString, 43 Optional: true, 44 ForceNew: true, 45 ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) { 46 // https://cloud.google.com/compute/docs/reference/latest/instanceTemplates#resource 47 // uuid is 26 characters, limit the prefix to 37. 48 value := v.(string) 49 if len(value) > 37 { 50 errors = append(errors, fmt.Errorf( 51 "%q cannot be longer than 37 characters, name is limited to 63", k)) 52 } 53 return 54 }, 55 }, 56 "disk": &schema.Schema{ 57 Type: schema.TypeList, 58 Required: true, 59 ForceNew: true, 60 Elem: &schema.Resource{ 61 Schema: map[string]*schema.Schema{ 62 "auto_delete": &schema.Schema{ 63 Type: schema.TypeBool, 64 Optional: true, 65 Default: true, 66 ForceNew: true, 67 }, 68 69 "boot": &schema.Schema{ 70 Type: schema.TypeBool, 71 Optional: true, 72 ForceNew: true, 73 Computed: true, 74 }, 75 76 "device_name": &schema.Schema{ 77 Type: schema.TypeString, 78 Optional: true, 79 ForceNew: true, 80 }, 81 82 "disk_name": &schema.Schema{ 83 Type: schema.TypeString, 84 Optional: true, 85 ForceNew: true, 86 }, 87 88 "disk_size_gb": &schema.Schema{ 89 Type: schema.TypeInt, 90 Optional: true, 91 ForceNew: true, 92 }, 93 94 "disk_type": &schema.Schema{ 95 Type: schema.TypeString, 96 Optional: true, 97 ForceNew: true, 98 Computed: true, 99 }, 100 101 "source_image": &schema.Schema{ 102 Type: schema.TypeString, 103 Optional: true, 104 ForceNew: true, 105 }, 106 107 "interface": &schema.Schema{ 108 Type: schema.TypeString, 109 Optional: true, 110 ForceNew: true, 111 Computed: true, 112 }, 113 114 "mode": &schema.Schema{ 115 Type: schema.TypeString, 116 Optional: true, 117 ForceNew: true, 118 Computed: true, 119 }, 120 121 "source": &schema.Schema{ 122 Type: schema.TypeString, 123 Optional: true, 124 ForceNew: true, 125 }, 126 127 "type": &schema.Schema{ 128 Type: schema.TypeString, 129 Optional: true, 130 ForceNew: true, 131 Computed: true, 132 }, 133 }, 134 }, 135 }, 136 137 "machine_type": &schema.Schema{ 138 Type: schema.TypeString, 139 Required: true, 140 ForceNew: true, 141 }, 142 143 "automatic_restart": &schema.Schema{ 144 Type: schema.TypeBool, 145 Optional: true, 146 Default: true, 147 ForceNew: true, 148 Deprecated: "Please use `scheduling.automatic_restart` instead", 149 }, 150 151 "can_ip_forward": &schema.Schema{ 152 Type: schema.TypeBool, 153 Optional: true, 154 Default: false, 155 ForceNew: true, 156 }, 157 158 "description": &schema.Schema{ 159 Type: schema.TypeString, 160 Optional: true, 161 ForceNew: true, 162 }, 163 164 "instance_description": &schema.Schema{ 165 Type: schema.TypeString, 166 Optional: true, 167 ForceNew: true, 168 }, 169 170 "metadata": &schema.Schema{ 171 Type: schema.TypeMap, 172 Optional: true, 173 ForceNew: true, 174 }, 175 176 "metadata_startup_script": &schema.Schema{ 177 Type: schema.TypeString, 178 Optional: true, 179 ForceNew: true, 180 }, 181 182 "metadata_fingerprint": &schema.Schema{ 183 Type: schema.TypeString, 184 Computed: true, 185 }, 186 187 "network_interface": &schema.Schema{ 188 Type: schema.TypeList, 189 Optional: true, 190 ForceNew: true, 191 Elem: &schema.Resource{ 192 Schema: map[string]*schema.Schema{ 193 "network": &schema.Schema{ 194 Type: schema.TypeString, 195 Optional: true, 196 ForceNew: true, 197 Computed: true, 198 }, 199 200 "subnetwork": &schema.Schema{ 201 Type: schema.TypeString, 202 Optional: true, 203 ForceNew: true, 204 }, 205 206 "subnetwork_project": &schema.Schema{ 207 Type: schema.TypeString, 208 Optional: true, 209 ForceNew: true, 210 Computed: true, 211 }, 212 213 "access_config": &schema.Schema{ 214 Type: schema.TypeList, 215 Optional: true, 216 ForceNew: true, 217 Elem: &schema.Resource{ 218 Schema: map[string]*schema.Schema{ 219 "nat_ip": &schema.Schema{ 220 Type: schema.TypeString, 221 Computed: true, 222 Optional: true, 223 }, 224 }, 225 }, 226 }, 227 }, 228 }, 229 }, 230 231 "on_host_maintenance": &schema.Schema{ 232 Type: schema.TypeString, 233 Optional: true, 234 ForceNew: true, 235 Deprecated: "Please use `scheduling.on_host_maintenance` instead", 236 }, 237 238 "project": &schema.Schema{ 239 Type: schema.TypeString, 240 Optional: true, 241 ForceNew: true, 242 Computed: true, 243 }, 244 245 "region": &schema.Schema{ 246 Type: schema.TypeString, 247 Optional: true, 248 ForceNew: true, 249 }, 250 251 "scheduling": &schema.Schema{ 252 Type: schema.TypeList, 253 Optional: true, 254 Computed: true, 255 ForceNew: true, 256 Elem: &schema.Resource{ 257 Schema: map[string]*schema.Schema{ 258 "preemptible": &schema.Schema{ 259 Type: schema.TypeBool, 260 Optional: true, 261 Default: false, 262 ForceNew: true, 263 }, 264 265 "automatic_restart": &schema.Schema{ 266 Type: schema.TypeBool, 267 Optional: true, 268 Default: true, 269 ForceNew: true, 270 }, 271 272 "on_host_maintenance": &schema.Schema{ 273 Type: schema.TypeString, 274 Optional: true, 275 Computed: true, 276 ForceNew: true, 277 }, 278 }, 279 }, 280 }, 281 282 "self_link": &schema.Schema{ 283 Type: schema.TypeString, 284 Computed: true, 285 }, 286 287 "service_account": &schema.Schema{ 288 Type: schema.TypeList, 289 MaxItems: 1, 290 Optional: true, 291 ForceNew: true, 292 Elem: &schema.Resource{ 293 Schema: map[string]*schema.Schema{ 294 "email": &schema.Schema{ 295 Type: schema.TypeString, 296 Optional: true, 297 Computed: true, 298 ForceNew: true, 299 }, 300 301 "scopes": &schema.Schema{ 302 Type: schema.TypeList, 303 Required: true, 304 ForceNew: true, 305 Elem: &schema.Schema{ 306 Type: schema.TypeString, 307 StateFunc: func(v interface{}) string { 308 return canonicalizeServiceScope(v.(string)) 309 }, 310 }, 311 }, 312 }, 313 }, 314 }, 315 316 "tags": &schema.Schema{ 317 Type: schema.TypeSet, 318 Optional: true, 319 ForceNew: true, 320 Elem: &schema.Schema{Type: schema.TypeString}, 321 Set: schema.HashString, 322 }, 323 324 "tags_fingerprint": &schema.Schema{ 325 Type: schema.TypeString, 326 Computed: true, 327 }, 328 }, 329 } 330 } 331 332 func buildDisks(d *schema.ResourceData, meta interface{}) ([]*compute.AttachedDisk, error) { 333 config := meta.(*Config) 334 335 disksCount := d.Get("disk.#").(int) 336 337 disks := make([]*compute.AttachedDisk, 0, disksCount) 338 for i := 0; i < disksCount; i++ { 339 prefix := fmt.Sprintf("disk.%d", i) 340 341 // Build the disk 342 var disk compute.AttachedDisk 343 disk.Type = "PERSISTENT" 344 disk.Mode = "READ_WRITE" 345 disk.Interface = "SCSI" 346 disk.Boot = i == 0 347 disk.AutoDelete = d.Get(prefix + ".auto_delete").(bool) 348 349 if v, ok := d.GetOk(prefix + ".boot"); ok { 350 disk.Boot = v.(bool) 351 } 352 353 if v, ok := d.GetOk(prefix + ".device_name"); ok { 354 disk.DeviceName = v.(string) 355 } 356 357 if v, ok := d.GetOk(prefix + ".source"); ok { 358 disk.Source = v.(string) 359 } else { 360 disk.InitializeParams = &compute.AttachedDiskInitializeParams{} 361 362 if v, ok := d.GetOk(prefix + ".disk_name"); ok { 363 disk.InitializeParams.DiskName = v.(string) 364 } 365 if v, ok := d.GetOk(prefix + ".disk_size_gb"); ok { 366 disk.InitializeParams.DiskSizeGb = int64(v.(int)) 367 } 368 disk.InitializeParams.DiskType = "pd-standard" 369 if v, ok := d.GetOk(prefix + ".disk_type"); ok { 370 disk.InitializeParams.DiskType = v.(string) 371 } 372 373 if v, ok := d.GetOk(prefix + ".source_image"); ok { 374 imageName := v.(string) 375 imageUrl, err := resolveImage(config, imageName) 376 if err != nil { 377 return nil, fmt.Errorf( 378 "Error resolving image name '%s': %s", 379 imageName, err) 380 } 381 disk.InitializeParams.SourceImage = imageUrl 382 } 383 } 384 385 if v, ok := d.GetOk(prefix + ".interface"); ok { 386 disk.Interface = v.(string) 387 } 388 389 if v, ok := d.GetOk(prefix + ".mode"); ok { 390 disk.Mode = v.(string) 391 } 392 393 if v, ok := d.GetOk(prefix + ".type"); ok { 394 disk.Type = v.(string) 395 } 396 397 disks = append(disks, &disk) 398 } 399 400 return disks, nil 401 } 402 403 func buildNetworks(d *schema.ResourceData, meta interface{}) ([]*compute.NetworkInterface, error) { 404 // Build up the list of networks 405 config := meta.(*Config) 406 407 project, err := getProject(d, config) 408 if err != nil { 409 return nil, err 410 } 411 412 networksCount := d.Get("network_interface.#").(int) 413 networkInterfaces := make([]*compute.NetworkInterface, 0, networksCount) 414 for i := 0; i < networksCount; i++ { 415 prefix := fmt.Sprintf("network_interface.%d", i) 416 417 var networkName, subnetworkName, subnetworkProject string 418 if v, ok := d.GetOk(prefix + ".network"); ok { 419 networkName = v.(string) 420 } 421 if v, ok := d.GetOk(prefix + ".subnetwork"); ok { 422 subnetworkName = v.(string) 423 } 424 if v, ok := d.GetOk(prefix + ".subnetwork_project"); ok { 425 subnetworkProject = v.(string) 426 } 427 if networkName == "" && subnetworkName == "" { 428 return nil, fmt.Errorf("network or subnetwork must be provided") 429 } 430 if networkName != "" && subnetworkName != "" { 431 return nil, fmt.Errorf("network or subnetwork must not both be provided") 432 } 433 434 var networkLink, subnetworkLink string 435 if networkName != "" { 436 networkLink, err = getNetworkLink(d, config, prefix+".network") 437 if err != nil { 438 return nil, fmt.Errorf("Error referencing network '%s': %s", 439 networkName, err) 440 } 441 442 } else { 443 // lookup subnetwork link using region and subnetwork name 444 region, err := getRegion(d, config) 445 if err != nil { 446 return nil, err 447 } 448 if subnetworkProject == "" { 449 subnetworkProject = project 450 } 451 subnetwork, err := config.clientCompute.Subnetworks.Get( 452 subnetworkProject, region, subnetworkName).Do() 453 if err != nil { 454 return nil, fmt.Errorf( 455 "Error referencing subnetwork '%s' in region '%s': %s", 456 subnetworkName, region, err) 457 } 458 subnetworkLink = subnetwork.SelfLink 459 } 460 461 // Build the networkInterface 462 var iface compute.NetworkInterface 463 iface.Network = networkLink 464 iface.Subnetwork = subnetworkLink 465 466 accessConfigsCount := d.Get(prefix + ".access_config.#").(int) 467 iface.AccessConfigs = make([]*compute.AccessConfig, accessConfigsCount) 468 for j := 0; j < accessConfigsCount; j++ { 469 acPrefix := fmt.Sprintf("%s.access_config.%d", prefix, j) 470 iface.AccessConfigs[j] = &compute.AccessConfig{ 471 Type: "ONE_TO_ONE_NAT", 472 NatIP: d.Get(acPrefix + ".nat_ip").(string), 473 } 474 } 475 476 networkInterfaces = append(networkInterfaces, &iface) 477 } 478 return networkInterfaces, nil 479 } 480 481 func resourceComputeInstanceTemplateCreate(d *schema.ResourceData, meta interface{}) error { 482 config := meta.(*Config) 483 484 project, err := getProject(d, config) 485 if err != nil { 486 return err 487 } 488 489 instanceProperties := &compute.InstanceProperties{} 490 491 instanceProperties.CanIpForward = d.Get("can_ip_forward").(bool) 492 instanceProperties.Description = d.Get("instance_description").(string) 493 instanceProperties.MachineType = d.Get("machine_type").(string) 494 disks, err := buildDisks(d, meta) 495 if err != nil { 496 return err 497 } 498 instanceProperties.Disks = disks 499 500 metadata, err := resourceInstanceMetadata(d) 501 if err != nil { 502 return err 503 } 504 instanceProperties.Metadata = metadata 505 networks, err := buildNetworks(d, meta) 506 if err != nil { 507 return err 508 } 509 instanceProperties.NetworkInterfaces = networks 510 511 instanceProperties.Scheduling = &compute.Scheduling{} 512 instanceProperties.Scheduling.OnHostMaintenance = "MIGRATE" 513 514 // Depreciated fields 515 if v, ok := d.GetOk("automatic_restart"); ok { 516 instanceProperties.Scheduling.AutomaticRestart = v.(bool) 517 } 518 519 if v, ok := d.GetOk("on_host_maintenance"); ok { 520 instanceProperties.Scheduling.OnHostMaintenance = v.(string) 521 } 522 523 forceSendFieldsScheduling := make([]string, 0, 3) 524 var hasSendMaintenance bool 525 hasSendMaintenance = false 526 if v, ok := d.GetOk("scheduling"); ok { 527 _schedulings := v.([]interface{}) 528 if len(_schedulings) > 1 { 529 return fmt.Errorf("Error, at most one `scheduling` block can be defined") 530 } 531 _scheduling := _schedulings[0].(map[string]interface{}) 532 533 if vp, okp := _scheduling["automatic_restart"]; okp { 534 instanceProperties.Scheduling.AutomaticRestart = vp.(bool) 535 forceSendFieldsScheduling = append(forceSendFieldsScheduling, "AutomaticRestart") 536 } 537 538 if vp, okp := _scheduling["on_host_maintenance"]; okp { 539 instanceProperties.Scheduling.OnHostMaintenance = vp.(string) 540 forceSendFieldsScheduling = append(forceSendFieldsScheduling, "OnHostMaintenance") 541 hasSendMaintenance = true 542 } 543 544 if vp, okp := _scheduling["preemptible"]; okp { 545 instanceProperties.Scheduling.Preemptible = vp.(bool) 546 forceSendFieldsScheduling = append(forceSendFieldsScheduling, "Preemptible") 547 if vp.(bool) && !hasSendMaintenance { 548 instanceProperties.Scheduling.OnHostMaintenance = "TERMINATE" 549 forceSendFieldsScheduling = append(forceSendFieldsScheduling, "OnHostMaintenance") 550 } 551 } 552 } 553 instanceProperties.Scheduling.ForceSendFields = forceSendFieldsScheduling 554 555 serviceAccountsCount := d.Get("service_account.#").(int) 556 serviceAccounts := make([]*compute.ServiceAccount, 0, serviceAccountsCount) 557 for i := 0; i < serviceAccountsCount; i++ { 558 prefix := fmt.Sprintf("service_account.%d", i) 559 560 scopesCount := d.Get(prefix + ".scopes.#").(int) 561 scopes := make([]string, 0, scopesCount) 562 for j := 0; j < scopesCount; j++ { 563 scope := d.Get(fmt.Sprintf(prefix+".scopes.%d", j)).(string) 564 scopes = append(scopes, canonicalizeServiceScope(scope)) 565 } 566 567 email := "default" 568 if v := d.Get(prefix + ".email"); v != nil { 569 email = v.(string) 570 } 571 572 serviceAccount := &compute.ServiceAccount{ 573 Email: email, 574 Scopes: scopes, 575 } 576 577 serviceAccounts = append(serviceAccounts, serviceAccount) 578 } 579 instanceProperties.ServiceAccounts = serviceAccounts 580 581 instanceProperties.Tags = resourceInstanceTags(d) 582 583 var itName string 584 if v, ok := d.GetOk("name"); ok { 585 itName = v.(string) 586 } else if v, ok := d.GetOk("name_prefix"); ok { 587 itName = resource.PrefixedUniqueId(v.(string)) 588 } else { 589 itName = resource.UniqueId() 590 } 591 instanceTemplate := compute.InstanceTemplate{ 592 Description: d.Get("description").(string), 593 Properties: instanceProperties, 594 Name: itName, 595 } 596 597 op, err := config.clientCompute.InstanceTemplates.Insert( 598 project, &instanceTemplate).Do() 599 if err != nil { 600 return fmt.Errorf("Error creating instance: %s", err) 601 } 602 603 // Store the ID now 604 d.SetId(instanceTemplate.Name) 605 606 err = computeOperationWaitGlobal(config, op, project, "Creating Instance Template") 607 if err != nil { 608 return err 609 } 610 611 return resourceComputeInstanceTemplateRead(d, meta) 612 } 613 614 func flattenDisks(disks []*compute.AttachedDisk, d *schema.ResourceData) []map[string]interface{} { 615 result := make([]map[string]interface{}, 0, len(disks)) 616 for i, disk := range disks { 617 diskMap := make(map[string]interface{}) 618 if disk.InitializeParams != nil { 619 var source_img = fmt.Sprintf("disk.%d.source_image", i) 620 if d.Get(source_img) == nil || d.Get(source_img) == "" { 621 sourceImageUrl := strings.Split(disk.InitializeParams.SourceImage, "/") 622 diskMap["source_image"] = sourceImageUrl[len(sourceImageUrl)-1] 623 } else { 624 diskMap["source_image"] = d.Get(source_img) 625 } 626 diskMap["disk_type"] = disk.InitializeParams.DiskType 627 diskMap["disk_name"] = disk.InitializeParams.DiskName 628 diskMap["disk_size_gb"] = disk.InitializeParams.DiskSizeGb 629 } 630 diskMap["auto_delete"] = disk.AutoDelete 631 diskMap["boot"] = disk.Boot 632 diskMap["device_name"] = disk.DeviceName 633 diskMap["interface"] = disk.Interface 634 diskMap["source"] = disk.Source 635 diskMap["mode"] = disk.Mode 636 diskMap["type"] = disk.Type 637 result = append(result, diskMap) 638 } 639 return result 640 } 641 642 func flattenNetworkInterfaces(networkInterfaces []*compute.NetworkInterface) ([]map[string]interface{}, string) { 643 result := make([]map[string]interface{}, 0, len(networkInterfaces)) 644 region := "" 645 for _, networkInterface := range networkInterfaces { 646 networkInterfaceMap := make(map[string]interface{}) 647 if networkInterface.Network != "" { 648 networkUrl := strings.Split(networkInterface.Network, "/") 649 networkInterfaceMap["network"] = networkUrl[len(networkUrl)-1] 650 } 651 if networkInterface.Subnetwork != "" { 652 subnetworkUrl := strings.Split(networkInterface.Subnetwork, "/") 653 networkInterfaceMap["subnetwork"] = subnetworkUrl[len(subnetworkUrl)-1] 654 region = subnetworkUrl[len(subnetworkUrl)-3] 655 networkInterfaceMap["subnetwork_project"] = subnetworkUrl[len(subnetworkUrl)-5] 656 } 657 658 if networkInterface.AccessConfigs != nil { 659 accessConfigsMap := make([]map[string]interface{}, 0, len(networkInterface.AccessConfigs)) 660 for _, accessConfig := range networkInterface.AccessConfigs { 661 accessConfigMap := make(map[string]interface{}) 662 accessConfigMap["nat_ip"] = accessConfig.NatIP 663 664 accessConfigsMap = append(accessConfigsMap, accessConfigMap) 665 } 666 networkInterfaceMap["access_config"] = accessConfigsMap 667 } 668 result = append(result, networkInterfaceMap) 669 } 670 return result, region 671 } 672 673 func flattenScheduling(scheduling *compute.Scheduling) ([]map[string]interface{}, bool) { 674 result := make([]map[string]interface{}, 0, 1) 675 schedulingMap := make(map[string]interface{}) 676 schedulingMap["automatic_restart"] = scheduling.AutomaticRestart 677 schedulingMap["on_host_maintenance"] = scheduling.OnHostMaintenance 678 schedulingMap["preemptible"] = scheduling.Preemptible 679 result = append(result, schedulingMap) 680 return result, scheduling.AutomaticRestart 681 } 682 683 func flattenServiceAccounts(serviceAccounts []*compute.ServiceAccount) []map[string]interface{} { 684 result := make([]map[string]interface{}, 0, len(serviceAccounts)) 685 for _, serviceAccount := range serviceAccounts { 686 serviceAccountMap := make(map[string]interface{}) 687 serviceAccountMap["email"] = serviceAccount.Email 688 serviceAccountMap["scopes"] = serviceAccount.Scopes 689 690 result = append(result, serviceAccountMap) 691 } 692 return result 693 } 694 695 func flattenMetadata(metadata *compute.Metadata) map[string]string { 696 metadataMap := make(map[string]string) 697 for _, item := range metadata.Items { 698 metadataMap[item.Key] = *item.Value 699 } 700 return metadataMap 701 } 702 703 func resourceComputeInstanceTemplateRead(d *schema.ResourceData, meta interface{}) error { 704 config := meta.(*Config) 705 project, err := getProject(d, config) 706 if err != nil { 707 return err 708 } 709 710 instanceTemplate, err := config.clientCompute.InstanceTemplates.Get( 711 project, d.Id()).Do() 712 if err != nil { 713 if gerr, ok := err.(*googleapi.Error); ok && gerr.Code == 404 { 714 log.Printf("[WARN] Removing Instance Template %q because it's gone", d.Get("name").(string)) 715 // The resource doesn't exist anymore 716 d.SetId("") 717 return nil 718 } 719 720 return fmt.Errorf("Error reading instance template: %s", err) 721 } 722 723 // Set the metadata fingerprint if there is one. 724 if instanceTemplate.Properties.Metadata != nil { 725 if err = d.Set("metadata_fingerprint", instanceTemplate.Properties.Metadata.Fingerprint); err != nil { 726 return fmt.Errorf("Error setting metadata_fingerprint: %s", err) 727 } 728 729 md := instanceTemplate.Properties.Metadata 730 731 _md := flattenMetadata(md) 732 733 if script, scriptExists := d.GetOk("metadata_startup_script"); scriptExists { 734 if err = d.Set("metadata_startup_script", script); err != nil { 735 return fmt.Errorf("Error setting metadata_startup_script: %s", err) 736 } 737 delete(_md, "startup-script") 738 } 739 if err = d.Set("metadata", _md); err != nil { 740 return fmt.Errorf("Error setting metadata: %s", err) 741 } 742 } 743 744 // Set the tags fingerprint if there is one. 745 if instanceTemplate.Properties.Tags != nil { 746 if err = d.Set("tags_fingerprint", instanceTemplate.Properties.Tags.Fingerprint); err != nil { 747 return fmt.Errorf("Error setting tags_fingerprint: %s", err) 748 } 749 } 750 if err = d.Set("self_link", instanceTemplate.SelfLink); err != nil { 751 return fmt.Errorf("Error setting self_link: %s", err) 752 } 753 if err = d.Set("name", instanceTemplate.Name); err != nil { 754 return fmt.Errorf("Error setting name: %s", err) 755 } 756 if instanceTemplate.Properties.Disks != nil { 757 if err = d.Set("disk", flattenDisks(instanceTemplate.Properties.Disks, d)); err != nil { 758 return fmt.Errorf("Error setting disk: %s", err) 759 } 760 } 761 if err = d.Set("description", instanceTemplate.Description); err != nil { 762 return fmt.Errorf("Error setting description: %s", err) 763 } 764 if err = d.Set("machine_type", instanceTemplate.Properties.MachineType); err != nil { 765 return fmt.Errorf("Error setting machine_type: %s", err) 766 } 767 768 if err = d.Set("can_ip_forward", instanceTemplate.Properties.CanIpForward); err != nil { 769 return fmt.Errorf("Error setting can_ip_forward: %s", err) 770 } 771 772 if err = d.Set("instance_description", instanceTemplate.Properties.Description); err != nil { 773 return fmt.Errorf("Error setting instance_description: %s", err) 774 } 775 if err = d.Set("project", project); err != nil { 776 return fmt.Errorf("Error setting project: %s", err) 777 } 778 if instanceTemplate.Properties.NetworkInterfaces != nil { 779 networkInterfaces, region := flattenNetworkInterfaces(instanceTemplate.Properties.NetworkInterfaces) 780 if err = d.Set("network_interface", networkInterfaces); err != nil { 781 return fmt.Errorf("Error setting network_interface: %s", err) 782 } 783 // region is where to look up the subnetwork if there is one attached to the instance template 784 if region != "" { 785 if err = d.Set("region", region); err != nil { 786 return fmt.Errorf("Error setting region: %s", err) 787 } 788 } 789 } 790 if instanceTemplate.Properties.Scheduling != nil { 791 scheduling, autoRestart := flattenScheduling(instanceTemplate.Properties.Scheduling) 792 if err = d.Set("scheduling", scheduling); err != nil { 793 return fmt.Errorf("Error setting scheduling: %s", err) 794 } 795 if err = d.Set("automatic_restart", autoRestart); err != nil { 796 return fmt.Errorf("Error setting automatic_restart: %s", err) 797 } 798 } 799 if instanceTemplate.Properties.Tags != nil { 800 if err = d.Set("tags", instanceTemplate.Properties.Tags.Items); err != nil { 801 return fmt.Errorf("Error setting tags: %s", err) 802 } 803 } 804 if instanceTemplate.Properties.ServiceAccounts != nil { 805 if err = d.Set("service_account", flattenServiceAccounts(instanceTemplate.Properties.ServiceAccounts)); err != nil { 806 return fmt.Errorf("Error setting service_account: %s", err) 807 } 808 } 809 return nil 810 } 811 812 func resourceComputeInstanceTemplateDelete(d *schema.ResourceData, meta interface{}) error { 813 config := meta.(*Config) 814 815 project, err := getProject(d, config) 816 if err != nil { 817 return err 818 } 819 820 op, err := config.clientCompute.InstanceTemplates.Delete( 821 project, d.Id()).Do() 822 if err != nil { 823 return fmt.Errorf("Error deleting instance template: %s", err) 824 } 825 826 err = computeOperationWaitGlobal(config, op, project, "Deleting Instance Template") 827 if err != nil { 828 return err 829 } 830 831 d.SetId("") 832 return nil 833 }