jsonplan: remove "proposed_unknown" structure in favor of "after_unknown" field in "change" (#19709)

* jsonplan: remove "proposed_unknown" structure in favor of
"after_unknown" field in "change"
This commit is contained in:
Kristin Laemmert 2018-12-20 14:30:18 -08:00 committed by GitHub
parent 364d3ffc4a
commit 2b6dc13f29
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 62 additions and 72 deletions

View File

@ -27,7 +27,6 @@ const FormatVersion = "0.1"
type plan struct {
FormatVersion string `json:"format_version,omitempty"`
PlannedValues stateValues `json:"planned_values,omitempty"`
ProposedUnknown stateValues `json:"proposed_unknown,omitempty"`
ResourceChanges []resourceChange `json:"resource_changes,omitempty"`
OutputChanges map[string]change `json:"output_changes,omitempty"`
PriorState json.RawMessage `json:"prior_state,omitempty"`
@ -62,8 +61,9 @@ type change struct {
// or "after" is unset (respectively). For ["no-op"], the before and after
// values are identical. The "after" value will be incomplete if there are
// values within it that won't be known until after apply.
Before json.RawMessage `json:"before,omitempty"`
After json.RawMessage `json:"after,omitempty"`
Before json.RawMessage `json:"before,omitempty"`
After json.RawMessage `json:"after,omitempty"`
AfterUnknown json.RawMessage `json:"after_unknown,omitempty"`
}
type output struct {
@ -81,7 +81,7 @@ func Marshal(
output := newPlan()
// marshalPlannedValues populates both PlannedValues and ProposedUnknowns
// output.PlannedValues
err := output.marshalPlannedValues(p.Changes, schemas)
if err != nil {
return nil, fmt.Errorf("error in marshalPlannedValues: %s", err)
@ -157,16 +157,36 @@ func (p *plan) marshalResourceChanges(changes *plans.Changes, schemas *terraform
if err != nil {
return err
}
} else {
// TODO: what is the expected value if after is not known?
}
}
afterUnknown, _ := cty.Transform(changeV.After, func(path cty.Path, val cty.Value) (cty.Value, error) {
if val.IsNull() {
return cty.False, nil
}
if !val.Type().IsPrimitiveType() {
return val, nil // just pass through non-primitives; they already contain our transform results
}
if val.IsKnown() {
// null rather than false here so that known values
// don't appear at all in JSON serialization of our result
return cty.False, nil
}
return cty.True, nil
})
a, _ := ctyjson.Marshal(afterUnknown, afterUnknown.Type())
r.Change = change{
Actions: []string{rc.Action.String()},
Before: json.RawMessage(before),
After: json.RawMessage(after),
Actions: []string{rc.Action.String()},
Before: json.RawMessage(before),
After: json.RawMessage(after),
AfterUnknown: a,
}
r.Deposed = rc.DeposedKey == states.NotDeposed
key := addr.Resource.Key
@ -207,6 +227,7 @@ func (p *plan) marshalOutputChanges(changes *plans.Changes) error {
}
var before, after []byte
afterUnknown := cty.False
if changeV.Before != cty.NilVal {
before, err = ctyjson.Marshal(changeV.Before, changeV.Before.Type())
if err != nil {
@ -219,13 +240,20 @@ func (p *plan) marshalOutputChanges(changes *plans.Changes) error {
if err != nil {
return err
}
} else {
afterUnknown = cty.True
}
}
var c change
c.Actions = []string{oc.Action.String()}
c.Before = json.RawMessage(before)
c.After = json.RawMessage(after)
a, _ := ctyjson.Marshal(afterUnknown, afterUnknown.Type())
c := change{
Actions: []string{oc.Action.String()},
Before: json.RawMessage(before),
After: json.RawMessage(after),
AfterUnknown: a,
}
p.OutputChanges[oc.Addr.OutputValue.Name] = c
}
@ -234,20 +262,18 @@ func (p *plan) marshalOutputChanges(changes *plans.Changes) error {
func (p *plan) marshalPlannedValues(changes *plans.Changes, schemas *terraform.Schemas) error {
// marshal the planned changes into a module
plan, unknownValues, err := marshalPlannedValues(changes, schemas)
plan, err := marshalPlannedValues(changes, schemas)
if err != nil {
return err
}
p.PlannedValues.RootModule = plan
p.ProposedUnknown.RootModule = unknownValues
// marshalPlannedOutputs
outputs, unknownOutputs, err := marshalPlannedOutputs(changes)
outputs, err := marshalPlannedOutputs(changes)
if err != nil {
return err
}
p.PlannedValues.Outputs = outputs
p.ProposedUnknown.Outputs = unknownOutputs
return nil
}

View File

@ -35,33 +35,16 @@ func marshalAttributeValues(value cty.Value, schema *configschema.Block) attribu
return ret
}
// marshalAttributeValuesBool returns an attributeValues structure with "true" and
// "false" in place of the values indicating whether the value is known or not.
func marshalAttributeValuesBool(value cty.Value, schema *configschema.Block) attributeValues {
ret := make(attributeValues)
it := value.ElementIterator()
for it.Next() {
k, v := it.Element()
if v.IsWhollyKnown() {
ret[k.AsString()] = "true"
}
ret[k.AsString()] = "false"
}
return ret
}
// marshalPlannedOutputs takes a list of changes and returns two output maps,
// the former with output values and the latter with true/false in place of
// values indicating whether the values are known at plan time.
func marshalPlannedOutputs(changes *plans.Changes) (map[string]output, map[string]output, error) {
func marshalPlannedOutputs(changes *plans.Changes) (map[string]output, error) {
if changes.Outputs == nil {
// No changes - we're done here!
return nil, nil, nil
return nil, nil
}
ret := make(map[string]output)
uRet := make(map[string]output)
for _, oc := range changes.Outputs {
if oc.ChangeSrc.Action == plans.Delete {
@ -71,23 +54,14 @@ func marshalPlannedOutputs(changes *plans.Changes) (map[string]output, map[strin
var after []byte
changeV, err := oc.Decode()
if err != nil {
return ret, uRet, err
return ret, err
}
if changeV.After != cty.NilVal {
if changeV.After.IsWhollyKnown() {
after, err = ctyjson.Marshal(changeV.After, changeV.After.Type())
if err != nil {
return ret, uRet, err
}
uRet[oc.Addr.OutputValue.Name] = output{
Value: json.RawMessage("true"),
Sensitive: oc.Sensitive,
}
} else {
uRet[oc.Addr.OutputValue.Name] = output{
Value: json.RawMessage("false"),
Sensitive: oc.Sensitive,
return ret, err
}
}
}
@ -98,17 +72,14 @@ func marshalPlannedOutputs(changes *plans.Changes) (map[string]output, map[strin
}
}
return ret, uRet, nil
return ret, nil
}
// marshalPlannedValues returns two modules:
// The former has attribute values populated and the latter has true/false in
// place of values indicating whether the values are known at plan time.
func marshalPlannedValues(changes *plans.Changes, schemas *terraform.Schemas) (module, module, error) {
var ret, uRet module
func marshalPlannedValues(changes *plans.Changes, schemas *terraform.Schemas) (module, error) {
var ret module
if changes.Empty() {
return ret, uRet, nil
return ret, nil
}
// build two maps:
@ -132,27 +103,26 @@ func marshalPlannedValues(changes *plans.Changes, schemas *terraform.Schemas) (m
}
// start with the root module
resources, uResources, err := marshalPlanResources(changes, moduleResourceMap[""], schemas)
resources, err := marshalPlanResources(changes, moduleResourceMap[""], schemas)
if err != nil {
return ret, uRet, err
return ret, err
}
ret.Resources = resources
uRet.Resources = uResources
childModules, err := marshalPlanModules(changes, schemas, moduleMap[""], moduleMap, moduleResourceMap)
if err != nil {
return ret, uRet, err
return ret, err
}
ret.ChildModules = childModules
return ret, uRet, nil
return ret, nil
}
// marshalPlannedValues returns two resource slices:
// The former has attribute values populated and the latter has true/false in
// place of values indicating whether the values are known at plan time.
func marshalPlanResources(changes *plans.Changes, ris []addrs.AbsResourceInstance, schemas *terraform.Schemas) ([]resource, []resource, error) {
var ret, uRet []resource
func marshalPlanResources(changes *plans.Changes, ris []addrs.AbsResourceInstance, schemas *terraform.Schemas) ([]resource, error) {
var ret []resource
for _, ri := range ris {
r := changes.ResourceInstance(ri)
@ -174,7 +144,7 @@ func marshalPlanResources(changes *plans.Changes, ris []addrs.AbsResourceInstanc
case addrs.DataResourceMode:
resource.Mode = "data"
default:
return nil, nil, fmt.Errorf("resource %s has an unsupported mode %s",
return nil, fmt.Errorf("resource %s has an unsupported mode %s",
r.Addr.String(),
r.Addr.Resource.Resource.Mode.String(),
)
@ -186,30 +156,24 @@ func marshalPlanResources(changes *plans.Changes, ris []addrs.AbsResourceInstanc
resource.Type,
)
if schema == nil {
return nil, nil, fmt.Errorf("no schema found for %s", r.Addr.String())
return nil, fmt.Errorf("no schema found for %s", r.Addr.String())
}
resource.SchemaVersion = schemaVer
changeV, err := r.Decode(schema.ImpliedType())
if err != nil {
return nil, nil, err
return nil, err
}
var unknownAttributeValues attributeValues
if changeV.After != cty.NilVal {
if changeV.After.IsWhollyKnown() {
resource.AttributeValues = marshalAttributeValues(changeV.After, schema)
}
unknownAttributeValues = marshalAttributeValuesBool(changeV.After, schema)
}
uResource := resource
uResource.AttributeValues = unknownAttributeValues
ret = append(ret, resource)
uRet = append(uRet, uResource)
}
return ret, uRet, nil
return ret, nil
}
// marshalPlanModules iterates over a list of modules to recursively describe
@ -232,7 +196,7 @@ func marshalPlanModules(
if child.String() != "" {
cm.Address = child.String()
}
rs, _, err := marshalPlanResources(changes, moduleResources, schemas)
rs, err := marshalPlanResources(changes, moduleResources, schemas)
if err != nil {
return nil, err
}