mirror of
https://github.com/letic/terraform-provider-google.git
synced 2024-10-06 18:51:13 +00:00
Fix perma-diff on instance templates.
When using instance templates, if you use one of our image shorthands at the moment, you'll get a perma-diff. This is because the config gets resolved to another format before it is set in state, and so we need to set that other format in state. Unfortunately, resolving images requires network access, so we have to do this with CustomizeDiff. CustomizeDiff was having trouble (I think? More on this below) on setting a field as not ForceNew once the field was already set, so I moved the decision for whether a field was ForceNew or not into CustomizeDiff. I also resolved the old and new images, and if they were the same, cleared the diff. Unfortunately, you can't actually clear a field on a sub-block right now. You have to clear top-level fields only. So this will currently throw an error. I opened hashicorp/terraform#18795 to fix that. Once that's merged, and we vendor it here, this patch fixes the problem. If hashicorp/terraform#18795 doesn't get merged, the next best workaround is to keep track of _all_ the fields under `disk` with a diff in our CustomizeDiff, check whether they've all changed or not, and if they've all changed, clear the changes on `disk`, which I _think_ will resolve the issue. That's just a massive pain, unfortunately.
This commit is contained in:
parent
7911cab2e4
commit
5cf6a5d131
@ -20,6 +20,7 @@ func resourceComputeInstanceTemplate() *schema.Resource {
|
|||||||
State: schema.ImportStatePassthrough,
|
State: schema.ImportStatePassthrough,
|
||||||
},
|
},
|
||||||
SchemaVersion: 1,
|
SchemaVersion: 1,
|
||||||
|
CustomizeDiff: resourceComputeInstanceTemplateCustomizeDiff,
|
||||||
MigrateState: resourceComputeInstanceTemplateMigrateState,
|
MigrateState: resourceComputeInstanceTemplateMigrateState,
|
||||||
|
|
||||||
// A compute instance template is more or less a subset of a compute
|
// A compute instance template is more or less a subset of a compute
|
||||||
@ -101,8 +102,7 @@ func resourceComputeInstanceTemplate() *schema.Resource {
|
|||||||
"source_image": &schema.Schema{
|
"source_image": &schema.Schema{
|
||||||
Type: schema.TypeString,
|
Type: schema.TypeString,
|
||||||
Optional: true,
|
Optional: true,
|
||||||
DiffSuppressFunc: compareSelfLinkRelativePaths,
|
Computed: true,
|
||||||
ForceNew: true,
|
|
||||||
},
|
},
|
||||||
|
|
||||||
"interface": &schema.Schema{
|
"interface": &schema.Schema{
|
||||||
@ -420,6 +420,48 @@ func resourceComputeInstanceTemplate() *schema.Resource {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func resourceComputeInstanceTemplateCustomizeDiff(diff *schema.ResourceDiff, meta interface{}) error {
|
||||||
|
config := meta.(*Config)
|
||||||
|
project, err := getProjectFromDiff(diff, config)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
numDisks := diff.Get("disk.#").(int)
|
||||||
|
for i := 0; i < numDisks; i++ {
|
||||||
|
key := fmt.Sprintf("disk.%d.source_image", i)
|
||||||
|
if diff.HasChange(key) {
|
||||||
|
old, new := diff.GetChange(key)
|
||||||
|
if old == "" || new == "" {
|
||||||
|
// no sense in resolving empty strings
|
||||||
|
err = diff.ForceNew(key)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
oldResolved, err := resolveImage(config, project, old.(string))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
newResolved, err := resolveImage(config, project, new.(string))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if oldResolved != newResolved {
|
||||||
|
err = diff.ForceNew(key)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
err = diff.Clear(key)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func buildDisks(d *schema.ResourceData, config *Config) ([]*computeBeta.AttachedDisk, error) {
|
func buildDisks(d *schema.ResourceData, config *Config) ([]*computeBeta.AttachedDisk, error) {
|
||||||
project, err := getProject(d, config)
|
project, err := getProject(d, config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -64,6 +64,20 @@ func getProject(d TerraformResourceData, config *Config) (string, error) {
|
|||||||
return getProjectFromSchema("project", d, config)
|
return getProjectFromSchema("project", d, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getProjectFromDiff reads the "project" field from the given diff and falls
|
||||||
|
// back to the provider's value if not given. If the provider's value is not
|
||||||
|
// given, an error is returned.
|
||||||
|
func getProjectFromDiff(d *schema.ResourceDiff, config *Config) (string, error) {
|
||||||
|
res, ok := d.GetOk("project")
|
||||||
|
if ok {
|
||||||
|
return res.(string), nil
|
||||||
|
}
|
||||||
|
if config.Project != "" {
|
||||||
|
return config.Project, nil
|
||||||
|
}
|
||||||
|
return "", fmt.Errorf("%s: required field is not set", "project")
|
||||||
|
}
|
||||||
|
|
||||||
func getProjectFromInstanceState(is *terraform.InstanceState, config *Config) (string, error) {
|
func getProjectFromInstanceState(is *terraform.InstanceState, config *Config) (string, error) {
|
||||||
res, ok := is.Attributes["project"]
|
res, ok := is.Attributes["project"]
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user