Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

id of instance templates now relies on the unique id of the resource #7358

Merged
merged 1 commit into from
Mar 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,22 @@ func DataSourceGoogleComputeInstanceTemplate() *schema.Resource {
Type: schema.TypeString,
Optional: true,
}
dsSchema["self_link_unique"] = &schema.Schema{
Type: schema.TypeString,
Optional: true,
}
dsSchema["most_recent"] = &schema.Schema{
Type: schema.TypeBool,
Optional: true,
}

// Set 'Optional' schema elements
addOptionalFieldsToSchema(dsSchema, "name", "filter", "most_recent", "project")
addOptionalFieldsToSchema(dsSchema, "name", "filter", "most_recent", "project", "self_link_unique")

dsSchema["name"].ExactlyOneOf = []string{"name", "filter"}
dsSchema["filter"].ExactlyOneOf = []string{"name", "filter"}
mutuallyExclusive:= []string{"name", "filter", "self_link_unique"}
for _, n:= range mutuallyExclusive {
dsSchema[n].ExactlyOneOf = mutuallyExclusive
}

return &schema.Resource{
Read: datasourceComputeInstanceTemplateRead,
Expand Down Expand Up @@ -73,8 +79,11 @@ func datasourceComputeInstanceTemplateRead(d *schema.ResourceData, meta interfac

return fmt.Errorf("your filter has returned %d instance template(s). Please refine your filter or set most_recent to return exactly one instance template", len(templates.Items))
}
if v, ok := d.GetOk("self_link_unique"); ok {
return retrieveInstanceFromUniqueId(d, meta, project, v.(string))
}

return fmt.Errorf("one of name or filters must be set")
return fmt.Errorf("one of name, filters or self_link_unique must be set")
}

func retrieveInstance(d *schema.ResourceData, meta interface{}, project, name string) error {
Expand All @@ -83,6 +92,14 @@ func retrieveInstance(d *schema.ResourceData, meta interface{}, project, name st
return resourceComputeInstanceTemplateRead(d, meta)
}

func retrieveInstanceFromUniqueId(d *schema.ResourceData, meta interface{}, project, self_link_unique string) error {
normalId, _ := parseUniqueId(self_link_unique)
d.SetId(normalId)
d.Set("self_link_unique", self_link_unique)
irsl marked this conversation as resolved.
Show resolved Hide resolved

return resourceComputeInstanceTemplateRead(d, meta)
}

// ByCreationTimestamp implements sort.Interface for []*InstanceTemplate based on
// the CreationTimestamp field.
type ByCreationTimestamp []*compute.InstanceTemplate
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,7 @@ func resourceComputeInstanceFromTemplateCreate(d *schema.ResourceData, meta inte
return err
}

sourceInstanceTemplate := d.Get("source_instance_template").(string)

sourceInstanceTemplate:= ConvertToUniqueIdWhenPresent(d.Get("source_instance_template").(string))
tpl, err := ParseInstanceTemplateFieldValue(sourceInstanceTemplate, d, config)
if err != nil {
return err
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ func ResourceComputeInstanceGroupManager() *schema.Resource {
"instance_template": {
Type: schema.TypeString,
Required: true,
DiffSuppressFunc: compareSelfLinkRelativePaths,
DiffSuppressFunc: compareSelfLinkRelativePathsIgnoreParams,
Description: `The full URL to an instance template from which all new instances of this version will be created.`,
},

Expand Down Expand Up @@ -495,6 +495,33 @@ func ResourceComputeInstanceGroupManager() *schema.Resource {
}
}

func parseUniqueId(s string) (string, string) {
splits:= strings.SplitN(s, "?uniqueId=", 2)
irsl marked this conversation as resolved.
Show resolved Hide resolved
if len(splits) == 2 {
return splits[0], splits[1]
}
return s, ""
}

func compareSelfLinkRelativePathsIgnoreParams(_unused1, old, new string, _unused2 *schema.ResourceData) bool {
oldName, oldUniqueId:= parseUniqueId(old)
newName, newUniqueId:= parseUniqueId(new)
if oldUniqueId != "" && newUniqueId != "" && oldUniqueId != newUniqueId {
return false
}
return compareSelfLinkRelativePaths(_unused1, oldName, newName, _unused2)
}

func ConvertToUniqueIdWhenPresent(s string) string {
original, uniqueId:= parseUniqueId(s)
if uniqueId != "" {
splits:= strings.Split(original, "/")
splits[len(splits)-1] = uniqueId
return strings.Join(splits, "/")
}
return s
}

func getNamedPorts(nps []interface{}) []*compute.NamedPort {
namedPorts := make([]*compute.NamedPort, 0, len(nps))
for _, v := range nps {
Expand Down Expand Up @@ -1160,7 +1187,7 @@ func expandVersions(configured []interface{}) []*compute.InstanceGroupManagerVer

version := compute.InstanceGroupManagerVersion{
Name: data["name"].(string),
InstanceTemplate: data["instance_template"].(string),
InstanceTemplate: ConvertToUniqueIdWhenPresent(data["instance_template"].(string)),
TargetSize: expandFixedOrPercent(data["target_size"].([]interface{})),
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -670,6 +670,12 @@ be from 0 to 999,999,999 inclusive.`,
Description: `The URI of the created resource.`,
},

"self_link_unique": {
Type: schema.TypeString,
Computed: true,
Description: `A special URI of the created resource that uniquely identifies this instance template.`,
},

"service_account": {
Type: schema.TypeList,
MaxItems: 1,
Expand Down Expand Up @@ -1256,6 +1262,8 @@ func resourceComputeInstanceTemplateCreate(d *schema.ResourceData, meta interfac

// Store the ID now
d.SetId(fmt.Sprintf("projects/%s/global/instanceTemplates/%s", project, instanceTemplate.Name))
// And also the unique ID
d.Set("self_link_unique", fmt.Sprintf("%v?uniqueId=%v", d.Id(), op.TargetId))

err = ComputeOperationWaitTime(config, op, project, "Creating Instance Template", userAgent, d.Timeout(schema.TimeoutCreate))
if err != nil {
Expand Down Expand Up @@ -1498,12 +1506,16 @@ func resourceComputeInstanceTemplateRead(d *schema.ResourceData, meta interface{
return err
}

splits := strings.Split(d.Id(), "/")
idStr := d.Id()
if v, ok := d.GetOk("self_link_unique"); ok && v != "" {
idStr = ConvertToUniqueIdWhenPresent(v.(string))
}

splits := strings.Split(idStr, "/")
instanceTemplate, err := config.NewComputeClient(userAgent).InstanceTemplates.Get(project, splits[len(splits)-1]).Do()
if err != nil {
return handleNotFoundError(err, d, fmt.Sprintf("Instance Template %q", d.Get("name").(string)))
}

// Set the metadata fingerprint if there is one.
if instanceTemplate.Properties.Metadata != nil {
if err = d.Set("metadata_fingerprint", instanceTemplate.Properties.Metadata.Fingerprint); err != nil {
Expand Down Expand Up @@ -1545,6 +1557,9 @@ func resourceComputeInstanceTemplateRead(d *schema.ResourceData, meta interface{
if err = d.Set("self_link", instanceTemplate.SelfLink); err != nil {
return fmt.Errorf("Error setting self_link: %s", err)
}
if err = d.Set("self_link_unique", fmt.Sprintf("%v?uniqueId=%v", instanceTemplate.SelfLink, instanceTemplate.Id)); err != nil {
return fmt.Errorf("Error setting self_link_unique: %s", err)
}
if err = d.Set("name", instanceTemplate.Name); err != nil {
return fmt.Errorf("Error setting name: %s", err)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ func ResourceComputeRegionInstanceGroupManager() *schema.Resource {
"instance_template": {
Type: schema.TypeString,
Required: true,
DiffSuppressFunc: compareSelfLinkRelativePaths,
DiffSuppressFunc: compareSelfLinkRelativePathsIgnoreParams,
Description: `The full URL to an instance template from which all new instances of this version will be created.`,
},

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,31 @@ func TestAccInstanceTemplateDatasource_filter_mostRecent(t *testing.T) {
})
}

func TestAccInstanceTemplateDatasource_self_link_unique(t *testing.T) {
t.Parallel()

VcrTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: TestAccProviders,
Steps: []resource.TestStep{
{
Config: testAccInstanceTemplate_self_link_unique(GetTestProjectFromEnv(), RandString(t, 10)),
Check: resource.ComposeTestCheckFunc(
checkDataSourceStateMatchesResourceStateWithIgnores(
"data.google_compute_instance_template.default",
"google_compute_instance_template.default",
// we don't compare the id here as we start this test from a self_link_unique url
// and the resource's ID will have the standard format project/projectname/global/instanceTemplates/tf-test-template-random
map[string]struct{}{
"id": {},
},
),
),
},
},
})
}

func testAccInstanceTemplate_name(project, suffix string) string {
return Nprintf(`
resource "google_compute_instance_template" "default" {
Expand Down Expand Up @@ -238,3 +263,31 @@ data "google_compute_instance_template" "default" {
}
`, map[string]interface{}{"project": project, "suffix": suffix})
}

func testAccInstanceTemplate_self_link_unique(project, suffix string) string {
return Nprintf(`
resource "google_compute_instance_template" "default" {
name = "tf-test-template-%{suffix}"
description = "Example template."

machine_type = "e2-small"

tags = ["foo", "bar"]

disk {
source_image = "cos-cloud/cos-stable"
auto_delete = true
boot = true
}

network_interface {
network = "default"
}
}

data "google_compute_instance_template" "default" {
project = "%{project}"
self_link_unique = google_compute_instance_template.default.self_link_unique
}
`, map[string]interface{}{"project": project, "suffix": suffix})
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,34 @@ func TestAccComputeInstanceFromTemplate_basic(t *testing.T) {
})
}

func TestAccComputeInstanceFromTemplate_self_link_unique(t *testing.T) {
t.Parallel()

var instance compute.Instance
instanceName := fmt.Sprintf("tf-test-%s", RandString(t, 10))
templateName := fmt.Sprintf("tf-test-%s", RandString(t, 10))
resourceName := "google_compute_instance_from_template.foobar"

VcrTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: TestAccProviders,
CheckDestroy: testAccCheckComputeInstanceFromTemplateDestroyProducer(t),
Steps: []resource.TestStep{
{
Config: testAccComputeInstanceFromTemplate_self_link_unique(instanceName, templateName),
Check: resource.ComposeTestCheckFunc(
testAccCheckComputeInstanceExists(t, resourceName, &instance),

// Check that fields were set based on the template
resource.TestCheckResourceAttr(resourceName, "machine_type", "n1-standard-1"),
resource.TestCheckResourceAttr(resourceName, "attached_disk.#", "1"),
resource.TestCheckResourceAttr(resourceName, "scheduling.0.automatic_restart", "false"),
),
},
},
})
}

func TestAccComputeInstanceFromRegionTemplate_basic(t *testing.T) {
t.Parallel()

Expand Down Expand Up @@ -418,6 +446,80 @@ resource "google_compute_instance_from_template" "foobar" {
`, template, template, instance)
}

func testAccComputeInstanceFromTemplate_self_link_unique(instance, template string) string {
return fmt.Sprintf(`
data "google_compute_image" "my_image" {
family = "debian-11"
project = "debian-cloud"
}

resource "google_compute_disk" "foobar" {
name = "%s"
image = data.google_compute_image.my_image.self_link
size = 10
type = "pd-ssd"
zone = "us-central1-a"
}

resource "google_compute_instance_template" "foobar" {
name = "%s"
machine_type = "n1-standard-1" // can't be e2 because of local-ssd

disk {
source = google_compute_disk.foobar.name
auto_delete = false
boot = true
}

disk {
disk_type = "local-ssd"
type = "SCRATCH"
interface = "NVME"
disk_size_gb = 375
}

disk {
source_image = data.google_compute_image.my_image.self_link
auto_delete = true
disk_size_gb = 100
boot = false
disk_type = "pd-ssd"
type = "PERSISTENT"
}

network_interface {
network = "default"
}

metadata = {
foo = "bar"
}

scheduling {
automatic_restart = true
}

can_ip_forward = true
}

resource "google_compute_instance_from_template" "foobar" {
name = "%s"
zone = "us-central1-a"

source_instance_template = google_compute_instance_template.foobar.self_link_unique

// Overrides
can_ip_forward = false
labels = {
my_key = "my_value"
}
scheduling {
automatic_restart = false
}
}
`, template, template, instance)
}

func testAccComputeInstanceFromTemplate_overrideBootDisk(templateDisk, overrideDisk, template, instance string) string {
return fmt.Sprintf(`
data "google_compute_image" "my_image" {
Expand Down
Loading