forked from fastly/terraform-provider-fastly
-
Notifications
You must be signed in to change notification settings - Fork 0
/
service_crud_attribute_definition.go
139 lines (117 loc) · 5.87 KB
/
service_crud_attribute_definition.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
package fastly
import (
"context"
"fmt"
gofastly "github.com/fastly/go-fastly/v9/fastly"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)
// ServiceCRUDAttributeDefinition is an interface for most ServiceAttributeDefinition implementations which can be
// represented by the four CRUD operations. Most service attributes will fall into this category and should implement
// this interface instead of ServiceAttributeDefinition directly.
//
// An attribute that implements ServiceCRUDAttributeDefinition can use the ToServiceAttributeDefinition function defined
// below in its constructor to convert it to the ServiceAttributeDefinition that the service resources expect.
//
// The requirements for a service attribute to be defined in terms of this interface are:
// - the attribute must be a nested block with a schema type of schema.TypeSet
// - the nested block must have its own "name" attribute which uniquely defines the nested resource
// - the block must support all four of the CRUD operations, or at least Create, Read, and Delete if updating the
// resource is not supported
//
// Some service attributes don't fit into these constraints are better suited to implementing the
// ServiceAttributeDefinition directly. One example is the "package" block in block_fastly_service_package.go, which
// only uses an Update operation, and therefore implements ServiceAttributeDefinition directly without
// ServiceCRUDAttributeDefinition.
type ServiceCRUDAttributeDefinition interface {
// Key returns the name of the nested block. This is used when composing the schema into the parent Service schema.
Key() string
// GetSchema returns the schema.Schema of the nested block. This gets composed into the parent Service schema.
GetSchema() *schema.Schema
// Create should create an instance of the nested block. The resource argument will be a map containing all of the
// attributes from the schema of the nested block. The d argument, of type schema.ResourceData, will contain the
// data for the whole service, so the resource argument should be used for most of the creation parameters. The d
// argument should just be used for things like getting the service ID. The serviceVersion argument should be used
// to decide which version of the service to make updates to. This will be an unlocked version that the base service
// update function created.
Create(ctx context.Context, d *schema.ResourceData, resource map[string]any, serviceVersion int, conn *gofastly.Client) error
// Read should refresh the state of all of the instance of the nested blocks. See the description of Create for more
// details about the arguments.
Read(ctx context.Context, d *schema.ResourceData, resource map[string]any, serviceVersion int, conn *gofastly.Client) error
// Update should make changes to an existing instance of the nested block. The arguments are as described in the
// Create comments, with the exception of modified which will contain only the attributes that have changed.
Update(ctx context.Context, d *schema.ResourceData, resource, modified map[string]any, serviceVersion int, conn *gofastly.Client) error
// Delete should remove the instance of the nested block. See the description of Create for more details about the
// arguments.
Delete(ctx context.Context, d *schema.ResourceData, resource map[string]any, serviceVersion int, conn *gofastly.Client) error
}
// ToServiceAttributeDefinition returns an implementation of ServiceAttributeDefinition for a particular implementation
// of ServiceCRUDAttributeDefinition. It implements the Process and Read methods from ServiceAttributeDefinition using
// the SetDiff functions.
func ToServiceAttributeDefinition(definition ServiceCRUDAttributeDefinition) ServiceAttributeDefinition {
return &blockSetAttributeHandler{definition}
}
// blockSetAttributeHandler provides a base implementation for ServiceAttributeDefinition.
type blockSetAttributeHandler struct {
handler ServiceCRUDAttributeDefinition
}
func (h *blockSetAttributeHandler) Register(s *schema.Resource) error {
s.Schema[h.handler.Key()] = h.handler.GetSchema()
return nil
}
func (h *blockSetAttributeHandler) Read(ctx context.Context, d *schema.ResourceData, s *gofastly.ServiceDetail, conn *gofastly.Client) error {
if s.ActiveVersion == nil {
return fmt.Errorf("error: no service ActiveVersion object")
}
return h.handler.Read(ctx, d, nil, gofastly.ToValue(s.ActiveVersion.Number), conn)
}
func (h *blockSetAttributeHandler) Process(ctx context.Context, d *schema.ResourceData, serviceVersion int, conn *gofastly.Client) error {
oldVal, newVal := d.GetChange(h.handler.Key())
if oldVal == nil {
oldVal = new(schema.Set)
}
if newVal == nil {
newVal = new(schema.Set)
}
oldSet := oldVal.(*schema.Set)
newSet := newVal.(*schema.Set)
setDiff := NewSetDiff(func(resource any) (any, error) {
t, ok := resource.(map[string]any)
if !ok {
return nil, fmt.Errorf("resource failed to be type asserted: %+v", resource)
}
return t["name"], nil
})
diffResult, err := setDiff.Diff(oldSet, newSet)
if err != nil {
return err
}
for _, resource := range diffResult.Deleted {
resource := resource.(map[string]any)
err := h.handler.Delete(ctx, d, resource, serviceVersion, conn)
if err != nil {
return err
}
}
for _, resource := range diffResult.Added {
resource := resource.(map[string]any)
err := h.handler.Create(ctx, d, resource, serviceVersion, conn)
if err != nil {
return err
}
}
for _, resource := range diffResult.Modified {
resource := resource.(map[string]any)
modified := setDiff.Filter(resource, oldSet)
err := h.handler.Update(ctx, d, resource, modified, serviceVersion, conn)
if err != nil {
return err
}
}
return nil
}
func (h *blockSetAttributeHandler) HasChange(d *schema.ResourceData) bool {
return d.HasChanges(h.handler.Key())
}
func (h *blockSetAttributeHandler) MustProcess(d *schema.ResourceData, _ bool) bool {
return h.HasChange(d)
}