diff --git a/CHANGELOG.md b/CHANGELOG.md index 15cafa964..3c5fc6a9d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,8 @@ -## 0.17.13 (unreleased) +## 0.17.14 (Unreleased) + +### Improvements + +## 0.17.13 (Released May 21, 2019) ### Improvements @@ -12,6 +16,7 @@ - Signature of `Pulumi.all` has been made more accurate. Calling `.all` on `Output`s that may be `undefined` will properly encode and pass along that `undefined` information. - Fix an issue where some operations would fail with `error: could not deserialize deployment: unknown secrets provider type`. +- Fix an issue where pulumi might try to replace existing resources when upgrading to the newest version of some resource providers. ## 0.17.12 (Released May 15, 2019) diff --git a/pkg/resource/deploy/source_eval.go b/pkg/resource/deploy/source_eval.go index cda69653b..272f18203 100644 --- a/pkg/resource/deploy/source_eval.go +++ b/pkg/resource/deploy/source_eval.go @@ -494,18 +494,21 @@ func (rm *resmon) getProvider(req providers.ProviderRequest, rawProviderRef stri } func (rm *resmon) parseProviderRequest(pkg tokens.Package, version string) (providers.ProviderRequest, error) { - if version == "" { - logging.V(5).Infof("parseProviderRequest(%s): semver version is the empty string", pkg) - return providers.NewProviderRequest(nil, pkg), nil - } + return providers.NewProviderRequest(nil, pkg), nil - parsedVersion, err := semver.Parse(version) - if err != nil { - logging.V(5).Infof("parseProviderRequest(%s, %s): semver version string is invalid: %v", pkg, version, err) - return providers.ProviderRequest{}, err - } + // TODO[pulumi/pulumi#2753]: We should re-enable this code once we have a solution for #2753. + // if version == "" { + // logging.V(5).Infof("parseProviderRequest(%s): semver version is the empty string", pkg) + // return providers.NewProviderRequest(nil, pkg), nil + // } - return providers.NewProviderRequest(&parsedVersion, pkg), nil + // parsedVersion, err := semver.Parse(version) + // if err != nil { + // logging.V(5).Infof("parseProviderRequest(%s, %s): semver version string is invalid: %v", pkg, version, err) + // return providers.ProviderRequest{}, err + // } + + // return providers.NewProviderRequest(&parsedVersion, pkg), nil } func (rm *resmon) SupportsFeature(ctx context.Context, diff --git a/pkg/resource/deploy/source_eval_test.go b/pkg/resource/deploy/source_eval_test.go index 1de1b76ed..26a626d87 100644 --- a/pkg/resource/deploy/source_eval_test.go +++ b/pkg/resource/deploy/source_eval_test.go @@ -485,190 +485,192 @@ func TestReadInvokeDefaultProviders(t *testing.T) { assert.Equal(t, expectedInvokes, int(invokes)) } -func TestReadResourceAndInvokeVersion(t *testing.T) { - runInfo := &EvalRunInfo{ - Proj: &workspace.Project{Name: "test"}, - Target: &Target{Name: "test"}, - } +// TODO[pulumi/pulumi#2753]: We should re-enable these tests (and fix them up as needed) once we have a solution +// for #2753. +// func TestReadResourceAndInvokeVersion(t *testing.T) { +// runInfo := &EvalRunInfo{ +// Proj: &workspace.Project{Name: "test"}, +// Target: &Target{Name: "test"}, +// } - newURN := func(t tokens.Type, name string, parent resource.URN) resource.URN { - var pt tokens.Type - if parent != "" { - pt = parent.Type() - } - return resource.NewURN(runInfo.Target.Name, runInfo.Proj.Name, pt, t, tokens.QName(name)) - } +// newURN := func(t tokens.Type, name string, parent resource.URN) resource.URN { +// var pt tokens.Type +// if parent != "" { +// pt = parent.Type() +// } +// return resource.NewURN(runInfo.Target.Name, runInfo.Proj.Name, pt, t, tokens.QName(name)) +// } - invokes := int32(0) - noopProvider := &deploytest.Provider{ - InvokeF: func(tokens.ModuleMember, resource.PropertyMap) (resource.PropertyMap, []plugin.CheckFailure, error) { - atomic.AddInt32(&invokes, 1) - return resource.PropertyMap{}, nil, nil - }, - } +// invokes := int32(0) +// noopProvider := &deploytest.Provider{ +// InvokeF: func(tokens.ModuleMember, resource.PropertyMap) (resource.PropertyMap, []plugin.CheckFailure, error) { +// atomic.AddInt32(&invokes, 1) +// return resource.PropertyMap{}, nil, nil +// }, +// } - // This program is designed to trigger the instantiation of two default providers: - // 1. Provider pkgA, version 0.18.0 - // 2. Provider pkgC, version 0.18.0 - program := func(_ plugin.RunInfo, resmon *deploytest.ResourceMonitor) error { - // Triggers pkgA, v0.18.0. - _, _, err := resmon.ReadResource("pkgA:m:typA", "resA", "id1", "", nil, "", "0.18.0") - assert.NoError(t, err) - // Uses pkgA's already-instantiated provider. - _, _, err = resmon.ReadResource("pkgA:m:typB", "resB", "id1", "", nil, "", "0.18.0") - assert.NoError(t, err) +// // This program is designed to trigger the instantiation of two default providers: +// // 1. Provider pkgA, version 0.18.0 +// // 2. Provider pkgC, version 0.18.0 +// program := func(_ plugin.RunInfo, resmon *deploytest.ResourceMonitor) error { +// // Triggers pkgA, v0.18.0. +// _, _, err := resmon.ReadResource("pkgA:m:typA", "resA", "id1", "", nil, "", "0.18.0") +// assert.NoError(t, err) +// // Uses pkgA's already-instantiated provider. +// _, _, err = resmon.ReadResource("pkgA:m:typB", "resB", "id1", "", nil, "", "0.18.0") +// assert.NoError(t, err) - // Triggers pkgC, v0.18.0. - _, _, err = resmon.ReadResource("pkgC:m:typC", "resC", "id1", "", nil, "", "0.18.0") - assert.NoError(t, err) +// // Triggers pkgC, v0.18.0. +// _, _, err = resmon.ReadResource("pkgC:m:typC", "resC", "id1", "", nil, "", "0.18.0") +// assert.NoError(t, err) - // Uses pkgA and pkgC's already-instantiated provider. - _, _, err = resmon.Invoke("pkgA:m:funcA", nil, "", "0.18.0") - assert.NoError(t, err) - _, _, err = resmon.Invoke("pkgA:m:funcB", nil, "", "0.18.0") - assert.NoError(t, err) - _, _, err = resmon.Invoke("pkgC:m:funcC", nil, "", "0.18.0") - assert.NoError(t, err) +// // Uses pkgA and pkgC's already-instantiated provider. +// _, _, err = resmon.Invoke("pkgA:m:funcA", nil, "", "0.18.0") +// assert.NoError(t, err) +// _, _, err = resmon.Invoke("pkgA:m:funcB", nil, "", "0.18.0") +// assert.NoError(t, err) +// _, _, err = resmon.Invoke("pkgC:m:funcC", nil, "", "0.18.0") +// assert.NoError(t, err) - return nil - } +// return nil +// } - ctx, err := newTestPluginContext(program) - assert.NoError(t, err) +// ctx, err := newTestPluginContext(program) +// assert.NoError(t, err) - providerSource := &testProviderSource{providers: make(map[providers.Reference]plugin.Provider)} +// providerSource := &testProviderSource{providers: make(map[providers.Reference]plugin.Provider)} - iter, res := NewEvalSource(ctx, runInfo, nil, false).Iterate(context.Background(), Options{}, providerSource) - assert.Nil(t, res) - registrations, reads := 0, 0 - for { - event, res := iter.Next() - assert.Nil(t, res) +// iter, res := NewEvalSource(ctx, runInfo, nil, false).Iterate(context.Background(), Options{}, providerSource) +// assert.Nil(t, res) +// registrations, reads := 0, 0 +// for { +// event, res := iter.Next() +// assert.Nil(t, res) - if event == nil { - break - } +// if event == nil { +// break +// } - switch e := event.(type) { - case RegisterResourceEvent: - goal := e.Goal() - urn, id := newURN(goal.Type, string(goal.Name), goal.Parent), resource.ID("id") +// switch e := event.(type) { +// case RegisterResourceEvent: +// goal := e.Goal() +// urn, id := newURN(goal.Type, string(goal.Name), goal.Parent), resource.ID("id") - assert.True(t, providers.IsProviderType(goal.Type)) - // The name of the provider resource is derived from the version requested. - assert.Equal(t, "default_0_18_0", string(goal.Name)) - ref, err := providers.NewReference(urn, id) - assert.NoError(t, err) - _, ok := providerSource.GetProvider(ref) - assert.False(t, ok) - providerSource.registerProvider(ref, noopProvider) +// assert.True(t, providers.IsProviderType(goal.Type)) +// // The name of the provider resource is derived from the version requested. +// assert.Equal(t, "default_0_18_0", string(goal.Name)) +// ref, err := providers.NewReference(urn, id) +// assert.NoError(t, err) +// _, ok := providerSource.GetProvider(ref) +// assert.False(t, ok) +// providerSource.registerProvider(ref, noopProvider) - e.Done(&RegisterResult{ - State: resource.NewState(goal.Type, urn, goal.Custom, false, id, goal.Properties, resource.PropertyMap{}, - goal.Parent, goal.Protect, false, goal.Dependencies, nil, goal.Provider, goal.PropertyDependencies, - false, nil), - }) - registrations++ +// e.Done(&RegisterResult{ +// State: resource.NewState(goal.Type, urn, goal.Custom, false, id, goal.Properties, resource.PropertyMap{}, +// goal.Parent, goal.Protect, false, goal.Dependencies, nil, goal.Provider, goal.PropertyDependencies, +// false, nil), +// }) +// registrations++ - case ReadResourceEvent: - urn := newURN(e.Type(), string(e.Name()), e.Parent()) - e.Done(&ReadResult{ - State: resource.NewState(e.Type(), urn, true, false, e.ID(), e.Properties(), - resource.PropertyMap{}, e.Parent(), false, false, e.Dependencies(), nil, e.Provider(), nil, false, - nil), - }) - reads++ - } - } +// case ReadResourceEvent: +// urn := newURN(e.Type(), string(e.Name()), e.Parent()) +// e.Done(&ReadResult{ +// State: resource.NewState(e.Type(), urn, true, false, e.ID(), e.Properties(), +// resource.PropertyMap{}, e.Parent(), false, false, e.Dependencies(), nil, e.Provider(), nil, false, +// nil), +// }) +// reads++ +// } +// } - assert.Equal(t, 2, registrations) - assert.Equal(t, 3, reads) - assert.Equal(t, int32(3), invokes) -} +// assert.Equal(t, 2, registrations) +// assert.Equal(t, 3, reads) +// assert.Equal(t, int32(3), invokes) +// } -func TestRegisterResourceWithVersion(t *testing.T) { - runInfo := &EvalRunInfo{ - Proj: &workspace.Project{Name: "test"}, - Target: &Target{Name: "test"}, - } +// func TestRegisterResourceWithVersion(t *testing.T) { +// runInfo := &EvalRunInfo{ +// Proj: &workspace.Project{Name: "test"}, +// Target: &Target{Name: "test"}, +// } - newURN := func(t tokens.Type, name string, parent resource.URN) resource.URN { - var pt tokens.Type - if parent != "" { - pt = parent.Type() - } - return resource.NewURN(runInfo.Target.Name, runInfo.Proj.Name, pt, t, tokens.QName(name)) - } +// newURN := func(t tokens.Type, name string, parent resource.URN) resource.URN { +// var pt tokens.Type +// if parent != "" { +// pt = parent.Type() +// } +// return resource.NewURN(runInfo.Target.Name, runInfo.Proj.Name, pt, t, tokens.QName(name)) +// } - noopProvider := &deploytest.Provider{} +// noopProvider := &deploytest.Provider{} - // This program is designed to trigger the instantiation of two default providers: - // 1. Provider pkgA, version 0.18.0 - // 2. Provider pkgC, version 0.18.0 - program := func(_ plugin.RunInfo, resmon *deploytest.ResourceMonitor) error { - // Triggers pkgA, v0.18.1. - _, _, _, err := resmon.RegisterResource("pkgA:m:typA", "resA", true, "", false, nil, "", - resource.PropertyMap{}, nil, false, "0.18.1", nil) - assert.NoError(t, err) +// // This program is designed to trigger the instantiation of two default providers: +// // 1. Provider pkgA, version 0.18.0 +// // 2. Provider pkgC, version 0.18.0 +// program := func(_ plugin.RunInfo, resmon *deploytest.ResourceMonitor) error { +// // Triggers pkgA, v0.18.1. +// _, _, _, err := resmon.RegisterResource("pkgA:m:typA", "resA", true, "", false, nil, "", +// resource.PropertyMap{}, nil, false, "0.18.1", nil) +// assert.NoError(t, err) - // Re-uses pkgA's already-instantiated provider. - _, _, _, err = resmon.RegisterResource("pkgA:m:typA", "resB", true, "", false, nil, "", - resource.PropertyMap{}, nil, false, "0.18.1", nil) - assert.NoError(t, err) +// // Re-uses pkgA's already-instantiated provider. +// _, _, _, err = resmon.RegisterResource("pkgA:m:typA", "resB", true, "", false, nil, "", +// resource.PropertyMap{}, nil, false, "0.18.1", nil) +// assert.NoError(t, err) - // Triggers pkgA, v0.18.2 - _, _, _, err = resmon.RegisterResource("pkgA:m:typA", "resB", true, "", false, nil, "", - resource.PropertyMap{}, nil, false, "0.18.2", nil) - assert.NoError(t, err) - return nil - } +// // Triggers pkgA, v0.18.2 +// _, _, _, err = resmon.RegisterResource("pkgA:m:typA", "resB", true, "", false, nil, "", +// resource.PropertyMap{}, nil, false, "0.18.2", nil) +// assert.NoError(t, err) +// return nil +// } - ctx, err := newTestPluginContext(program) - assert.NoError(t, err) +// ctx, err := newTestPluginContext(program) +// assert.NoError(t, err) - providerSource := &testProviderSource{providers: make(map[providers.Reference]plugin.Provider)} +// providerSource := &testProviderSource{providers: make(map[providers.Reference]plugin.Provider)} - iter, res := NewEvalSource(ctx, runInfo, nil, false).Iterate(context.Background(), Options{}, providerSource) - assert.Nil(t, res) - registered181, registered182 := false, false - for { - event, res := iter.Next() - assert.Nil(t, res) +// iter, res := NewEvalSource(ctx, runInfo, nil, false).Iterate(context.Background(), Options{}, providerSource) +// assert.Nil(t, res) +// registered181, registered182 := false, false +// for { +// event, res := iter.Next() +// assert.Nil(t, res) - if event == nil { - break - } +// if event == nil { +// break +// } - switch e := event.(type) { - case RegisterResourceEvent: - goal := e.Goal() - urn, id := newURN(goal.Type, string(goal.Name), goal.Parent), resource.ID("id") +// switch e := event.(type) { +// case RegisterResourceEvent: +// goal := e.Goal() +// urn, id := newURN(goal.Type, string(goal.Name), goal.Parent), resource.ID("id") - if providers.IsProviderType(goal.Type) { - switch goal.Name { - case "default_0_18_1": - assert.False(t, registered181) - registered181 = true - case "default_0_18_2": - assert.False(t, registered182) - registered182 = true - } +// if providers.IsProviderType(goal.Type) { +// switch goal.Name { +// case "default_0_18_1": +// assert.False(t, registered181) +// registered181 = true +// case "default_0_18_2": +// assert.False(t, registered182) +// registered182 = true +// } - ref, err := providers.NewReference(urn, id) - assert.NoError(t, err) - _, ok := providerSource.GetProvider(ref) - assert.False(t, ok) - providerSource.registerProvider(ref, noopProvider) - } +// ref, err := providers.NewReference(urn, id) +// assert.NoError(t, err) +// _, ok := providerSource.GetProvider(ref) +// assert.False(t, ok) +// providerSource.registerProvider(ref, noopProvider) +// } - e.Done(&RegisterResult{ - State: resource.NewState(goal.Type, urn, goal.Custom, false, id, goal.Properties, resource.PropertyMap{}, - goal.Parent, goal.Protect, false, goal.Dependencies, nil, goal.Provider, goal.PropertyDependencies, - false, nil), - }) - } - } +// e.Done(&RegisterResult{ +// State: resource.NewState(goal.Type, urn, goal.Custom, false, id, goal.Properties, resource.PropertyMap{}, +// goal.Parent, goal.Protect, false, goal.Dependencies, nil, goal.Provider, goal.PropertyDependencies, +// false, nil), +// }) +// } +// } - assert.True(t, registered181) - assert.True(t, registered182) -} +// assert.True(t, registered181) +// assert.True(t, registered182) +// }