Omit unknowns in resources in stack outputs during preview. (#3427)
If a stack output includes a `Resource`, we will as of a recent change always show the output diff, but this diff will potentially include unknowns, leading to spurious output like: ``` + namePrefix : output<string> ``` These changes supress these diffs by adding a special key to the POJO we generate for resources *during preview only* that indicates that the POJO represents a Pulumi resource, then stripping all adds of unknown values from diffs for objects marked with that key. Fixes #3314.
This commit is contained in:
parent
9bf688338c
commit
c383810bf8
|
@ -13,6 +13,9 @@ CHANGELOG
|
|||
imported by passing the `--force` flag.
|
||||
[#3422](https://github.com/pulumi/pulumi/pull/3422)
|
||||
|
||||
- Omit unknowns in resources in stack outputs during preview.
|
||||
[#3427](https://github.com/pulumi/pulumi/pull/3427)
|
||||
|
||||
## 1.4.0 (2019-10-24)
|
||||
|
||||
- `FileAsset` in the Python SDK now accepts anything implementing `os.PathLike` in addition to `str`.
|
||||
|
|
|
@ -238,6 +238,64 @@ func PrintObject(
|
|||
}
|
||||
}
|
||||
|
||||
func massageStackPreviewAdd(p resource.PropertyValue) {
|
||||
switch {
|
||||
case p.IsArray():
|
||||
for _, v := range p.ArrayValue() {
|
||||
massageStackPreviewAdd(v)
|
||||
}
|
||||
case p.IsObject():
|
||||
delete(p.ObjectValue(), "@isPulumiResource")
|
||||
for _, v := range p.ObjectValue() {
|
||||
massageStackPreviewAdd(v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func massageStackPreviewDiff(diff resource.ValueDiff, inResource bool) {
|
||||
switch {
|
||||
case diff.Array != nil:
|
||||
for _, p := range diff.Array.Adds {
|
||||
massageStackPreviewAdd(p)
|
||||
}
|
||||
for _, d := range diff.Array.Updates {
|
||||
massageStackPreviewDiff(d, inResource)
|
||||
}
|
||||
case diff.Object != nil:
|
||||
massageStackPreviewOutputDiff(diff.Object, inResource)
|
||||
}
|
||||
}
|
||||
|
||||
// massageStackPreviewOutputDiff removes any adds of unknown values nested inside Pulumi resources present in a stack's
|
||||
// outputs.
|
||||
func massageStackPreviewOutputDiff(diff *resource.ObjectDiff, inResource bool) {
|
||||
if diff == nil {
|
||||
return
|
||||
}
|
||||
|
||||
_, isResource := diff.Adds["@isPulumiResource"]
|
||||
if isResource {
|
||||
delete(diff.Adds, "@isPulumiResource")
|
||||
|
||||
for k, v := range diff.Adds {
|
||||
if v.IsComputed() {
|
||||
delete(diff.Adds, k)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, p := range diff.Adds {
|
||||
massageStackPreviewAdd(p)
|
||||
}
|
||||
for k, d := range diff.Updates {
|
||||
if isResource && d.New.IsComputed() && !shouldPrintPropertyValue(d.Old, false) {
|
||||
delete(diff.Updates, k)
|
||||
} else {
|
||||
massageStackPreviewDiff(d, inResource)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// GetResourceOutputsPropertiesString prints only those properties that either differ from the input properties or, if
|
||||
// there is an old snapshot of the resource, differ from the prior old snapshot's output properties.
|
||||
func GetResourceOutputsPropertiesString(
|
||||
|
@ -298,6 +356,12 @@ func GetResourceOutputsPropertiesString(
|
|||
var outputDiff *resource.ObjectDiff
|
||||
if step.Old != nil && step.Old.Outputs != nil {
|
||||
outputDiff = step.Old.Outputs.Diff(outs, IsInternalPropertyKey)
|
||||
|
||||
// If this is the root stack type, we want to strip out any nested resource outputs that are not known if
|
||||
// they have no corresponding output in the old state.
|
||||
if planning && step.URN.Type() == resource.RootStackType {
|
||||
massageStackPreviewOutputDiff(outputDiff, false)
|
||||
}
|
||||
}
|
||||
|
||||
// If we asked to not show-sames, and no outputs changed then don't show anything at all here.
|
||||
|
|
|
@ -16,7 +16,7 @@ import * as asset from "../asset";
|
|||
import { getProject, getStack } from "../metadata";
|
||||
import { Inputs, Output, output, secret } from "../output";
|
||||
import { ComponentResource, Resource, ResourceTransformation } from "../resource";
|
||||
import { getRootResource, isQueryMode, setRootResource } from "./settings";
|
||||
import { getRootResource, isDryRun, isQueryMode, setRootResource } from "./settings";
|
||||
|
||||
/**
|
||||
* rootPulumiStackTypeName is the type name that should be used to construct the root component in the tree of Pulumi
|
||||
|
@ -176,7 +176,13 @@ async function massageComplex(prop: any, objectStack: any[]): Promise<any> {
|
|||
if (Resource.isInstance(prop)) {
|
||||
// Emit a resource as a normal pojo. But filter out all our internal properties so that
|
||||
// they don't clutter the display/checkpoint with values not relevant to the application.
|
||||
return serializeAllKeys(n => !n.startsWith("__"));
|
||||
//
|
||||
// In preview only, we mark the POJO with "@isPulumiResource" to indicate that it is derived
|
||||
// from a resource. This allows the engine to perform resource-specific filtering of unknowns
|
||||
// from output diffs during a preview. This filtering is not necessary during an update because
|
||||
// all property values are known.
|
||||
const pojo = await serializeAllKeys(n => !n.startsWith("__"));
|
||||
return !isDryRun() ? pojo : { ...pojo, "@isPulumiResource": true };
|
||||
}
|
||||
|
||||
if (prop instanceof Array) {
|
||||
|
|
|
@ -21,7 +21,7 @@ from inspect import isawaitable
|
|||
from typing import Callable, Any, Dict, List
|
||||
|
||||
from ..resource import ComponentResource, Resource, ResourceTransformation
|
||||
from .settings import get_project, get_stack, get_root_resource, set_root_resource
|
||||
from .settings import get_project, get_stack, get_root_resource, is_dry_run, set_root_resource
|
||||
from .rpc_manager import RPC_MANAGER
|
||||
from .. import log
|
||||
|
||||
|
@ -149,6 +149,17 @@ def massage(attr: Any, seen: List[Any]):
|
|||
if isawaitable(attr):
|
||||
return Output.from_input(attr).apply(lambda v: massage(v, seen))
|
||||
|
||||
if isinstance(attr, Resource):
|
||||
result = massage(attr.__dict__, seen)
|
||||
|
||||
# In preview only, we mark the result with "@isPulumiResource" to indicate that it is derived
|
||||
# from a resource. This allows the engine to perform resource-specific filtering of unknowns
|
||||
# from output diffs during a preview. This filtering is not necessary during an update because
|
||||
# all property values are known.
|
||||
if is_dry_run():
|
||||
result["@isPulumiResource"] = True
|
||||
return result
|
||||
|
||||
if hasattr(attr, "__dict__"):
|
||||
# recurse on the dictionary itself. It will be handled above.
|
||||
return massage(attr.__dict__, seen)
|
||||
|
|
Loading…
Reference in a new issue