|
15 | 15 | package tfsandbox
|
16 | 16 |
|
17 | 17 | import (
|
| 18 | + "fmt" |
18 | 19 | "strings"
|
19 | 20 |
|
20 | 21 | tfjson "github.com/hashicorp/terraform-json"
|
@@ -188,43 +189,46 @@ func unknown() resource.PropertyValue {
|
188 | 189 | })
|
189 | 190 | }
|
190 | 191 |
|
191 |
| -// secretUnknown returns true if the value is a secret and the secret value is unknown. |
192 |
| -func secretUnknown(value resource.PropertyValue) bool { |
193 |
| - if value.IsSecret() { |
194 |
| - secret := value.SecretValue() |
195 |
| - if secret != nil && secret.Element.IsComputed() { |
196 |
| - return true |
| 192 | +// isInternalOutputResource returns true if the resource is an internal is_secret output |
| 193 | +// which is used to keep track of the secretness of the output. |
| 194 | +func isInternalOutputResource(name string) bool { |
| 195 | + return strings.HasPrefix(name, terraformIsSecretOutputPrefix) |
| 196 | +} |
| 197 | + |
| 198 | +// outputIsSecret returns true if the output is a secret based on the value of the |
| 199 | +// corresponding is_secret output. |
| 200 | +func (p *Plan) outputIsSecret(outputName string) bool { |
| 201 | + isSecretKey := fmt.Sprintf("%s%s", terraformIsSecretOutputPrefix, outputName) |
| 202 | + if isSecretVal, ok := p.rawPlan.OutputChanges[isSecretKey]; ok { |
| 203 | + // If the value is unknown, just return false because we don't know the value |
| 204 | + // so secretness doesn't matter yet |
| 205 | + if afterUnknown, ok := isSecretVal.AfterUnknown.(bool); ok && afterUnknown { |
| 206 | + return false |
197 | 207 | }
|
| 208 | + return isSecretVal.After.(bool) |
198 | 209 | }
|
199 |
| - |
| 210 | + contract.Failf("isSecret key %q not found in output changes", isSecretKey) |
200 | 211 | return false
|
201 | 212 | }
|
202 | 213 |
|
203 |
| -// IsInternalOutputResource returns true if the resource is an internal output resource. |
204 |
| -// which is used to expose outputs from the source module in a way that maintains unknown-ness |
205 |
| -// and secretness of the outputs. |
206 |
| -func (p *ResourcePlan) IsInternalOutputResource() bool { |
207 |
| - return strings.HasPrefix(p.Name(), terraformDataResourcePrefix) |
208 |
| -} |
209 |
| - |
210 | 214 | // Outputs returns the outputs of a terraform plan as a Pulumi property map.
|
211 | 215 | func (p *Plan) Outputs() resource.PropertyMap {
|
212 | 216 | outputs := resource.PropertyMap{}
|
213 |
| - p.Resources.VisitResources(func(res *ResourcePlan) { |
214 |
| - if res.IsInternalOutputResource() { |
215 |
| - withoutPrefix := strings.TrimPrefix(res.Name(), terraformDataResourcePrefix) |
216 |
| - outputKey := resource.PropertyKey(withoutPrefix) |
217 |
| - plannedValues := res.PlannedValues() |
218 |
| - if v, ok := plannedValues[resource.PropertyKey("input")]; ok { |
219 |
| - if secretUnknown(v) { |
220 |
| - // collapse secret unknowns into just unknown |
221 |
| - outputs[outputKey] = unknown() |
222 |
| - } else { |
223 |
| - outputs[outputKey] = v |
224 |
| - } |
| 217 | + for outputKey, output := range p.rawPlan.OutputChanges { |
| 218 | + if isInternalOutputResource(outputKey) { |
| 219 | + continue |
| 220 | + } |
| 221 | + key := resource.PropertyKey(outputKey) |
| 222 | + if afterUnknown, ok := output.AfterUnknown.(bool); ok && afterUnknown { |
| 223 | + outputs[key] = unknown() |
| 224 | + } else { |
| 225 | + val := resource.NewPropertyValueRepl(output.After, nil, replaceJSONNumberValue) |
| 226 | + if p.outputIsSecret(outputKey) { |
| 227 | + val = resource.MakeSecret(val) |
225 | 228 | }
|
| 229 | + outputs[key] = val |
226 | 230 | }
|
227 |
| - }) |
| 231 | + } |
228 | 232 | return outputs
|
229 | 233 | }
|
230 | 234 |
|
@@ -260,26 +264,31 @@ func newState(rawState *tfjson.State) (*State, error) {
|
260 | 264 | }, nil
|
261 | 265 | }
|
262 | 266 |
|
263 |
| -// IsInternalOutputResource returns true if the resource is an internal output resource. |
264 |
| -// which is used to expose outputs from the source module in a way that maintains unknown-ness |
265 |
| -// and secretness of the outputs. |
266 |
| -func (s *ResourceState) IsInternalOutputResource() bool { |
267 |
| - return strings.HasPrefix(s.Name(), terraformDataResourcePrefix) |
| 267 | +// outputIsSecret returns true if the output is a secret based on the value of the |
| 268 | +// corresponding is_secret output. |
| 269 | +func (s *State) outputIsSecret(outputName string) bool { |
| 270 | + isSecretKey := fmt.Sprintf("%s%s", terraformIsSecretOutputPrefix, outputName) |
| 271 | + if isSecretVal, ok := s.rawState.Values.Outputs[isSecretKey]; ok { |
| 272 | + return isSecretVal.Value.(bool) |
| 273 | + } |
| 274 | + contract.Failf("isSecret key %q not found in output changes", isSecretKey) |
| 275 | + return false |
268 | 276 | }
|
269 | 277 |
|
270 | 278 | // Outputs returns the outputs of a terraform module state as a Pulumi property map.
|
271 | 279 | func (s *State) Outputs() resource.PropertyMap {
|
272 | 280 | outputs := resource.PropertyMap{}
|
273 |
| - s.Resources.VisitResources(func(res *ResourceState) { |
274 |
| - if res.IsInternalOutputResource() { |
275 |
| - withoutPrefix := strings.TrimPrefix(res.Name(), terraformDataResourcePrefix) |
276 |
| - outputKey := resource.PropertyKey(withoutPrefix) |
277 |
| - attributeValues := res.AttributeValues() |
278 |
| - if v, ok := attributeValues[resource.PropertyKey("input")]; ok { |
279 |
| - outputs[outputKey] = v |
280 |
| - } |
| 281 | + for outputKey, output := range s.rawState.Values.Outputs { |
| 282 | + if isInternalOutputResource(outputKey) { |
| 283 | + continue |
281 | 284 | }
|
282 |
| - }) |
| 285 | + key := resource.PropertyKey(outputKey) |
| 286 | + val := resource.NewPropertyValueRepl(output.Value, nil, replaceJSONNumberValue) |
| 287 | + if s.outputIsSecret(outputKey) { |
| 288 | + val = resource.MakeSecret(val) |
| 289 | + } |
| 290 | + outputs[key] = val |
| 291 | + } |
283 | 292 |
|
284 | 293 | return outputs
|
285 | 294 | }
|
0 commit comments