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