2017-05-18 23:51:52 +02:00
|
|
|
// Licensed to Pulumi Corporation ("Pulumi") under one or more
|
|
|
|
// contributor license agreements. See the NOTICE file distributed with
|
|
|
|
// this work for additional information regarding copyright ownership.
|
|
|
|
// Pulumi licenses this file to You under the Apache License, Version 2.0
|
|
|
|
// (the "License"); you may not use this file except in compliance with
|
|
|
|
// the License. You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
2017-02-20 20:18:47 +01:00
|
|
|
|
|
|
|
package resource
|
|
|
|
|
|
|
|
import (
|
|
|
|
"reflect"
|
|
|
|
"sort"
|
|
|
|
|
2017-02-20 22:55:09 +01:00
|
|
|
"github.com/golang/glog"
|
2017-02-20 20:18:47 +01:00
|
|
|
structpb "github.com/golang/protobuf/ptypes/struct"
|
|
|
|
|
2017-05-18 20:38:28 +02:00
|
|
|
"github.com/pulumi/lumi/pkg/util/contract"
|
2017-02-20 20:18:47 +01:00
|
|
|
)
|
|
|
|
|
2017-02-25 00:41:56 +01:00
|
|
|
// MarshalOptions controls the marshaling of RPC structures.
|
|
|
|
type MarshalOptions struct {
|
Unmap properties on the receive side
This change makes progress on a few things with respect to properly
receiving properties on the engine side, coming from the provider side,
of the RPC boundary. The issues here are twofold:
1. Properties need to get unmapped using a JSON-tag-sensitive
marshaler, so that they are cased properly, etc. For that, we
have a new mapper.Unmap function (which is ultra lame -- see
pulumi/lumi#138).
2. We have the reverse problem with respect to resource IDs: on
the send side, we must translate from URNs (which the engine
knows about) and provider IDs (which the provider knows about);
similarly, then, on the receive side, we must translate from
provider IDs back into URNs.
As a result of these getting fixed, we can now properly marshal the
resulting properties back into the resource object during the plan
execution, alongside propagating and memoizing its ID.
2017-05-31 20:51:46 +02:00
|
|
|
OldURNs bool // true to permit old URNs in the properties (e.g., for pre-update).
|
|
|
|
RawResources bool // true to marshal resources "as-is"; often used when ID mappings aren't known yet.
|
2017-02-25 00:41:56 +01:00
|
|
|
}
|
|
|
|
|
Initial support for output properties (1 of 3)
This change includes approximately 1/3rd of the change necessary
to support output properties, as per pulumi/lumi#90.
In short, the runtime now has a new hidden type, Latent<T>, which
represents a "speculative" value, whose eventual type will be T,
that we can use during evaluation in various ways. Namely,
operations against Latent<T>s generally produce new Latent<U>s.
During planning, any Latent<T>s that end up in resource properties
are transformed into "unknown" property values. An unknown property
value is legal only during planning-time activities, such as Check,
Name, and InspectChange. As a result, those RPC interfaces have
been updated to include lookaside maps indicating which properties
have unknown values. My intent is to add some helper functions to
make dealing with this circumstance more correct-by-construction.
For now, using an unresolved Latent<T> in a conditional will lead
to an error. See pulumi/lumi#67. Speculating beyond these -- by
supporting iterative planning and application -- is something we
want to support eventually, but it makes sense to do that as an
additive change beyond this initial support. That is a missing 1/3.
Finally, the other missing 1/3rd which will happen much sooner
than the rest is restructuing plan application so that it will
correctly observe resolution of Latent<T> values. Right now, the
evaluation happens in one single pass, prior to the application, and
so Latent<T>s never actually get witnessed in a resolved state.
2017-05-24 02:32:59 +02:00
|
|
|
// MarshalPropertiesWithUnknowns marshals a resource's property map as a "JSON-like" protobuf structure. Any URNs are
|
|
|
|
// replaced with their resource IDs during marshaling; it is an error to marshal a URN for a resource without an ID. A
|
|
|
|
// map of any unknown properties encountered during marshaling (latent values) is returned on the side; these values are
|
|
|
|
// marshaled using the default value in the returned structure and so this map is essential for interpreting results.
|
|
|
|
func MarshalPropertiesWithUnknowns(
|
|
|
|
ctx *Context, props PropertyMap, opts MarshalOptions) (*structpb.Struct, map[string]bool) {
|
|
|
|
var unk map[string]bool
|
2017-02-20 20:18:47 +01:00
|
|
|
result := &structpb.Struct{
|
|
|
|
Fields: make(map[string]*structpb.Value),
|
|
|
|
}
|
|
|
|
for _, key := range StablePropertyKeys(props) {
|
2017-06-05 04:24:48 +02:00
|
|
|
if v := props[key]; !v.IsOutput() {
|
2017-05-25 22:19:20 +02:00
|
|
|
mv, known := MarshalPropertyValue(ctx, props[key], opts)
|
2017-06-05 04:24:48 +02:00
|
|
|
if known {
|
|
|
|
result.Fields[string(key)] = mv
|
|
|
|
} else {
|
2017-05-25 22:19:20 +02:00
|
|
|
if unk == nil {
|
|
|
|
unk = make(map[string]bool)
|
|
|
|
}
|
|
|
|
unk[string(key)] = true // remember that this property was unknown, tainting this whole object.
|
Initial support for output properties (1 of 3)
This change includes approximately 1/3rd of the change necessary
to support output properties, as per pulumi/lumi#90.
In short, the runtime now has a new hidden type, Latent<T>, which
represents a "speculative" value, whose eventual type will be T,
that we can use during evaluation in various ways. Namely,
operations against Latent<T>s generally produce new Latent<U>s.
During planning, any Latent<T>s that end up in resource properties
are transformed into "unknown" property values. An unknown property
value is legal only during planning-time activities, such as Check,
Name, and InspectChange. As a result, those RPC interfaces have
been updated to include lookaside maps indicating which properties
have unknown values. My intent is to add some helper functions to
make dealing with this circumstance more correct-by-construction.
For now, using an unresolved Latent<T> in a conditional will lead
to an error. See pulumi/lumi#67. Speculating beyond these -- by
supporting iterative planning and application -- is something we
want to support eventually, but it makes sense to do that as an
additive change beyond this initial support. That is a missing 1/3.
Finally, the other missing 1/3rd which will happen much sooner
than the rest is restructuing plan application so that it will
correctly observe resolution of Latent<T> values. Right now, the
evaluation happens in one single pass, prior to the application, and
so Latent<T>s never actually get witnessed in a resolved state.
2017-05-24 02:32:59 +02:00
|
|
|
}
|
2017-02-25 00:41:56 +01:00
|
|
|
}
|
2017-02-20 20:18:47 +01:00
|
|
|
}
|
Initial support for output properties (1 of 3)
This change includes approximately 1/3rd of the change necessary
to support output properties, as per pulumi/lumi#90.
In short, the runtime now has a new hidden type, Latent<T>, which
represents a "speculative" value, whose eventual type will be T,
that we can use during evaluation in various ways. Namely,
operations against Latent<T>s generally produce new Latent<U>s.
During planning, any Latent<T>s that end up in resource properties
are transformed into "unknown" property values. An unknown property
value is legal only during planning-time activities, such as Check,
Name, and InspectChange. As a result, those RPC interfaces have
been updated to include lookaside maps indicating which properties
have unknown values. My intent is to add some helper functions to
make dealing with this circumstance more correct-by-construction.
For now, using an unresolved Latent<T> in a conditional will lead
to an error. See pulumi/lumi#67. Speculating beyond these -- by
supporting iterative planning and application -- is something we
want to support eventually, but it makes sense to do that as an
additive change beyond this initial support. That is a missing 1/3.
Finally, the other missing 1/3rd which will happen much sooner
than the rest is restructuing plan application so that it will
correctly observe resolution of Latent<T> values. Right now, the
evaluation happens in one single pass, prior to the application, and
so Latent<T>s never actually get witnessed in a resolved state.
2017-05-24 02:32:59 +02:00
|
|
|
return result, unk
|
2017-02-20 20:18:47 +01:00
|
|
|
}
|
|
|
|
|
Initial support for output properties (1 of 3)
This change includes approximately 1/3rd of the change necessary
to support output properties, as per pulumi/lumi#90.
In short, the runtime now has a new hidden type, Latent<T>, which
represents a "speculative" value, whose eventual type will be T,
that we can use during evaluation in various ways. Namely,
operations against Latent<T>s generally produce new Latent<U>s.
During planning, any Latent<T>s that end up in resource properties
are transformed into "unknown" property values. An unknown property
value is legal only during planning-time activities, such as Check,
Name, and InspectChange. As a result, those RPC interfaces have
been updated to include lookaside maps indicating which properties
have unknown values. My intent is to add some helper functions to
make dealing with this circumstance more correct-by-construction.
For now, using an unresolved Latent<T> in a conditional will lead
to an error. See pulumi/lumi#67. Speculating beyond these -- by
supporting iterative planning and application -- is something we
want to support eventually, but it makes sense to do that as an
additive change beyond this initial support. That is a missing 1/3.
Finally, the other missing 1/3rd which will happen much sooner
than the rest is restructuing plan application so that it will
correctly observe resolution of Latent<T> values. Right now, the
evaluation happens in one single pass, prior to the application, and
so Latent<T>s never actually get witnessed in a resolved state.
2017-05-24 02:32:59 +02:00
|
|
|
// MarshalProperties performs ordinary marshaling of a resource's properties but then validates afterwards that all
|
|
|
|
// fields were known (in other words, no latent properties were encountered).
|
|
|
|
func MarshalProperties(ctx *Context, props PropertyMap, opts MarshalOptions) *structpb.Struct {
|
|
|
|
pstr, unks := MarshalPropertiesWithUnknowns(ctx, props, opts)
|
|
|
|
contract.Assertf(unks == nil, "Unexpected unknown properties during final marshaling")
|
|
|
|
return pstr
|
|
|
|
}
|
|
|
|
|
|
|
|
// MarshalPropertyValue marshals a single resource property value into its "JSON-like" value representation. The
|
|
|
|
// boolean return value indicates whether the value was known (true) or unknown (false).
|
2017-02-25 00:41:56 +01:00
|
|
|
func MarshalPropertyValue(ctx *Context, v PropertyValue, opts MarshalOptions) (*structpb.Value, bool) {
|
2017-02-20 20:18:47 +01:00
|
|
|
if v.IsNull() {
|
|
|
|
return &structpb.Value{
|
|
|
|
Kind: &structpb.Value_NullValue{
|
2017-02-28 20:02:33 +01:00
|
|
|
NullValue: structpb.NullValue_NULL_VALUE,
|
2017-02-20 20:18:47 +01:00
|
|
|
},
|
2017-02-25 00:41:56 +01:00
|
|
|
}, true
|
2017-02-20 20:18:47 +01:00
|
|
|
} else if v.IsBool() {
|
|
|
|
return &structpb.Value{
|
|
|
|
Kind: &structpb.Value_BoolValue{
|
2017-02-28 20:02:33 +01:00
|
|
|
BoolValue: v.BoolValue(),
|
2017-02-20 20:18:47 +01:00
|
|
|
},
|
2017-02-25 00:41:56 +01:00
|
|
|
}, true
|
2017-02-20 20:18:47 +01:00
|
|
|
} else if v.IsNumber() {
|
|
|
|
return &structpb.Value{
|
|
|
|
Kind: &structpb.Value_NumberValue{
|
2017-02-28 20:02:33 +01:00
|
|
|
NumberValue: v.NumberValue(),
|
2017-02-20 20:18:47 +01:00
|
|
|
},
|
2017-02-25 00:41:56 +01:00
|
|
|
}, true
|
2017-02-20 20:18:47 +01:00
|
|
|
} else if v.IsString() {
|
|
|
|
return &structpb.Value{
|
|
|
|
Kind: &structpb.Value_StringValue{
|
2017-02-28 20:02:33 +01:00
|
|
|
StringValue: v.StringValue(),
|
2017-02-20 20:18:47 +01:00
|
|
|
},
|
2017-02-25 00:41:56 +01:00
|
|
|
}, true
|
2017-02-20 20:18:47 +01:00
|
|
|
} else if v.IsArray() {
|
Initial support for output properties (1 of 3)
This change includes approximately 1/3rd of the change necessary
to support output properties, as per pulumi/lumi#90.
In short, the runtime now has a new hidden type, Latent<T>, which
represents a "speculative" value, whose eventual type will be T,
that we can use during evaluation in various ways. Namely,
operations against Latent<T>s generally produce new Latent<U>s.
During planning, any Latent<T>s that end up in resource properties
are transformed into "unknown" property values. An unknown property
value is legal only during planning-time activities, such as Check,
Name, and InspectChange. As a result, those RPC interfaces have
been updated to include lookaside maps indicating which properties
have unknown values. My intent is to add some helper functions to
make dealing with this circumstance more correct-by-construction.
For now, using an unresolved Latent<T> in a conditional will lead
to an error. See pulumi/lumi#67. Speculating beyond these -- by
supporting iterative planning and application -- is something we
want to support eventually, but it makes sense to do that as an
additive change beyond this initial support. That is a missing 1/3.
Finally, the other missing 1/3rd which will happen much sooner
than the rest is restructuing plan application so that it will
correctly observe resolution of Latent<T> values. Right now, the
evaluation happens in one single pass, prior to the application, and
so Latent<T>s never actually get witnessed in a resolved state.
2017-05-24 02:32:59 +02:00
|
|
|
outcome := true
|
2017-02-20 20:18:47 +01:00
|
|
|
var elems []*structpb.Value
|
|
|
|
for _, elem := range v.ArrayValue() {
|
Initial support for output properties (1 of 3)
This change includes approximately 1/3rd of the change necessary
to support output properties, as per pulumi/lumi#90.
In short, the runtime now has a new hidden type, Latent<T>, which
represents a "speculative" value, whose eventual type will be T,
that we can use during evaluation in various ways. Namely,
operations against Latent<T>s generally produce new Latent<U>s.
During planning, any Latent<T>s that end up in resource properties
are transformed into "unknown" property values. An unknown property
value is legal only during planning-time activities, such as Check,
Name, and InspectChange. As a result, those RPC interfaces have
been updated to include lookaside maps indicating which properties
have unknown values. My intent is to add some helper functions to
make dealing with this circumstance more correct-by-construction.
For now, using an unresolved Latent<T> in a conditional will lead
to an error. See pulumi/lumi#67. Speculating beyond these -- by
supporting iterative planning and application -- is something we
want to support eventually, but it makes sense to do that as an
additive change beyond this initial support. That is a missing 1/3.
Finally, the other missing 1/3rd which will happen much sooner
than the rest is restructuing plan application so that it will
correctly observe resolution of Latent<T> values. Right now, the
evaluation happens in one single pass, prior to the application, and
so Latent<T>s never actually get witnessed in a resolved state.
2017-05-24 02:32:59 +02:00
|
|
|
elemv, known := MarshalPropertyValue(ctx, elem, opts)
|
|
|
|
outcome = outcome && known
|
|
|
|
elems = append(elems, elemv)
|
2017-02-20 20:18:47 +01:00
|
|
|
}
|
|
|
|
return &structpb.Value{
|
|
|
|
Kind: &structpb.Value_ListValue{
|
2017-02-28 20:02:33 +01:00
|
|
|
ListValue: &structpb.ListValue{Values: elems},
|
2017-02-20 20:18:47 +01:00
|
|
|
},
|
Initial support for output properties (1 of 3)
This change includes approximately 1/3rd of the change necessary
to support output properties, as per pulumi/lumi#90.
In short, the runtime now has a new hidden type, Latent<T>, which
represents a "speculative" value, whose eventual type will be T,
that we can use during evaluation in various ways. Namely,
operations against Latent<T>s generally produce new Latent<U>s.
During planning, any Latent<T>s that end up in resource properties
are transformed into "unknown" property values. An unknown property
value is legal only during planning-time activities, such as Check,
Name, and InspectChange. As a result, those RPC interfaces have
been updated to include lookaside maps indicating which properties
have unknown values. My intent is to add some helper functions to
make dealing with this circumstance more correct-by-construction.
For now, using an unresolved Latent<T> in a conditional will lead
to an error. See pulumi/lumi#67. Speculating beyond these -- by
supporting iterative planning and application -- is something we
want to support eventually, but it makes sense to do that as an
additive change beyond this initial support. That is a missing 1/3.
Finally, the other missing 1/3rd which will happen much sooner
than the rest is restructuing plan application so that it will
correctly observe resolution of Latent<T> values. Right now, the
evaluation happens in one single pass, prior to the application, and
so Latent<T>s never actually get witnessed in a resolved state.
2017-05-24 02:32:59 +02:00
|
|
|
}, outcome
|
2017-02-20 20:18:47 +01:00
|
|
|
} else if v.IsObject() {
|
Initial support for output properties (1 of 3)
This change includes approximately 1/3rd of the change necessary
to support output properties, as per pulumi/lumi#90.
In short, the runtime now has a new hidden type, Latent<T>, which
represents a "speculative" value, whose eventual type will be T,
that we can use during evaluation in various ways. Namely,
operations against Latent<T>s generally produce new Latent<U>s.
During planning, any Latent<T>s that end up in resource properties
are transformed into "unknown" property values. An unknown property
value is legal only during planning-time activities, such as Check,
Name, and InspectChange. As a result, those RPC interfaces have
been updated to include lookaside maps indicating which properties
have unknown values. My intent is to add some helper functions to
make dealing with this circumstance more correct-by-construction.
For now, using an unresolved Latent<T> in a conditional will lead
to an error. See pulumi/lumi#67. Speculating beyond these -- by
supporting iterative planning and application -- is something we
want to support eventually, but it makes sense to do that as an
additive change beyond this initial support. That is a missing 1/3.
Finally, the other missing 1/3rd which will happen much sooner
than the rest is restructuing plan application so that it will
correctly observe resolution of Latent<T> values. Right now, the
evaluation happens in one single pass, prior to the application, and
so Latent<T>s never actually get witnessed in a resolved state.
2017-05-24 02:32:59 +02:00
|
|
|
obj, unks := MarshalPropertiesWithUnknowns(ctx, v.ObjectValue(), opts)
|
2017-02-20 20:18:47 +01:00
|
|
|
return &structpb.Value{
|
|
|
|
Kind: &structpb.Value_StructValue{
|
Initial support for output properties (1 of 3)
This change includes approximately 1/3rd of the change necessary
to support output properties, as per pulumi/lumi#90.
In short, the runtime now has a new hidden type, Latent<T>, which
represents a "speculative" value, whose eventual type will be T,
that we can use during evaluation in various ways. Namely,
operations against Latent<T>s generally produce new Latent<U>s.
During planning, any Latent<T>s that end up in resource properties
are transformed into "unknown" property values. An unknown property
value is legal only during planning-time activities, such as Check,
Name, and InspectChange. As a result, those RPC interfaces have
been updated to include lookaside maps indicating which properties
have unknown values. My intent is to add some helper functions to
make dealing with this circumstance more correct-by-construction.
For now, using an unresolved Latent<T> in a conditional will lead
to an error. See pulumi/lumi#67. Speculating beyond these -- by
supporting iterative planning and application -- is something we
want to support eventually, but it makes sense to do that as an
additive change beyond this initial support. That is a missing 1/3.
Finally, the other missing 1/3rd which will happen much sooner
than the rest is restructuing plan application so that it will
correctly observe resolution of Latent<T> values. Right now, the
evaluation happens in one single pass, prior to the application, and
so Latent<T>s never actually get witnessed in a resolved state.
2017-05-24 02:32:59 +02:00
|
|
|
StructValue: obj,
|
2017-02-20 20:18:47 +01:00
|
|
|
},
|
Initial support for output properties (1 of 3)
This change includes approximately 1/3rd of the change necessary
to support output properties, as per pulumi/lumi#90.
In short, the runtime now has a new hidden type, Latent<T>, which
represents a "speculative" value, whose eventual type will be T,
that we can use during evaluation in various ways. Namely,
operations against Latent<T>s generally produce new Latent<U>s.
During planning, any Latent<T>s that end up in resource properties
are transformed into "unknown" property values. An unknown property
value is legal only during planning-time activities, such as Check,
Name, and InspectChange. As a result, those RPC interfaces have
been updated to include lookaside maps indicating which properties
have unknown values. My intent is to add some helper functions to
make dealing with this circumstance more correct-by-construction.
For now, using an unresolved Latent<T> in a conditional will lead
to an error. See pulumi/lumi#67. Speculating beyond these -- by
supporting iterative planning and application -- is something we
want to support eventually, but it makes sense to do that as an
additive change beyond this initial support. That is a missing 1/3.
Finally, the other missing 1/3rd which will happen much sooner
than the rest is restructuing plan application so that it will
correctly observe resolution of Latent<T> values. Right now, the
evaluation happens in one single pass, prior to the application, and
so Latent<T>s never actually get witnessed in a resolved state.
2017-05-24 02:32:59 +02:00
|
|
|
}, unks == nil
|
2017-02-20 20:18:47 +01:00
|
|
|
} else if v.IsResource() {
|
Unmap properties on the receive side
This change makes progress on a few things with respect to properly
receiving properties on the engine side, coming from the provider side,
of the RPC boundary. The issues here are twofold:
1. Properties need to get unmapped using a JSON-tag-sensitive
marshaler, so that they are cased properly, etc. For that, we
have a new mapper.Unmap function (which is ultra lame -- see
pulumi/lumi#138).
2. We have the reverse problem with respect to resource IDs: on
the send side, we must translate from URNs (which the engine
knows about) and provider IDs (which the provider knows about);
similarly, then, on the receive side, we must translate from
provider IDs back into URNs.
As a result of these getting fixed, we can now properly marshal the
resulting properties back into the resource object during the plan
execution, alongside propagating and memoizing its ID.
2017-05-31 20:51:46 +02:00
|
|
|
// During marshaling, the wire format of a resource URN is the provider ID; in some circumstances, this is
|
|
|
|
// not desirable -- such as when the provider is marshaling data for its own use, or when the IDs are not
|
|
|
|
// yet ready -- in which case RawResources == true and we simply marshal the URN as-is.
|
Support replacement IDs
This change introduces a new RPC function to the provider interface;
in pseudo-code:
UpdateImpact(id ID, t Type, olds PropertyMap, news PropertyMap)
(bool, PropertyMap, error)
Essentially, during the planning phase, we will consult each provider
about the nature of a proposed update. This update includes a set of
old properties and the new ones and, if the resource provider will need
to replace the property as a result of the update, it will return true;
in general, the PropertyMap will eventually contain a list of all
properties that will be modified as a result of the operation (see below).
The planning phase reacts to this by propagating the change to dependent
resources, so that they know that the ID will change (and so that they
can recalculate their own state accordingly, possibly leading to a ripple
effect). This ensures the overall DAG / schedule is ordered correctly.
This change is most of pulumi/coconut#105. The only missing piece
is to generalize replacing the "ID" property with replacing arbitrary
properties; there are hooks in here for this, but until pulumi/coconut#90
is addressed, it doesn't make sense to make much progress on this.
2017-03-01 18:08:53 +01:00
|
|
|
var wire string
|
2017-02-20 22:55:09 +01:00
|
|
|
m := v.ResourceValue()
|
Unmap properties on the receive side
This change makes progress on a few things with respect to properly
receiving properties on the engine side, coming from the provider side,
of the RPC boundary. The issues here are twofold:
1. Properties need to get unmapped using a JSON-tag-sensitive
marshaler, so that they are cased properly, etc. For that, we
have a new mapper.Unmap function (which is ultra lame -- see
pulumi/lumi#138).
2. We have the reverse problem with respect to resource IDs: on
the send side, we must translate from URNs (which the engine
knows about) and provider IDs (which the provider knows about);
similarly, then, on the receive side, we must translate from
provider IDs back into URNs.
As a result of these getting fixed, we can now properly marshal the
resulting properties back into the resource object during the plan
execution, alongside propagating and memoizing its ID.
2017-05-31 20:51:46 +02:00
|
|
|
if opts.RawResources {
|
Support replacement IDs
This change introduces a new RPC function to the provider interface;
in pseudo-code:
UpdateImpact(id ID, t Type, olds PropertyMap, news PropertyMap)
(bool, PropertyMap, error)
Essentially, during the planning phase, we will consult each provider
about the nature of a proposed update. This update includes a set of
old properties and the new ones and, if the resource provider will need
to replace the property as a result of the update, it will return true;
in general, the PropertyMap will eventually contain a list of all
properties that will be modified as a result of the operation (see below).
The planning phase reacts to this by propagating the change to dependent
resources, so that they know that the ID will change (and so that they
can recalculate their own state accordingly, possibly leading to a ripple
effect). This ensures the overall DAG / schedule is ordered correctly.
This change is most of pulumi/coconut#105. The only missing piece
is to generalize replacing the "ID" property with replacing arbitrary
properties; there are hooks in here for this, but until pulumi/coconut#90
is addressed, it doesn't make sense to make much progress on this.
2017-03-01 18:08:53 +01:00
|
|
|
wire = string(m)
|
2017-03-01 02:03:33 +01:00
|
|
|
} else {
|
2017-04-22 00:27:32 +02:00
|
|
|
contract.Assertf(ctx != nil, "Resource encountered with a nil context; URN not recoverable")
|
Support replacement IDs
This change introduces a new RPC function to the provider interface;
in pseudo-code:
UpdateImpact(id ID, t Type, olds PropertyMap, news PropertyMap)
(bool, PropertyMap, error)
Essentially, during the planning phase, we will consult each provider
about the nature of a proposed update. This update includes a set of
old properties and the new ones and, if the resource provider will need
to replace the property as a result of the update, it will return true;
in general, the PropertyMap will eventually contain a list of all
properties that will be modified as a result of the operation (see below).
The planning phase reacts to this by propagating the change to dependent
resources, so that they know that the ID will change (and so that they
can recalculate their own state accordingly, possibly leading to a ripple
effect). This ensures the overall DAG / schedule is ordered correctly.
This change is most of pulumi/coconut#105. The only missing piece
is to generalize replacing the "ID" property with replacing arbitrary
properties; there are hooks in here for this, but until pulumi/coconut#90
is addressed, it doesn't make sense to make much progress on this.
2017-03-01 18:08:53 +01:00
|
|
|
var id ID
|
2017-03-03 02:10:10 +01:00
|
|
|
if res, has := ctx.URNRes[m]; has {
|
Support replacement IDs
This change introduces a new RPC function to the provider interface;
in pseudo-code:
UpdateImpact(id ID, t Type, olds PropertyMap, news PropertyMap)
(bool, PropertyMap, error)
Essentially, during the planning phase, we will consult each provider
about the nature of a proposed update. This update includes a set of
old properties and the new ones and, if the resource provider will need
to replace the property as a result of the update, it will return true;
in general, the PropertyMap will eventually contain a list of all
properties that will be modified as a result of the operation (see below).
The planning phase reacts to this by propagating the change to dependent
resources, so that they know that the ID will change (and so that they
can recalculate their own state accordingly, possibly leading to a ripple
effect). This ensures the overall DAG / schedule is ordered correctly.
This change is most of pulumi/coconut#105. The only missing piece
is to generalize replacing the "ID" property with replacing arbitrary
properties; there are hooks in here for this, but until pulumi/coconut#90
is addressed, it doesn't make sense to make much progress on this.
2017-03-01 18:08:53 +01:00
|
|
|
id = res.ID() // found a new resource with this ID, use it.
|
Unmap properties on the receive side
This change makes progress on a few things with respect to properly
receiving properties on the engine side, coming from the provider side,
of the RPC boundary. The issues here are twofold:
1. Properties need to get unmapped using a JSON-tag-sensitive
marshaler, so that they are cased properly, etc. For that, we
have a new mapper.Unmap function (which is ultra lame -- see
pulumi/lumi#138).
2. We have the reverse problem with respect to resource IDs: on
the send side, we must translate from URNs (which the engine
knows about) and provider IDs (which the provider knows about);
similarly, then, on the receive side, we must translate from
provider IDs back into URNs.
As a result of these getting fixed, we can now properly marshal the
resulting properties back into the resource object during the plan
execution, alongside propagating and memoizing its ID.
2017-05-31 20:51:46 +02:00
|
|
|
} else if oldid, has := ctx.URNOldIDs[m]; opts.OldURNs && has {
|
Support replacement IDs
This change introduces a new RPC function to the provider interface;
in pseudo-code:
UpdateImpact(id ID, t Type, olds PropertyMap, news PropertyMap)
(bool, PropertyMap, error)
Essentially, during the planning phase, we will consult each provider
about the nature of a proposed update. This update includes a set of
old properties and the new ones and, if the resource provider will need
to replace the property as a result of the update, it will return true;
in general, the PropertyMap will eventually contain a list of all
properties that will be modified as a result of the operation (see below).
The planning phase reacts to this by propagating the change to dependent
resources, so that they know that the ID will change (and so that they
can recalculate their own state accordingly, possibly leading to a ripple
effect). This ensures the overall DAG / schedule is ordered correctly.
This change is most of pulumi/coconut#105. The only missing piece
is to generalize replacing the "ID" property with replacing arbitrary
properties; there are hooks in here for this, but until pulumi/coconut#90
is addressed, it doesn't make sense to make much progress on this.
2017-03-01 18:08:53 +01:00
|
|
|
id = oldid // found an old resource, maybe deleted, so use that.
|
|
|
|
} else {
|
2017-03-03 02:10:10 +01:00
|
|
|
contract.Failf("Expected resource URN '%v' to exist at marshal time", m)
|
Support replacement IDs
This change introduces a new RPC function to the provider interface;
in pseudo-code:
UpdateImpact(id ID, t Type, olds PropertyMap, news PropertyMap)
(bool, PropertyMap, error)
Essentially, during the planning phase, we will consult each provider
about the nature of a proposed update. This update includes a set of
old properties and the new ones and, if the resource provider will need
to replace the property as a result of the update, it will return true;
in general, the PropertyMap will eventually contain a list of all
properties that will be modified as a result of the operation (see below).
The planning phase reacts to this by propagating the change to dependent
resources, so that they know that the ID will change (and so that they
can recalculate their own state accordingly, possibly leading to a ripple
effect). This ensures the overall DAG / schedule is ordered correctly.
This change is most of pulumi/coconut#105. The only missing piece
is to generalize replacing the "ID" property with replacing arbitrary
properties; there are hooks in here for this, but until pulumi/coconut#90
is addressed, it doesn't make sense to make much progress on this.
2017-03-01 18:08:53 +01:00
|
|
|
}
|
2017-03-03 02:10:10 +01:00
|
|
|
contract.Assertf(id != "", "Expected resource URN '%v' to have an ID at marshal time", m)
|
Support replacement IDs
This change introduces a new RPC function to the provider interface;
in pseudo-code:
UpdateImpact(id ID, t Type, olds PropertyMap, news PropertyMap)
(bool, PropertyMap, error)
Essentially, during the planning phase, we will consult each provider
about the nature of a proposed update. This update includes a set of
old properties and the new ones and, if the resource provider will need
to replace the property as a result of the update, it will return true;
in general, the PropertyMap will eventually contain a list of all
properties that will be modified as a result of the operation (see below).
The planning phase reacts to this by propagating the change to dependent
resources, so that they know that the ID will change (and so that they
can recalculate their own state accordingly, possibly leading to a ripple
effect). This ensures the overall DAG / schedule is ordered correctly.
This change is most of pulumi/coconut#105. The only missing piece
is to generalize replacing the "ID" property with replacing arbitrary
properties; there are hooks in here for this, but until pulumi/coconut#90
is addressed, it doesn't make sense to make much progress on this.
2017-03-01 18:08:53 +01:00
|
|
|
wire = string(id)
|
2017-03-01 02:03:33 +01:00
|
|
|
}
|
Unmap properties on the receive side
This change makes progress on a few things with respect to properly
receiving properties on the engine side, coming from the provider side,
of the RPC boundary. The issues here are twofold:
1. Properties need to get unmapped using a JSON-tag-sensitive
marshaler, so that they are cased properly, etc. For that, we
have a new mapper.Unmap function (which is ultra lame -- see
pulumi/lumi#138).
2. We have the reverse problem with respect to resource IDs: on
the send side, we must translate from URNs (which the engine
knows about) and provider IDs (which the provider knows about);
similarly, then, on the receive side, we must translate from
provider IDs back into URNs.
As a result of these getting fixed, we can now properly marshal the
resulting properties back into the resource object during the plan
execution, alongside propagating and memoizing its ID.
2017-05-31 20:51:46 +02:00
|
|
|
glog.V(7).Infof("Serializing resource URN '%v' as '%v' (raw=%v)", m, wire, opts.RawResources)
|
2017-02-20 20:18:47 +01:00
|
|
|
return &structpb.Value{
|
|
|
|
Kind: &structpb.Value_StringValue{
|
Support replacement IDs
This change introduces a new RPC function to the provider interface;
in pseudo-code:
UpdateImpact(id ID, t Type, olds PropertyMap, news PropertyMap)
(bool, PropertyMap, error)
Essentially, during the planning phase, we will consult each provider
about the nature of a proposed update. This update includes a set of
old properties and the new ones and, if the resource provider will need
to replace the property as a result of the update, it will return true;
in general, the PropertyMap will eventually contain a list of all
properties that will be modified as a result of the operation (see below).
The planning phase reacts to this by propagating the change to dependent
resources, so that they know that the ID will change (and so that they
can recalculate their own state accordingly, possibly leading to a ripple
effect). This ensures the overall DAG / schedule is ordered correctly.
This change is most of pulumi/coconut#105. The only missing piece
is to generalize replacing the "ID" property with replacing arbitrary
properties; there are hooks in here for this, but until pulumi/coconut#90
is addressed, it doesn't make sense to make much progress on this.
2017-03-01 18:08:53 +01:00
|
|
|
StringValue: wire,
|
2017-02-20 20:18:47 +01:00
|
|
|
},
|
2017-02-25 00:41:56 +01:00
|
|
|
}, true
|
2017-05-25 22:19:20 +02:00
|
|
|
} else if v.IsComputed() {
|
2017-06-08 15:48:23 +02:00
|
|
|
e := v.ComputedValue().Element
|
2017-06-05 04:24:48 +02:00
|
|
|
contract.Assert(!e.IsComputed())
|
2017-05-29 22:08:30 +02:00
|
|
|
w, known := MarshalPropertyValue(ctx, e, opts)
|
|
|
|
contract.Assert(known)
|
|
|
|
return w, false
|
2017-05-25 22:19:20 +02:00
|
|
|
} else if v.IsOutput() {
|
2017-06-08 15:48:23 +02:00
|
|
|
e := v.OutputValue().Element
|
2017-06-05 04:24:48 +02:00
|
|
|
contract.Assert(!e.IsComputed())
|
2017-05-29 22:08:30 +02:00
|
|
|
w, known := MarshalPropertyValue(ctx, e, opts)
|
|
|
|
contract.Assert(known)
|
|
|
|
return w, false
|
2017-02-20 20:18:47 +01:00
|
|
|
}
|
2017-04-08 16:44:02 +02:00
|
|
|
|
|
|
|
contract.Failf("Unrecognized property value: %v (type=%v)", v.V, reflect.TypeOf(v.V))
|
|
|
|
return nil, true
|
2017-02-20 20:18:47 +01:00
|
|
|
}
|
|
|
|
|
Unmap properties on the receive side
This change makes progress on a few things with respect to properly
receiving properties on the engine side, coming from the provider side,
of the RPC boundary. The issues here are twofold:
1. Properties need to get unmapped using a JSON-tag-sensitive
marshaler, so that they are cased properly, etc. For that, we
have a new mapper.Unmap function (which is ultra lame -- see
pulumi/lumi#138).
2. We have the reverse problem with respect to resource IDs: on
the send side, we must translate from URNs (which the engine
knows about) and provider IDs (which the provider knows about);
similarly, then, on the receive side, we must translate from
provider IDs back into URNs.
As a result of these getting fixed, we can now properly marshal the
resulting properties back into the resource object during the plan
execution, alongside propagating and memoizing its ID.
2017-05-31 20:51:46 +02:00
|
|
|
// UnmarshalProperties unmarshals a "JSON-like" protobuf structure into a new resource property map.
|
|
|
|
func UnmarshalProperties(ctx *Context, props *structpb.Struct, opts MarshalOptions) PropertyMap {
|
2017-02-20 20:18:47 +01:00
|
|
|
result := make(PropertyMap)
|
2017-06-01 17:23:59 +02:00
|
|
|
if props != nil {
|
|
|
|
UnmarshalPropertiesInto(ctx, props, result, opts)
|
|
|
|
}
|
Unmap properties on the receive side
This change makes progress on a few things with respect to properly
receiving properties on the engine side, coming from the provider side,
of the RPC boundary. The issues here are twofold:
1. Properties need to get unmapped using a JSON-tag-sensitive
marshaler, so that they are cased properly, etc. For that, we
have a new mapper.Unmap function (which is ultra lame -- see
pulumi/lumi#138).
2. We have the reverse problem with respect to resource IDs: on
the send side, we must translate from URNs (which the engine
knows about) and provider IDs (which the provider knows about);
similarly, then, on the receive side, we must translate from
provider IDs back into URNs.
As a result of these getting fixed, we can now properly marshal the
resulting properties back into the resource object during the plan
execution, alongside propagating and memoizing its ID.
2017-05-31 20:51:46 +02:00
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
2017-06-05 04:24:48 +02:00
|
|
|
// UnmarshalPropertiesInto unmarshals a "JSON-like" protobuf structure into an existing resource property map.
|
|
|
|
func UnmarshalPropertiesInto(ctx *Context, props *structpb.Struct, t PropertyMap, opts MarshalOptions) {
|
Unmap properties on the receive side
This change makes progress on a few things with respect to properly
receiving properties on the engine side, coming from the provider side,
of the RPC boundary. The issues here are twofold:
1. Properties need to get unmapped using a JSON-tag-sensitive
marshaler, so that they are cased properly, etc. For that, we
have a new mapper.Unmap function (which is ultra lame -- see
pulumi/lumi#138).
2. We have the reverse problem with respect to resource IDs: on
the send side, we must translate from URNs (which the engine
knows about) and provider IDs (which the provider knows about);
similarly, then, on the receive side, we must translate from
provider IDs back into URNs.
As a result of these getting fixed, we can now properly marshal the
resulting properties back into the resource object during the plan
execution, alongside propagating and memoizing its ID.
2017-05-31 20:51:46 +02:00
|
|
|
contract.Assert(props != nil)
|
2017-02-20 20:18:47 +01:00
|
|
|
|
|
|
|
// First sort the keys so we enumerate them in order (in case errors happen, we want determinism).
|
|
|
|
var keys []string
|
|
|
|
for k := range props.Fields {
|
|
|
|
keys = append(keys, k)
|
|
|
|
}
|
|
|
|
sort.Strings(keys)
|
|
|
|
|
|
|
|
// And now unmarshal every field it into the map.
|
|
|
|
for _, k := range keys {
|
Unmap properties on the receive side
This change makes progress on a few things with respect to properly
receiving properties on the engine side, coming from the provider side,
of the RPC boundary. The issues here are twofold:
1. Properties need to get unmapped using a JSON-tag-sensitive
marshaler, so that they are cased properly, etc. For that, we
have a new mapper.Unmap function (which is ultra lame -- see
pulumi/lumi#138).
2. We have the reverse problem with respect to resource IDs: on
the send side, we must translate from URNs (which the engine
knows about) and provider IDs (which the provider knows about);
similarly, then, on the receive side, we must translate from
provider IDs back into URNs.
As a result of these getting fixed, we can now properly marshal the
resulting properties back into the resource object during the plan
execution, alongside propagating and memoizing its ID.
2017-05-31 20:51:46 +02:00
|
|
|
pk := PropertyKey(k)
|
2017-06-01 19:09:52 +02:00
|
|
|
v := t[pk]
|
Unmap properties on the receive side
This change makes progress on a few things with respect to properly
receiving properties on the engine side, coming from the provider side,
of the RPC boundary. The issues here are twofold:
1. Properties need to get unmapped using a JSON-tag-sensitive
marshaler, so that they are cased properly, etc. For that, we
have a new mapper.Unmap function (which is ultra lame -- see
pulumi/lumi#138).
2. We have the reverse problem with respect to resource IDs: on
the send side, we must translate from URNs (which the engine
knows about) and provider IDs (which the provider knows about);
similarly, then, on the receive side, we must translate from
provider IDs back into URNs.
As a result of these getting fixed, we can now properly marshal the
resulting properties back into the resource object during the plan
execution, alongside propagating and memoizing its ID.
2017-05-31 20:51:46 +02:00
|
|
|
UnmarshalPropertyValueInto(ctx, props.Fields[k], &v, opts)
|
2017-06-05 04:24:48 +02:00
|
|
|
contract.Assert(!v.IsComputed())
|
Unmap properties on the receive side
This change makes progress on a few things with respect to properly
receiving properties on the engine side, coming from the provider side,
of the RPC boundary. The issues here are twofold:
1. Properties need to get unmapped using a JSON-tag-sensitive
marshaler, so that they are cased properly, etc. For that, we
have a new mapper.Unmap function (which is ultra lame -- see
pulumi/lumi#138).
2. We have the reverse problem with respect to resource IDs: on
the send side, we must translate from URNs (which the engine
knows about) and provider IDs (which the provider knows about);
similarly, then, on the receive side, we must translate from
provider IDs back into URNs.
As a result of these getting fixed, we can now properly marshal the
resulting properties back into the resource object during the plan
execution, alongside propagating and memoizing its ID.
2017-05-31 20:51:46 +02:00
|
|
|
t[pk] = v
|
2017-02-20 20:18:47 +01:00
|
|
|
}
|
Unmap properties on the receive side
This change makes progress on a few things with respect to properly
receiving properties on the engine side, coming from the provider side,
of the RPC boundary. The issues here are twofold:
1. Properties need to get unmapped using a JSON-tag-sensitive
marshaler, so that they are cased properly, etc. For that, we
have a new mapper.Unmap function (which is ultra lame -- see
pulumi/lumi#138).
2. We have the reverse problem with respect to resource IDs: on
the send side, we must translate from URNs (which the engine
knows about) and provider IDs (which the provider knows about);
similarly, then, on the receive side, we must translate from
provider IDs back into URNs.
As a result of these getting fixed, we can now properly marshal the
resulting properties back into the resource object during the plan
execution, alongside propagating and memoizing its ID.
2017-05-31 20:51:46 +02:00
|
|
|
}
|
2017-02-20 20:18:47 +01:00
|
|
|
|
Unmap properties on the receive side
This change makes progress on a few things with respect to properly
receiving properties on the engine side, coming from the provider side,
of the RPC boundary. The issues here are twofold:
1. Properties need to get unmapped using a JSON-tag-sensitive
marshaler, so that they are cased properly, etc. For that, we
have a new mapper.Unmap function (which is ultra lame -- see
pulumi/lumi#138).
2. We have the reverse problem with respect to resource IDs: on
the send side, we must translate from URNs (which the engine
knows about) and provider IDs (which the provider knows about);
similarly, then, on the receive side, we must translate from
provider IDs back into URNs.
As a result of these getting fixed, we can now properly marshal the
resulting properties back into the resource object during the plan
execution, alongside propagating and memoizing its ID.
2017-05-31 20:51:46 +02:00
|
|
|
// UnmarshalPropertyValue unmarshals a single "JSON-like" value into a new property value.
|
|
|
|
func UnmarshalPropertyValue(ctx *Context, v *structpb.Value, opts MarshalOptions) PropertyValue {
|
|
|
|
var result PropertyValue
|
|
|
|
UnmarshalPropertyValueInto(ctx, v, &result, opts)
|
2017-02-20 20:18:47 +01:00
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
Unmap properties on the receive side
This change makes progress on a few things with respect to properly
receiving properties on the engine side, coming from the provider side,
of the RPC boundary. The issues here are twofold:
1. Properties need to get unmapped using a JSON-tag-sensitive
marshaler, so that they are cased properly, etc. For that, we
have a new mapper.Unmap function (which is ultra lame -- see
pulumi/lumi#138).
2. We have the reverse problem with respect to resource IDs: on
the send side, we must translate from URNs (which the engine
knows about) and provider IDs (which the provider knows about);
similarly, then, on the receive side, we must translate from
provider IDs back into URNs.
As a result of these getting fixed, we can now properly marshal the
resulting properties back into the resource object during the plan
execution, alongside propagating and memoizing its ID.
2017-05-31 20:51:46 +02:00
|
|
|
// UnmarshalPropertyValueInto unmarshals a single "JSON-like" value into an existing property value slot. The existing
|
|
|
|
// slot may be used to drive transformations, if necessary, such as recovering resource URNs on the receiver side.
|
|
|
|
func UnmarshalPropertyValueInto(ctx *Context, v *structpb.Value, t *PropertyValue, opts MarshalOptions) {
|
|
|
|
contract.Assert(v != nil)
|
|
|
|
|
|
|
|
switch v.Kind.(type) {
|
|
|
|
case *structpb.Value_NullValue:
|
|
|
|
contract.Assert(t.CanNull())
|
|
|
|
*t = NewNullProperty()
|
|
|
|
case *structpb.Value_BoolValue:
|
|
|
|
contract.Assert(t.CanBool())
|
|
|
|
*t = NewBoolProperty(v.GetBoolValue())
|
|
|
|
case *structpb.Value_NumberValue:
|
|
|
|
contract.Assert(t.CanNumber())
|
|
|
|
*t = NewNumberProperty(v.GetNumberValue())
|
|
|
|
case *structpb.Value_StringValue:
|
|
|
|
// In the case of a string, the target may be either a resource URN or a real string.
|
|
|
|
s := v.GetStringValue()
|
|
|
|
if t.CanString() || opts.RawResources {
|
|
|
|
*t = NewStringProperty(s)
|
|
|
|
} else {
|
|
|
|
// During unmarshaling, we must translate from the expected resource wire format of a provider ID, back
|
|
|
|
// into its Lumi side URN. There are cases when this is not desirable, most notably, when a resource
|
|
|
|
// provider is unmarshaling data for its own consumption (as is the case for receiving payloads from Lumi,
|
|
|
|
// for instance). In such cases, RawResources == true, and those will end up as simple strings (above).
|
|
|
|
contract.Assert(t.CanResource())
|
|
|
|
contract.Assertf(ctx != nil, "Resource encountered with a nil context; URN not recoverable")
|
|
|
|
id := ID(s)
|
|
|
|
urn, has := ctx.IDURN[id]
|
|
|
|
contract.Assertf(has, "Expected resource ID '%v' to have a URN; none found", id)
|
|
|
|
glog.V(7).Infof("Deserializing resource ID '%v' as URN '%v' (raw=%v)", id, urn, opts.RawResources)
|
|
|
|
*t = NewResourceProperty(urn)
|
|
|
|
}
|
|
|
|
case *structpb.Value_ListValue:
|
|
|
|
contract.Assert(t.CanArray())
|
|
|
|
|
|
|
|
// If there's already an array, prefer to swap elements within it.
|
|
|
|
var elems []PropertyValue
|
|
|
|
if t.IsArray() {
|
|
|
|
elems = t.ArrayValue()
|
|
|
|
}
|
|
|
|
|
|
|
|
lst := v.GetListValue()
|
|
|
|
for i, elem := range lst.GetValues() {
|
|
|
|
if i == len(elems) {
|
|
|
|
elems = append(elems, PropertyValue{})
|
2017-02-20 20:18:47 +01:00
|
|
|
}
|
Unmap properties on the receive side
This change makes progress on a few things with respect to properly
receiving properties on the engine side, coming from the provider side,
of the RPC boundary. The issues here are twofold:
1. Properties need to get unmapped using a JSON-tag-sensitive
marshaler, so that they are cased properly, etc. For that, we
have a new mapper.Unmap function (which is ultra lame -- see
pulumi/lumi#138).
2. We have the reverse problem with respect to resource IDs: on
the send side, we must translate from URNs (which the engine
knows about) and provider IDs (which the provider knows about);
similarly, then, on the receive side, we must translate from
provider IDs back into URNs.
As a result of these getting fixed, we can now properly marshal the
resulting properties back into the resource object during the plan
execution, alongside propagating and memoizing its ID.
2017-05-31 20:51:46 +02:00
|
|
|
contract.Assert(len(elems) > i)
|
|
|
|
UnmarshalPropertyValueInto(ctx, elem, &elems[i], opts)
|
2017-02-20 20:18:47 +01:00
|
|
|
}
|
Unmap properties on the receive side
This change makes progress on a few things with respect to properly
receiving properties on the engine side, coming from the provider side,
of the RPC boundary. The issues here are twofold:
1. Properties need to get unmapped using a JSON-tag-sensitive
marshaler, so that they are cased properly, etc. For that, we
have a new mapper.Unmap function (which is ultra lame -- see
pulumi/lumi#138).
2. We have the reverse problem with respect to resource IDs: on
the send side, we must translate from URNs (which the engine
knows about) and provider IDs (which the provider knows about);
similarly, then, on the receive side, we must translate from
provider IDs back into URNs.
As a result of these getting fixed, we can now properly marshal the
resulting properties back into the resource object during the plan
execution, alongside propagating and memoizing its ID.
2017-05-31 20:51:46 +02:00
|
|
|
*t = NewArrayProperty(elems)
|
|
|
|
case *structpb.Value_StructValue:
|
|
|
|
contract.Assert(t.CanObject())
|
|
|
|
|
|
|
|
// If there's already an object, prefer to swap existing properties.
|
|
|
|
var obj PropertyMap
|
|
|
|
if t.IsObject() {
|
|
|
|
obj = t.ObjectValue()
|
|
|
|
} else {
|
|
|
|
obj = make(PropertyMap)
|
|
|
|
*t = NewObjectProperty(obj)
|
|
|
|
}
|
|
|
|
|
|
|
|
UnmarshalPropertiesInto(ctx, v.GetStructValue(), obj, opts)
|
|
|
|
default:
|
|
|
|
contract.Failf("Unrecognized structpb value kind: %v", reflect.TypeOf(v.Kind))
|
2017-02-20 20:18:47 +01:00
|
|
|
}
|
|
|
|
}
|