From cc5e4803782f20464c82b96edb09dcf538eae1ae Mon Sep 17 00:00:00 2001 From: Martin Atkins Date: Tue, 21 Nov 2017 16:22:55 -0800 Subject: [PATCH] config: detect and warn about access to "counted" attributes A common pattern is to conditionally assign to "count" in a resource in order to decide dynamically whether it should be created. In that situation it's necessary to refer to attributes of the resource using the splat syntax, but historically we didn't show errors in output expressions and so people "got away with" incorrect usage in that context. The intent of this warning is to catch potentially-problematic usage of attributes on such resources even if the count happens to be currently set dynamically to 1, which would not generate the error. Then the user can quickly locate and fix the incorrect usage regardless of the current value. --- config/config.go | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/config/config.go b/config/config.go index f77ca475c..62f265844 100644 --- a/config/config.go +++ b/config/config.go @@ -814,6 +814,52 @@ func (c *Config) Validate() tfdiags.Diagnostics { } } + // Detect a common mistake of using a "count"ed resource in + // an output value without using the splat or index form. + // Prior to 0.11 this error was silently ignored, but outputs + // now have their errors checked like all other contexts. + // + // TODO: Remove this in 0.12. + for _, v := range o.RawConfig.Variables { + rv, ok := v.(*ResourceVariable) + if !ok { + continue + } + + // If the variable seems to be treating the referenced + // resource as a singleton (no count specified) then + // we'll check to make sure it is indeed a singleton. + // It's a warning if not. + + if rv.Multi || rv.Index != 0 { + // This reference is treating the resource as a + // multi-resource, so the warning doesn't apply. + continue + } + + for _, r := range c.Resources { + if r.Id() != rv.ResourceId() { + continue + } + + // We test specifically for the raw string "1" here + // because we _do_ want to generate this warning if + // the user has provided an expression that happens + // to return 1 right now, to catch situations where + // a count might dynamically be set to something + // other than 1 and thus splat syntax is still needed + // to be safe. + if r.RawCount != nil && r.RawCount.Raw != nil && r.RawCount.Raw["count"] != "1" { + diags = diags.Append(tfdiags.SimpleWarning(fmt.Sprintf( + "output %q: must use splat syntax to access %s attribute %q, because it has \"count\" set; use %s.*.%s to obtain a list of the attributes across all instances", + o.Name, + r.Id(), rv.Field, + r.Id(), rv.Field, + ))) + } + } + } + } }