We pass this information for Diff and Check on specific resources, so we can correctly block unknows from flowing to plugins during applies.
210 lines
5.9 KiB
Go
210 lines
5.9 KiB
Go
package deploy
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
"github.com/pkg/errors"
|
|
uuid "github.com/satori/go.uuid"
|
|
|
|
"github.com/pulumi/pulumi/pkg/resource"
|
|
"github.com/pulumi/pulumi/pkg/resource/plugin"
|
|
"github.com/pulumi/pulumi/pkg/tokens"
|
|
"github.com/pulumi/pulumi/pkg/util/contract"
|
|
"github.com/pulumi/pulumi/pkg/workspace"
|
|
)
|
|
|
|
type builtinProvider struct {
|
|
backendClient BackendClient
|
|
context context.Context
|
|
cancel context.CancelFunc
|
|
}
|
|
|
|
func newBuiltinProvider(backendClient BackendClient) *builtinProvider {
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
return &builtinProvider{
|
|
backendClient: backendClient,
|
|
context: ctx,
|
|
cancel: cancel,
|
|
}
|
|
}
|
|
|
|
func (p *builtinProvider) Close() error {
|
|
return nil
|
|
}
|
|
|
|
func (p *builtinProvider) Pkg() tokens.Package {
|
|
return "pulumi"
|
|
}
|
|
|
|
// CheckConfig validates the configuration for this resource provider.
|
|
func (p *builtinProvider) CheckConfig(urn resource.URN, olds,
|
|
news resource.PropertyMap, allowUnknowns bool) (resource.PropertyMap, []plugin.CheckFailure, error) {
|
|
|
|
return nil, nil, nil
|
|
}
|
|
|
|
// DiffConfig checks what impacts a hypothetical change to this provider's configuration will have on the provider.
|
|
func (p *builtinProvider) DiffConfig(urn resource.URN, olds, news resource.PropertyMap,
|
|
allowUnknowns bool) (plugin.DiffResult, error) {
|
|
return plugin.DiffResult{Changes: plugin.DiffNone}, nil
|
|
}
|
|
|
|
func (p *builtinProvider) Configure(props resource.PropertyMap) error {
|
|
return nil
|
|
}
|
|
|
|
const stackReferenceType = "pulumi:pulumi:StackReference"
|
|
|
|
func (p *builtinProvider) Check(urn resource.URN, state, inputs resource.PropertyMap,
|
|
allowUnknowns bool) (resource.PropertyMap, []plugin.CheckFailure, error) {
|
|
|
|
typ := urn.Type()
|
|
if typ != stackReferenceType {
|
|
return nil, nil, errors.Errorf("unrecognized resource type '%v'", urn.Type())
|
|
}
|
|
|
|
var name resource.PropertyValue
|
|
for k := range inputs {
|
|
if k != "name" {
|
|
return nil, []plugin.CheckFailure{{Property: k, Reason: fmt.Sprintf("unknown property \"%v\"", k)}}, nil
|
|
}
|
|
}
|
|
|
|
name, ok := inputs["name"]
|
|
if !ok {
|
|
return nil, []plugin.CheckFailure{{Property: "name", Reason: `missing required property "name"`}}, nil
|
|
}
|
|
if !name.IsString() && !name.IsComputed() {
|
|
return nil, []plugin.CheckFailure{{Property: "name", Reason: `property "name" must be a string`}}, nil
|
|
}
|
|
return inputs, nil, nil
|
|
}
|
|
|
|
func (p *builtinProvider) Diff(urn resource.URN, id resource.ID, state, inputs resource.PropertyMap,
|
|
allowUnknowns bool) (plugin.DiffResult, error) {
|
|
|
|
contract.Assert(urn.Type() == stackReferenceType)
|
|
|
|
if !inputs["name"].DeepEquals(state["name"]) {
|
|
return plugin.DiffResult{
|
|
Changes: plugin.DiffSome,
|
|
ReplaceKeys: []resource.PropertyKey{"name"},
|
|
}, nil
|
|
}
|
|
|
|
return plugin.DiffResult{Changes: plugin.DiffNone}, nil
|
|
}
|
|
|
|
func (p *builtinProvider) Create(urn resource.URN,
|
|
inputs resource.PropertyMap) (resource.ID, resource.PropertyMap, resource.Status, error) {
|
|
|
|
contract.Assert(urn.Type() == stackReferenceType)
|
|
|
|
state, err := p.readStackReference(inputs)
|
|
if err != nil {
|
|
return "", nil, resource.StatusUnknown, err
|
|
}
|
|
id := resource.ID(uuid.NewV4().String())
|
|
return id, state, resource.StatusOK, nil
|
|
}
|
|
|
|
func (p *builtinProvider) Update(urn resource.URN, id resource.ID, state,
|
|
inputs resource.PropertyMap) (resource.PropertyMap, resource.Status, error) {
|
|
|
|
contract.Failf("unexpected update for builtin resource %v", urn)
|
|
contract.Assert(urn.Type() == stackReferenceType)
|
|
|
|
return state, resource.StatusOK, errors.New("unexpected update for builtin resource")
|
|
}
|
|
|
|
func (p *builtinProvider) Delete(urn resource.URN, id resource.ID,
|
|
state resource.PropertyMap) (resource.Status, error) {
|
|
|
|
contract.Assert(urn.Type() == stackReferenceType)
|
|
|
|
return resource.StatusOK, nil
|
|
}
|
|
|
|
func (p *builtinProvider) Read(urn resource.URN, id resource.ID,
|
|
inputs, state resource.PropertyMap) (plugin.ReadResult, resource.Status, error) {
|
|
|
|
contract.Assert(urn.Type() == stackReferenceType)
|
|
|
|
outputs, err := p.readStackReference(state)
|
|
if err != nil {
|
|
return plugin.ReadResult{}, resource.StatusUnknown, err
|
|
}
|
|
|
|
return plugin.ReadResult{
|
|
Inputs: inputs,
|
|
Outputs: outputs,
|
|
}, resource.StatusOK, nil
|
|
}
|
|
|
|
const readStackResourceOutputs = "pulumi:pulumi:readStackResourceOutputs"
|
|
|
|
func (p *builtinProvider) Invoke(tok tokens.ModuleMember,
|
|
args resource.PropertyMap) (resource.PropertyMap, []plugin.CheckFailure, error) {
|
|
if tok != readStackResourceOutputs {
|
|
return nil, nil, errors.Errorf("unrecognized function name: '%v'", tok)
|
|
}
|
|
|
|
outs, err := p.readStackResourceOutputs(args)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
return outs, nil, nil
|
|
}
|
|
|
|
func (p *builtinProvider) GetPluginInfo() (workspace.PluginInfo, error) {
|
|
// return an error: this should not be called for the builtin provider
|
|
return workspace.PluginInfo{}, errors.New("the builtin provider does not report plugin info")
|
|
}
|
|
|
|
func (p *builtinProvider) SignalCancellation() error {
|
|
p.cancel()
|
|
return nil
|
|
}
|
|
|
|
func (p *builtinProvider) readStackReference(inputs resource.PropertyMap) (resource.PropertyMap, error) {
|
|
name, ok := inputs["name"]
|
|
contract.Assert(ok)
|
|
contract.Assert(name.IsString())
|
|
|
|
if p.backendClient == nil {
|
|
return nil, errors.New("no backend client is available")
|
|
}
|
|
|
|
outputs, err := p.backendClient.GetStackOutputs(p.context, name.StringValue())
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return resource.PropertyMap{
|
|
"name": name,
|
|
"outputs": resource.NewObjectProperty(outputs),
|
|
}, nil
|
|
}
|
|
|
|
func (p *builtinProvider) readStackResourceOutputs(inputs resource.PropertyMap) (resource.PropertyMap, error) {
|
|
name, ok := inputs["stackName"]
|
|
contract.Assert(ok)
|
|
contract.Assert(name.IsString())
|
|
|
|
if p.backendClient == nil {
|
|
return nil, errors.New("no backend client is available")
|
|
}
|
|
|
|
outputs, err := p.backendClient.GetStackResourceOutputs(p.context, name.StringValue())
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return resource.PropertyMap{
|
|
"name": name,
|
|
"outputs": resource.NewObjectProperty(outputs),
|
|
}, nil
|
|
}
|