|
1 | 1 | package cloudamqp
|
2 | 2 |
|
3 | 3 | import (
|
| 4 | + "context" |
| 5 | + "encoding/json" |
4 | 6 | "fmt"
|
5 | 7 | "log"
|
6 | 8 | "strconv"
|
7 | 9 | "strings"
|
8 | 10 |
|
9 | 11 | "github.com/84codes/go-api/api"
|
10 |
| - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" |
| 12 | + "github.com/hashicorp/terraform-plugin-framework/path" |
| 13 | + "github.com/hashicorp/terraform-plugin-framework/resource" |
| 14 | + "github.com/hashicorp/terraform-plugin-framework/resource/schema" |
| 15 | + "github.com/hashicorp/terraform-plugin-framework/resource/schema/boolplanmodifier" |
| 16 | + "github.com/hashicorp/terraform-plugin-framework/resource/schema/int64planmodifier" |
| 17 | + "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" |
| 18 | + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" |
| 19 | + "github.com/hashicorp/terraform-plugin-framework/types" |
11 | 20 | )
|
12 | 21 |
|
13 |
| -func resourceAwsEventBridge() *schema.Resource { |
14 |
| - return &schema.Resource{ |
15 |
| - Create: resourceAwsEventBridgeCreate, |
16 |
| - Read: resourceAwsEventBridgeRead, |
17 |
| - Delete: resourceAwsEventBridgeDelete, |
18 |
| - Importer: &schema.ResourceImporter{ |
19 |
| - StateContext: schema.ImportStatePassthroughContext, |
20 |
| - }, |
21 |
| - Schema: map[string]*schema.Schema{ |
22 |
| - "instance_id": { |
23 |
| - Type: schema.TypeInt, |
24 |
| - ForceNew: true, |
| 22 | +type awsEventBridgeResource struct { |
| 23 | + client *api.API |
| 24 | +} |
| 25 | + |
| 26 | +type awsEventBridgeResourceModel struct { |
| 27 | + Id types.String `tfsdk:"id"` |
| 28 | + InstanceID types.Int64 `tfsdk:"instance_id"` |
| 29 | + AwsAccountId types.String `tfsdk:"aws_account_id"` |
| 30 | + AwsRegion types.String `tfsdk:"aws_region"` |
| 31 | + Vhost types.String `tfsdk:"vhost"` |
| 32 | + QueueName types.String `tfsdk:"queue"` |
| 33 | + WithHeaders types.Bool `tfsdk:"with_headers"` |
| 34 | + Status types.String `tfsdk:"status"` |
| 35 | +} |
| 36 | + |
| 37 | +type awsEventBridgeResourceApiModel struct { |
| 38 | + AwsAccountId string `json:"aws_account_id"` |
| 39 | + AwsRegion string `json:"aws_region"` |
| 40 | + Vhost string `json:"vhost"` |
| 41 | + QueueName string `json:"queue"` |
| 42 | + WithHeaders bool `json:"with_headers"` |
| 43 | +} |
| 44 | + |
| 45 | +func (r *awsEventBridgeResource) Configure(ctx context.Context, request resource.ConfigureRequest, response *resource.ConfigureResponse) { |
| 46 | + // Always perform a nil check when handling ProviderData because Terraform |
| 47 | + // sets that data after it calls the ConfigureProvider RPC. |
| 48 | + if request.ProviderData == nil { |
| 49 | + return |
| 50 | + } |
| 51 | + |
| 52 | + client, ok := request.ProviderData.(*api.API) |
| 53 | + |
| 54 | + if !ok { |
| 55 | + response.Diagnostics.AddError( |
| 56 | + "Unexpected Resource Configure Type", |
| 57 | + fmt.Sprintf("Expected *api.API, got: %T. Please report this issue to the provider developers.", request.ProviderData), |
| 58 | + ) |
| 59 | + |
| 60 | + return |
| 61 | + } |
| 62 | + |
| 63 | + r.client = client |
| 64 | +} |
| 65 | + |
| 66 | +func (r *awsEventBridgeResource) Metadata(ctx context.Context, request resource.MetadataRequest, response *resource.MetadataResponse) { |
| 67 | + response.TypeName = "cloudamqp_integration_aws_eventbridge" |
| 68 | +} |
| 69 | + |
| 70 | +func (r *awsEventBridgeResource) Schema(ctx context.Context, request resource.SchemaRequest, response *resource.SchemaResponse) { |
| 71 | + response.Schema = schema.Schema{ |
| 72 | + Attributes: map[string]schema.Attribute{ |
| 73 | + "id": schema.StringAttribute{ |
| 74 | + Computed: true, |
| 75 | + }, |
| 76 | + "instance_id": schema.Int64Attribute{ |
25 | 77 | Required: true,
|
26 | 78 | Description: "Instance identifier",
|
| 79 | + PlanModifiers: []planmodifier.Int64{ |
| 80 | + int64planmodifier.RequiresReplace(), |
| 81 | + }, |
27 | 82 | },
|
28 |
| - "aws_account_id": { |
29 |
| - Type: schema.TypeString, |
30 |
| - ForceNew: true, |
| 83 | + "aws_account_id": schema.StringAttribute{ |
31 | 84 | Required: true,
|
32 | 85 | Description: "The 12 digit AWS Account ID where you want the events to be sent to.",
|
| 86 | + PlanModifiers: []planmodifier.String{ |
| 87 | + stringplanmodifier.RequiresReplace(), |
| 88 | + }, |
33 | 89 | },
|
34 |
| - "aws_region": { |
35 |
| - Type: schema.TypeString, |
36 |
| - ForceNew: true, |
| 90 | + "aws_region": schema.StringAttribute{ |
37 | 91 | Required: true,
|
38 | 92 | Description: "The AWS region where you the events to be sent to. (e.g. us-west-1, us-west-2, ..., etc.)",
|
| 93 | + PlanModifiers: []planmodifier.String{ |
| 94 | + stringplanmodifier.RequiresReplace(), |
| 95 | + }, |
39 | 96 | },
|
40 |
| - "vhost": { |
41 |
| - Type: schema.TypeString, |
42 |
| - ForceNew: true, |
| 97 | + "vhost": schema.StringAttribute{ |
43 | 98 | Required: true,
|
44 | 99 | Description: "The VHost the queue resides in.",
|
| 100 | + PlanModifiers: []planmodifier.String{ |
| 101 | + stringplanmodifier.RequiresReplace(), |
| 102 | + }, |
45 | 103 | },
|
46 |
| - "queue": { |
47 |
| - Type: schema.TypeString, |
48 |
| - ForceNew: true, |
| 104 | + "queue": schema.StringAttribute{ |
49 | 105 | Required: true,
|
50 | 106 | Description: "A (durable) queue on your RabbitMQ instance.",
|
| 107 | + PlanModifiers: []planmodifier.String{ |
| 108 | + stringplanmodifier.RequiresReplace(), |
| 109 | + }, |
51 | 110 | },
|
52 |
| - "with_headers": { |
53 |
| - Type: schema.TypeBool, |
54 |
| - ForceNew: true, |
| 111 | + "with_headers": schema.BoolAttribute{ |
55 | 112 | Required: true,
|
56 | 113 | Description: "Include message headers in the event data.",
|
| 114 | + PlanModifiers: []planmodifier.Bool{ |
| 115 | + boolplanmodifier.RequiresReplace(), |
| 116 | + }, |
57 | 117 | },
|
58 |
| - "status": { |
59 |
| - Type: schema.TypeString, |
| 118 | + "status": schema.StringAttribute{ |
60 | 119 | Computed: true,
|
61 | 120 | Description: "Always set to null, unless there is an error starting the EventBridge",
|
62 | 121 | },
|
63 | 122 | },
|
64 | 123 | }
|
65 | 124 | }
|
66 | 125 |
|
67 |
| -func resourceAwsEventBridgeCreate(d *schema.ResourceData, meta interface{}) error { |
68 |
| - var ( |
69 |
| - api = meta.(*api.API) |
70 |
| - keys = awsEventbridgeAttributeKeys() |
71 |
| - params = make(map[string]interface{}) |
72 |
| - instanceID = d.Get("instance_id").(int) |
73 |
| - ) |
| 126 | +func (r *awsEventBridgeResource) Create(ctx context.Context, request resource.CreateRequest, response *resource.CreateResponse) { |
| 127 | + var data awsEventBridgeResourceModel |
| 128 | + |
| 129 | + // Read Terraform plan data into the model |
| 130 | + response.Diagnostics.Append(request.Plan.Get(ctx, &data)...) |
| 131 | + |
| 132 | + if response.Diagnostics.HasError() { |
| 133 | + return |
| 134 | + } |
| 135 | + |
| 136 | + apiModel := awsEventBridgeResourceApiModel{ |
| 137 | + AwsAccountId: data.AwsAccountId.ValueString(), |
| 138 | + AwsRegion: data.AwsRegion.ValueString(), |
| 139 | + Vhost: data.Vhost.ValueString(), |
| 140 | + QueueName: data.QueueName.ValueString(), |
| 141 | + WithHeaders: data.WithHeaders.ValueBool(), |
| 142 | + } |
74 | 143 |
|
75 |
| - for _, k := range keys { |
76 |
| - if v := d.Get(k); v != nil { |
77 |
| - params[k] = v |
78 |
| - } |
| 144 | + var params map[string]interface{} |
| 145 | + temp, err := json.Marshal(apiModel) |
| 146 | + if err != nil { |
| 147 | + response.Diagnostics.AddError( |
| 148 | + "Unable to Create Resource", |
| 149 | + "An unexpected error occurred while creating the resource create request. "+ |
| 150 | + "Please report this issue to the provider developers.\n\n"+ |
| 151 | + "JSON Error: "+err.Error(), |
| 152 | + ) |
| 153 | + return |
79 | 154 | }
|
| 155 | + // TODO: This is totally a hack to get the struct into a map[string]interface{} |
| 156 | + // It is very unlikely this will fail after the first one succeeds, so it should be fine to ignore the error |
| 157 | + // Maybe after the api is moved into the repo we can improve the interface |
| 158 | + _ = json.Unmarshal(temp, ¶ms) |
80 | 159 |
|
81 |
| - data, err := api.CreateAwsEventBridge(instanceID, params) |
| 160 | + apiResponse, err := r.client.CreateAwsEventBridge(int(data.InstanceID.ValueInt64()), params) |
82 | 161 | if err != nil {
|
83 |
| - return err |
| 162 | + response.Diagnostics.AddError( |
| 163 | + "Failed to Create Resource", |
| 164 | + "An error occurred while calling the api to create the surface, verify your permissions are correct.\n\n"+ |
| 165 | + "JSON Error: "+err.Error(), |
| 166 | + ) |
| 167 | + return |
84 | 168 | }
|
85 | 169 |
|
86 |
| - d.SetId(data["id"].(string)) |
87 |
| - return nil |
| 170 | + data.Id = types.StringValue(apiResponse["id"].(string)) |
| 171 | + data.Status = types.StringNull() |
| 172 | + |
| 173 | + // Save data into Terraform state |
| 174 | + response.Diagnostics.Append(response.State.Set(ctx, &data)...) |
88 | 175 | }
|
89 | 176 |
|
90 |
| -func resourceAwsEventBridgeRead(d *schema.ResourceData, meta interface{}) error { |
91 |
| - if strings.Contains(d.Id(), ",") { |
92 |
| - log.Printf("[DEBUG] cloudamqp::resource::aws-eventbridge::read id contains : %v", d.Id()) |
93 |
| - s := strings.Split(d.Id(), ",") |
| 177 | +func (r *awsEventBridgeResource) Read(ctx context.Context, request resource.ReadRequest, response *resource.ReadResponse) { |
| 178 | + var state awsEventBridgeResourceModel |
| 179 | + |
| 180 | + // Read Terraform plan data into the model |
| 181 | + response.Diagnostics.Append(request.State.Get(ctx, &state)...) |
| 182 | + |
| 183 | + if strings.Contains(state.Id.ValueString(), ",") { |
| 184 | + log.Printf("[DEBUG] cloudamqp::resource::aws-eventbridge::read id contains : %v", state.Id.String()) |
| 185 | + s := strings.Split(state.Id.ValueString(), ",") |
94 | 186 | log.Printf("[DEBUG] cloudamqp::resource::aws-eventbridge::read split ids: %v, %v", s[0], s[1])
|
95 |
| - d.SetId(s[0]) |
| 187 | + state.Id = types.StringValue(s[0]) |
96 | 188 | instanceID, _ := strconv.Atoi(s[1])
|
97 |
| - d.Set("instance_id", instanceID) |
| 189 | + state.InstanceID = types.Int64Value(int64(instanceID)) |
98 | 190 | }
|
99 |
| - if d.Get("instance_id").(int) == 0 { |
100 |
| - return fmt.Errorf("missing instance identifier: {resource_id},{instance_id}") |
| 191 | + if state.InstanceID.ValueInt64() == 0 { |
| 192 | + response.Diagnostics.AddError("Missing instance identifier {resource_id},{instance_id}", "") |
| 193 | + return |
101 | 194 | }
|
102 | 195 |
|
103 | 196 | var (
|
104 |
| - api = meta.(*api.API) |
105 |
| - instanceID = d.Get("instance_id").(int) |
| 197 | + id = state.Id.ValueString() |
| 198 | + instanceID = int(state.InstanceID.ValueInt64()) |
106 | 199 | )
|
107 | 200 |
|
108 |
| - log.Printf("[DEBUG] cloudamqp::resource::aws-eventbridge::read ID: %v, instanceID %v", d.Id(), instanceID) |
109 |
| - data, err := api.ReadAwsEventBridge(instanceID, d.Id()) |
| 201 | + log.Printf("[DEBUG] cloudamqp::resource::aws-eventbridge::read ID: %v, instanceID %v", id, instanceID) |
| 202 | + data, err := r.client.ReadAwsEventBridge(instanceID, id) |
110 | 203 | if err != nil {
|
111 |
| - return err |
| 204 | + response.Diagnostics.AddError("Something went wrong while reading the aws event bridge", fmt.Sprintf("%v", err)) |
| 205 | + return |
112 | 206 | }
|
113 | 207 |
|
114 |
| - for k, v := range data { |
115 |
| - if validateAwsEventBridgeSchemaAttribute(k) { |
116 |
| - if v == nil { |
117 |
| - continue |
118 |
| - } |
119 |
| - if err = d.Set(k, v); err != nil { |
120 |
| - return fmt.Errorf("error setting %s for resource %s: %s", k, d.Id(), err) |
121 |
| - } |
122 |
| - } |
123 |
| - } |
| 208 | + state.AwsAccountId = types.StringValue(data["aws_account_id"].(string)) |
| 209 | + state.AwsRegion = types.StringValue(data["aws_region"].(string)) |
| 210 | + state.Vhost = types.StringValue(data["vhost"].(string)) |
| 211 | + state.QueueName = types.StringValue(data["queue"].(string)) |
| 212 | + state.WithHeaders = types.BoolValue(data["with_headers"].(bool)) |
124 | 213 |
|
125 |
| - return nil |
126 |
| -} |
| 214 | + // Save data into Terraform state |
| 215 | + response.Diagnostics.Append(response.State.Set(ctx, &state)...) |
127 | 216 |
|
128 |
| -func resourceAwsEventBridgeDelete(d *schema.ResourceData, meta interface{}) error { |
129 |
| - var ( |
130 |
| - api = meta.(*api.API) |
131 |
| - instanceID = d.Get("instance_id").(int) |
132 |
| - ) |
| 217 | + return |
| 218 | +} |
133 | 219 |
|
134 |
| - return api.DeleteAwsEventBridge(instanceID, d.Id()) |
| 220 | +func (r *awsEventBridgeResource) Update(ctx context.Context, request resource.UpdateRequest, response *resource.UpdateResponse) { |
| 221 | + // This resource does not implement the Update function |
135 | 222 | }
|
136 | 223 |
|
137 |
| -func awsEventbridgeAttributeKeys() []string { |
138 |
| - return []string{ |
139 |
| - "aws_account_id", |
140 |
| - "aws_region", |
141 |
| - "vhost", |
142 |
| - "queue", |
143 |
| - "with_headers", |
| 224 | +func (r *awsEventBridgeResource) Delete(ctx context.Context, request resource.DeleteRequest, response *resource.DeleteResponse) { |
| 225 | + var data awsEventBridgeResourceModel |
| 226 | + |
| 227 | + // Read Terraform plan data into the model |
| 228 | + response.Diagnostics.Append(request.State.Get(ctx, &data)...) |
| 229 | + var id = data.Id.ValueString() |
| 230 | + err := r.client.DeleteAwsEventBridge(int(data.InstanceID.ValueInt64()), id) |
| 231 | + |
| 232 | + if err != nil { |
| 233 | + response.Diagnostics.AddError("An error occurred while deleting cloudamqp_integration_aws_eventbridge", |
| 234 | + fmt.Sprintf("Error deleting Cloudamqp event bridge %s: %s", id, err), |
| 235 | + ) |
144 | 236 | }
|
145 | 237 | }
|
146 | 238 |
|
147 |
| -func validateAwsEventBridgeSchemaAttribute(key string) bool { |
148 |
| - switch key { |
149 |
| - case "aws_account_id", |
150 |
| - "aws_region", |
151 |
| - "vhost", |
152 |
| - "queue", |
153 |
| - "with_headers", |
154 |
| - "status": |
155 |
| - return true |
156 |
| - } |
157 |
| - return false |
| 239 | +func (r *awsEventBridgeResource) ImportState(ctx context.Context, request resource.ImportStateRequest, response *resource.ImportStateResponse) { |
| 240 | + resource.ImportStatePassthroughID(ctx, path.Root("id"), request, response) |
158 | 241 | }
|
0 commit comments