Skip to content

Commit e744083

Browse files
authored
Merge pull request #379 from hashicorp/deprecate-exists
Deprecate Exists
2 parents 3a14f25 + b54d0fe commit e744083

File tree

9 files changed

+80
-50
lines changed

9 files changed

+80
-50
lines changed

helper/resource/state.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,5 +276,6 @@ func (conf *StateChangeConf) WaitForStateContext(ctx context.Context) (interface
276276
//
277277
// Deprecated: Please use WaitForStateContext to ensure proper plugin shutdown
278278
func (conf *StateChangeConf) WaitForState() (interface{}, error) {
279+
log.Printf("[WARN] WaitForState is deprecated, please use WaitForStateContext")
279280
return conf.WaitForStateContext(context.Background())
280281
}

helper/resource/wait.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package resource
33
import (
44
"context"
55
"errors"
6+
"log"
67
"sync"
78
"time"
89
)
@@ -65,6 +66,7 @@ func RetryContext(ctx context.Context, timeout time.Duration, f RetryFunc) error
6566
//
6667
// Deprecated: Please use RetryContext to ensure proper plugin shutdown
6768
func Retry(timeout time.Duration, f RetryFunc) error {
69+
log.Printf("[WARN] Retry is deprecated, please use RetryContext")
6870
return RetryContext(context.Background(), timeout, f)
6971
}
7072

helper/schema/provider.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"errors"
66
"fmt"
7+
"log"
78
"sort"
89

910
"github.com/hashicorp/go-multierror"
@@ -89,6 +90,10 @@ func (p *Provider) InternalValidate() error {
8990
return errors.New("provider is nil")
9091
}
9192

93+
if p.ConfigureFunc != nil && p.ConfigureContextFunc != nil {
94+
return errors.New("ConfigureFunc and ConfigureContextFunc must not both be set")
95+
}
96+
9297
var validationErrors error
9398
sm := schemaMap(p.Schema)
9499
if err := sm.InternalValidate(sm); err != nil {
@@ -114,6 +119,11 @@ func (p *Provider) InternalValidate() error {
114119
}
115120
}
116121

122+
// Warn of deprecations
123+
if p.ConfigureFunc != nil && p.ConfigureContextFunc == nil {
124+
log.Printf("[WARN] ConfigureFunc is deprecated, please use ConfigureContextFunc")
125+
}
126+
117127
return validationErrors
118128
}
119129

helper/schema/provider_test.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -540,6 +540,23 @@ func TestProvider_InternalValidate(t *testing.T) {
540540
},
541541
ExpectedErr: fmt.Errorf("%s is a reserved field name for a provider", "alias"),
542542
},
543+
{ // ConfigureFunc and ConfigureContext cannot both be set
544+
P: &Provider{
545+
Schema: map[string]*Schema{
546+
"foo": {
547+
Type: TypeString,
548+
Optional: true,
549+
},
550+
},
551+
ConfigureFunc: func(d *ResourceData) (interface{}, error) {
552+
return nil, nil
553+
},
554+
ConfigureContextFunc: func(ctx context.Context, d *ResourceData) (interface{}, error) {
555+
return nil, nil
556+
},
557+
},
558+
ExpectedErr: fmt.Errorf("ConfigureFunc and ConfigureContextFunc must not both be set"),
559+
},
543560
}
544561

545562
for i, tc := range cases {

helper/schema/resource.go

Lines changed: 32 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -103,11 +103,20 @@ type Resource struct {
103103
Read ReadFunc
104104
Update UpdateFunc
105105
Delete DeleteFunc
106+
107+
// Exists is a function that is called to check if a resource still
108+
// exists. If this returns false, then this will affect the diff
109+
// accordingly. If this function isn't set, it will not be called. You
110+
// can also signal existence in the Read method by calling d.SetId("")
111+
// if the Resource is no longer present and should be removed from state.
112+
// The *ResourceData passed to Exists should _not_ be modified.
113+
//
114+
// Deprecated: ReadContext should be able to encapsulate the logic of Exists
106115
Exists ExistsFunc
107116

108117
// The functions below are the CRUD operations for this resource.
109118
//
110-
// The only optional operation is Update and Exists. If Update is not
119+
// The only optional operation is Update. If Update is not
111120
// implemented, then updates will not be supported for this resource.
112121
//
113122
// The ResourceData parameter in the functions below are used to
@@ -120,20 +129,11 @@ type Resource struct {
120129
// to store API clients, configuration structures, etc.
121130
//
122131
// If any errors occur during each of the operation, an error should be
123-
// returned. If a resource was partially updated, be careful to enable
124-
// partial state mode for ResourceData and use it accordingly.
125-
//
126-
// Exists is a function that is called to check if a resource still
127-
// exists. If this returns false, then this will affect the diff
128-
// accordingly. If this function isn't set, it will not be called. You
129-
// can also signal existence in the Read method by calling d.SetId("")
130-
// if the Resource is no longer present and should be removed from state.
131-
// The *ResourceData passed to Exists should _not_ be modified.
132+
// returned.
132133
CreateContext CreateContextFunc
133134
ReadContext ReadContextFunc
134135
UpdateContext UpdateContextFunc
135136
DeleteContext DeleteContextFunc
136-
ExistsContext ExistsContextFunc
137137

138138
// CustomizeDiff is a custom function for working with the diff that
139139
// Terraform has created for this resource - it can be used to customize the
@@ -233,9 +233,6 @@ type UpdateContextFunc func(context.Context, *ResourceData, interface{}) error
233233
// See Resource documentation.
234234
type DeleteContextFunc func(context.Context, *ResourceData, interface{}) error
235235

236-
// See Resource documentation.
237-
type ExistsContextFunc func(context.Context, *ResourceData, interface{}) (bool, error)
238-
239236
// See Resource documentation.
240237
type StateMigrateFunc func(
241238
int, *terraform.InstanceState, interface{}) (*terraform.InstanceState, error)
@@ -300,15 +297,6 @@ func (r *Resource) delete(ctx context.Context, d *ResourceData, meta interface{}
300297
return r.DeleteContext(ctx, d, meta)
301298
}
302299

303-
func (r *Resource) exists(ctx context.Context, d *ResourceData, meta interface{}) (bool, error) {
304-
if r.Exists != nil {
305-
return r.Exists(d, meta)
306-
}
307-
ctx, cancel := context.WithTimeout(ctx, d.Timeout(TimeoutRead))
308-
defer cancel()
309-
return r.ExistsContext(ctx, d, meta)
310-
}
311-
312300
// Apply creates, updates, and/or deletes a resource.
313301
func (r *Resource) Apply(
314302
ctx context.Context,
@@ -505,7 +493,7 @@ func (r *Resource) RefreshWithoutUpgrade(
505493
}
506494
}
507495

508-
if r.existsFuncSet() {
496+
if r.Exists != nil {
509497
// Make a copy of data so that if it is modified it doesn't
510498
// affect our Read later.
511499
data, err := schemaMap(r.Schema).Data(s, nil)
@@ -515,7 +503,7 @@ func (r *Resource) RefreshWithoutUpgrade(
515503
return s, err
516504
}
517505

518-
exists, err := r.exists(ctx, data, meta)
506+
exists, err := r.Exists(data, meta)
519507

520508
if err != nil {
521509
return s, err
@@ -557,10 +545,6 @@ func (r *Resource) deleteFuncSet() bool {
557545
return (r.Delete != nil || r.DeleteContext != nil)
558546
}
559547

560-
func (r *Resource) existsFuncSet() bool {
561-
return (r.Exists != nil || r.ExistsContext != nil)
562-
}
563-
564548
// InternalValidate should be called to validate the structure
565549
// of the resource.
566550
//
@@ -688,8 +672,25 @@ func (r *Resource) InternalValidate(topSchemaMap schemaMap, writable bool) error
688672
if r.DeleteContext != nil && r.Delete != nil {
689673
return fmt.Errorf("DeleteContext and Delete should not both be set")
690674
}
691-
if r.ExistsContext != nil && r.Exists != nil {
692-
return fmt.Errorf("ExistsContext and Exists should not both be set")
675+
676+
// Warn of deprecations
677+
if r.Exists != nil {
678+
log.Printf("[WARN] Exists is deprecated, please encapsulate the logic in ReadContext")
679+
}
680+
if r.Create != nil && r.CreateContext == nil {
681+
log.Printf("[WARN] Create is deprecated, please use CreateContext")
682+
}
683+
if r.Read != nil && r.ReadContext == nil {
684+
log.Printf("[WARN] Read is deprecated, please use ReadContext")
685+
}
686+
if r.Update != nil && r.UpdateContext == nil {
687+
log.Printf("[WARN] Update is deprecated, please use UpdateContext")
688+
}
689+
if r.Delete != nil && r.DeleteContext == nil {
690+
log.Printf("[WARN] Delete is deprecated, please use DeleteContext")
691+
}
692+
if r.MigrateState != nil {
693+
log.Printf("[WARN] MigrateState is deprecated, please use StateUpgraders")
693694
}
694695

695696
return schemaMap(r.Schema).InternalValidate(tsm)

helper/schema/resource_importer.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package schema
33
import (
44
"context"
55
"errors"
6+
"log"
67
)
78

89
// ResourceImporter defines how a resource is imported in Terraform. This
@@ -59,6 +60,9 @@ func (r *ResourceImporter) InternalValidate() error {
5960
if r.State != nil && r.StateContext != nil {
6061
return errors.New("Both State and StateContext cannot be set.")
6162
}
63+
if r.State != nil && r.StateContext == nil {
64+
log.Printf("[WARN] State is deprecated, please use StateContext")
65+
}
6266
return nil
6367
}
6468

@@ -67,6 +71,7 @@ func (r *ResourceImporter) InternalValidate() error {
6771
//
6872
// Deprecated: Please use the context aware ImportStatePassthroughContext instead
6973
func ImportStatePassthrough(d *ResourceData, m interface{}) ([]*ResourceData, error) {
74+
log.Printf("[WARN] ImportStatePassthrough is deprecated, please use ImportStatePassthroughContext")
7075
return []*ResourceData{d}, nil
7176
}
7277

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package schema
2+
3+
import "testing"
4+
5+
func TestInternalValidate(t *testing.T) {
6+
r := &ResourceImporter{
7+
State: ImportStatePassthrough,
8+
StateContext: ImportStatePassthroughContext,
9+
}
10+
if err := r.InternalValidate(); err == nil {
11+
t.Fatal("ResourceImporter should not allow State and StateContext to be set")
12+
}
13+
}

helper/schema/resource_test.go

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -928,24 +928,6 @@ func TestResourceInternalValidate(t *testing.T) {
928928
true,
929929
true,
930930
},
931-
19: { // Exists and ExistsContext should not both be set
932-
&Resource{
933-
Create: Noop,
934-
Read: Noop,
935-
Update: Noop,
936-
Delete: Noop,
937-
Exists: func(*ResourceData, interface{}) (bool, error) { return false, nil },
938-
ExistsContext: func(context.Context, *ResourceData, interface{}) (bool, error) { return false, nil },
939-
Schema: map[string]*Schema{
940-
"foo": {
941-
Type: TypeString,
942-
Required: true,
943-
},
944-
},
945-
},
946-
true,
947-
true,
948-
},
949931
}
950932

951933
for i, tc := range cases {

internal/helper/plugin/grpc_provider.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -360,7 +360,6 @@ func (s *GRPCProviderServer) upgradeFlatmapState(ctx context.Context, version in
360360
"schema_version": strconv.Itoa(version),
361361
},
362362
}
363-
364363
is, err := res.MigrateState(version, is, s.provider.Meta())
365364
if err != nil {
366365
return nil, 0, err

0 commit comments

Comments
 (0)