Compare commits

...

6 commits

Author SHA1 Message Date
evanboyle 55310b2ac2 read resource go sdk test 2019-11-15 14:06:58 -08:00
evanboyle 536966739d changelog 2019-11-14 19:11:22 -08:00
evanboyle 7fcae87679 remove comment 2019-11-14 19:07:46 -08:00
evanboyle b2f213167d support for ignoreChanges in go sdk 2019-11-14 19:04:06 -08:00
evanboyle 84fcfa37dd Merge branch 'evan/ignoreChanges' of https://github.com/pulumi/pulumi into evan/ignoreChanges 2019-11-14 18:59:00 -08:00
evanboyle 39c6ea2bae checkpoint 2019-11-13 14:33:29 -08:00
4 changed files with 140 additions and 6 deletions

View file

@ -3,6 +3,8 @@ CHANGELOG
## HEAD (Unreleased)
- Add support for IgnoreChanges in the go SDK [#3514](https://github.com/pulumi/pulumi/pull/3514)
- Support for a `go run` style workflow. Building or installing a pulumi program written in go is
now optional. [3503](https://github.com/pulumi/pulumi/pull/3503)

View file

@ -4946,3 +4946,126 @@ func TestSingleResourceDefaultProviderGolangLifecycle(t *testing.T) {
}
p.Run(t, nil)
}
// This test validates the wiring of the IgnoreChanges prop in the go SDK.
// It doesn't attempt to validate underlying behavior.
func TestIgnoreChangesGolangLifecycle(t *testing.T) {
var expectedIgnoreChanges []string
loaders := []*deploytest.ProviderLoader{
deploytest.NewProviderLoader("pkgA", semver.MustParse("1.0.0"), func() (plugin.Provider, error) {
return &deploytest.Provider{
CreateF: func(urn resource.URN,
news resource.PropertyMap, timeout float64) (resource.ID, resource.PropertyMap, resource.Status, error) {
return "created-id", news, resource.StatusOK, nil
},
ReadF: func(urn resource.URN, id resource.ID,
inputs, state resource.PropertyMap) (plugin.ReadResult, resource.Status, error) {
return plugin.ReadResult{Inputs: inputs, Outputs: state}, resource.StatusOK, nil
},
DiffF: func(urn resource.URN, id resource.ID,
olds, news resource.PropertyMap, ignoreChanges []string) (plugin.DiffResult, error) {
// just verify that the IgnoreChanges prop made it through
assert.Equal(t, expectedIgnoreChanges, ignoreChanges)
return plugin.DiffResult{}, nil
},
}, nil
}),
}
setupAndRunProgram := func(ignoreChanges []string) *deploy.Snapshot {
program := deploytest.NewLanguageRuntime(func(info plugin.RunInfo, monitor *deploytest.ResourceMonitor) error {
ctx, err := pulumi.NewContext(context.Background(), pulumi.RunInfo{
Project: info.Project,
Stack: info.Stack,
Parallel: info.Parallel,
DryRun: info.DryRun,
MonitorAddr: info.MonitorAddress,
})
assert.NoError(t, err)
return pulumi.RunWithContext(ctx, func(ctx *pulumi.Context) error {
opts := pulumi.ResourceOpt{
IgnoreChanges: ignoreChanges,
}
_, err := ctx.RegisterResource("pkgA:m:typA", "resA", true, nil, opts)
assert.NoError(t, err)
return nil
})
})
host := deploytest.NewPluginHost(nil, nil, program, loaders...)
p := &TestPlan{
Options: UpdateOptions{host: host},
Steps: []TestStep{
{
Op: Update,
Validate: func(project workspace.Project, target deploy.Target, j *Journal,
events []Event, res result.Result) result.Result {
for _, event := range events {
if event.Type == ResourcePreEvent {
payload := event.Payload.(ResourcePreEventPayload)
assert.Equal(t, []deploy.StepOp{deploy.OpCreate}, []deploy.StepOp{payload.Metadata.Op})
}
}
return res
},
},
},
}
return p.Run(t, nil)
}
// ignore changes specified
ignoreChanges := []string{"b"}
setupAndRunProgram(ignoreChanges)
// ignore changes empty
ignoreChanges = []string{}
setupAndRunProgram(ignoreChanges)
}
func TestReadResourceGolangLifecycle(t *testing.T) {
loaders := []*deploytest.ProviderLoader{
deploytest.NewProviderLoader("pkgA", semver.MustParse("1.0.0"), func() (plugin.Provider, error) {
return &deploytest.Provider{
ReadF: func(urn resource.URN, id resource.ID,
inputs, state resource.PropertyMap) (plugin.ReadResult, resource.Status, error) {
return plugin.ReadResult{Inputs: inputs, Outputs: state}, resource.StatusOK, nil
},
}, nil
}),
}
setupAndRunProgram := func() *deploy.Snapshot {
program := deploytest.NewLanguageRuntime(func(info plugin.RunInfo, monitor *deploytest.ResourceMonitor) error {
ctx, err := pulumi.NewContext(context.Background(), pulumi.RunInfo{
Project: info.Project,
Stack: info.Stack,
Parallel: info.Parallel,
DryRun: info.DryRun,
MonitorAddr: info.MonitorAddress,
})
assert.NoError(t, err)
return pulumi.RunWithContext(ctx, func(ctx *pulumi.Context) error {
opts := pulumi.ResourceOpt{}
_, err := ctx.ReadResource("pkgA:m:typA", "resA", "someId", map[string]interface{}{}, opts)
assert.NoError(t, err)
return nil
})
})
host := deploytest.NewPluginHost(nil, nil, program, loaders...)
p := &TestPlan{
Options: UpdateOptions{host: host},
Steps: []TestStep{{Op: Update}},
}
return p.Run(t, nil)
}
setupAndRunProgram()
}

View file

@ -287,6 +287,7 @@ func (ctx *Context) RegisterResource(
DeleteBeforeReplace: inputs.deleteBeforeReplace,
ImportId: inputs.importID,
CustomTimeouts: inputs.customTimeouts,
IgnoreChanges: inputs.ignoreChanges,
})
if err != nil {
logging.V(9).Infof("RegisterResource(%s, %s): error: %v", t, name, err)
@ -396,13 +397,14 @@ type resourceInputs struct {
deleteBeforeReplace bool
importID string
customTimeouts *pulumirpc.RegisterResourceRequest_CustomTimeouts
ignoreChanges []string
}
// prepareResourceInputs prepares the inputs for a resource operation, shared between read and register.
func (ctx *Context) prepareResourceInputs(props map[string]interface{}, opts ...ResourceOpt) (*resourceInputs, error) {
// Get the parent and dependency URNs from the options, in addition to the protection bit. If there wasn't an
// explicit parent, and a root stack resource exists, we will automatically parent to that.
parent, optDeps, protect, provider, deleteBeforeReplace, importID, err := ctx.getOpts(opts...)
parent, optDeps, protect, provider, deleteBeforeReplace, importID, ignoreChanges, err := ctx.getOpts(opts...)
if err != nil {
return nil, errors.Wrap(err, "resolving options")
}
@ -455,6 +457,7 @@ func (ctx *Context) prepareResourceInputs(props map[string]interface{}, opts ...
deleteBeforeReplace: deleteBeforeReplace,
importID: string(importID),
customTimeouts: timeouts,
ignoreChanges: ignoreChanges,
}, nil
}
@ -473,13 +476,14 @@ func (ctx *Context) getTimeouts(opts ...ResourceOpt) *pulumirpc.RegisterResource
// getOpts returns a set of resource options from an array of them. This includes the parent URN, any dependency URNs,
// a boolean indicating whether the resource is to be protected, and the URN and ID of the resource's provider, if any.
func (ctx *Context) getOpts(opts ...ResourceOpt) (URN, []URN, bool, string, bool, ID, error) {
func (ctx *Context) getOpts(opts ...ResourceOpt) (URN, []URN, bool, string, bool, ID, []string, error) {
var parent Resource
var deps []Resource
var protect bool
var provider ProviderResource
var deleteBeforeReplace bool
var importID ID
var ignoreChanges []string
for _, opt := range opts {
if parent == nil && opt.Parent != nil {
parent = opt.Parent
@ -499,6 +503,9 @@ func (ctx *Context) getOpts(opts ...ResourceOpt) (URN, []URN, bool, string, bool
if importID == "" && opt.Import != "" {
importID = opt.Import
}
if ignoreChanges == nil && opt.IgnoreChanges != nil {
ignoreChanges = opt.IgnoreChanges
}
}
var parentURN URN
@ -507,7 +514,7 @@ func (ctx *Context) getOpts(opts ...ResourceOpt) (URN, []URN, bool, string, bool
} else {
urn, _, err := parent.URN().await(context.TODO())
if err != nil {
return "", nil, false, "", false, "", err
return "", nil, false, "", false, "", nil, err
}
parentURN = urn
}
@ -518,7 +525,7 @@ func (ctx *Context) getOpts(opts ...ResourceOpt) (URN, []URN, bool, string, bool
for i, r := range deps {
urn, _, err := r.URN().await(context.TODO())
if err != nil {
return "", nil, false, "", false, "", err
return "", nil, false, "", false, "", nil, err
}
depURNs[i] = urn
}
@ -528,12 +535,12 @@ func (ctx *Context) getOpts(opts ...ResourceOpt) (URN, []URN, bool, string, bool
if provider != nil {
pr, err := ctx.resolveProviderReference(provider)
if err != nil {
return "", nil, false, "", false, "", err
return "", nil, false, "", false, "", nil, err
}
providerRef = pr
}
return parentURN, depURNs, protect, providerRef, false, importID, nil
return parentURN, depURNs, protect, providerRef, false, importID, ignoreChanges, nil
}
func (ctx *Context) resolveProviderReference(provider ProviderResource) (string, error) {

View file

@ -69,6 +69,8 @@ type ResourceOpt struct {
Import ID
// CustomTimeouts is an optional configuration block used for CRUD operations
CustomTimeouts *CustomTimeouts
// Ignore changes to any of the specified properties.
IgnoreChanges []string
}
// InvokeOpt contains optional settings that control an invoke's behavior.