@@ -44,24 +44,30 @@ type vpcFirewallRulesResource struct {
4444
4545type vpcFirewallRulesResourceModel struct {
4646 // This ID is specific to Terraform only
47- ID types.String `tfsdk:"id"`
48- Rules []vpcFirewallRulesResourceRuleModel `tfsdk:"rules"`
49- Timeouts timeouts.Value `tfsdk:"timeouts"`
50- VPCID types.String `tfsdk:"vpc_id"`
47+ ID types.String `tfsdk:"id"`
48+ Rules []vpcFirewallRulesResourceRuleModel `tfsdk:"rules"`
49+ Timeouts timeouts.Value `tfsdk:"timeouts"`
50+ VPCID types.String `tfsdk:"vpc_id"`
51+
52+ // Populated from the same fields within [vpcFirewallRulesResourceRuleModel].
53+ TimeCreated types.String `tfsdk:"time_created"`
54+ TimeModified types.String `tfsdk:"time_modified"`
5155}
5256
5357type vpcFirewallRulesResourceRuleModel struct {
54- Action types.String `tfsdk:"action"`
55- Description types.String `tfsdk:"description"`
56- Direction types.String `tfsdk:"direction"`
57- Filters * vpcFirewallRulesResourceRuleFiltersModel `tfsdk:"filters"`
58- ID types.String `tfsdk:"id"`
59- Name types.String `tfsdk:"name"`
60- Priority types.Int64 `tfsdk:"priority"`
61- Status types.String `tfsdk:"status"`
62- Targets []vpcFirewallRulesResourceRuleTargetModel `tfsdk:"targets"`
63- TimeCreated types.String `tfsdk:"time_created"`
64- TimeModified types.String `tfsdk:"time_modified"`
58+ Action types.String `tfsdk:"action"`
59+ Description types.String `tfsdk:"description"`
60+ Direction types.String `tfsdk:"direction"`
61+ Filters * vpcFirewallRulesResourceRuleFiltersModel `tfsdk:"filters"`
62+ Name types.String `tfsdk:"name"`
63+ Priority types.Int64 `tfsdk:"priority"`
64+ Status types.String `tfsdk:"status"`
65+ Targets []vpcFirewallRulesResourceRuleTargetModel `tfsdk:"targets"`
66+
67+ // Used to retrieve the timestamps from the API and populate the same fields
68+ // within [vpcFirewallRulesResourceModel].
69+ TimeCreated types.String `tfsdk:"-"`
70+ TimeModified types.String `tfsdk:"-"`
6571}
6672
6773type vpcFirewallRulesResourceRuleTargetModel struct {
@@ -110,6 +116,10 @@ func (r *vpcFirewallRulesResource) Schema(ctx context.Context, _ resource.Schema
110116 stringplanmodifier .RequiresReplace (),
111117 },
112118 },
119+ // The rules attribute cannot contain computed attributes since the upstream API
120+ // returns updated attributes for every rule, irrespective of which rules actually
121+ // change. See https://github.com/oxidecomputer/terraform-provider-oxide/issues/453
122+ // for more information.
113123 "rules" : schema.SetNestedAttribute {
114124 Required : true ,
115125 Description : "Associated firewall rules." ,
@@ -202,10 +212,6 @@ func (r *vpcFirewallRulesResource) Schema(ctx context.Context, _ resource.Schema
202212 },
203213 },
204214 },
205- "id" : schema.StringAttribute {
206- Computed : true ,
207- Description : "Unique, immutable, system-controlled identifier of the firewall rule." ,
208- },
209215 "name" : schema.StringAttribute {
210216 Required : true ,
211217 Description : "Name of the VPC firewall rule." ,
@@ -255,14 +261,6 @@ func (r *vpcFirewallRulesResource) Schema(ctx context.Context, _ resource.Schema
255261 },
256262 },
257263 },
258- "time_created" : schema.StringAttribute {
259- Computed : true ,
260- Description : "Timestamp of when this VPC firewall rule was created." ,
261- },
262- "time_modified" : schema.StringAttribute {
263- Computed : true ,
264- Description : "Timestamp of when this VPC firewall rule was last modified." ,
265- },
266264 },
267265 },
268266 },
@@ -276,6 +274,14 @@ func (r *vpcFirewallRulesResource) Schema(ctx context.Context, _ resource.Schema
276274 Computed : true ,
277275 Description : "Unique, immutable, system-controlled identifier of the firewall rules. Specific only to Terraform." ,
278276 },
277+ "time_created" : schema.StringAttribute {
278+ Computed : true ,
279+ Description : "Timestamp of when the VPC firewall rules were last created." ,
280+ },
281+ "time_modified" : schema.StringAttribute {
282+ Computed : true ,
283+ Description : "Timestamp of when the VPC firewall rules were last modified." ,
284+ },
279285 },
280286 }
281287}
@@ -327,6 +333,13 @@ func (r *vpcFirewallRulesResource) Create(ctx context.Context, req resource.Crea
327333 return
328334 }
329335
336+ plan .TimeCreated = types .StringNull ()
337+ plan .TimeModified = types .StringNull ()
338+ if len (plan .Rules ) > 0 {
339+ plan .TimeCreated = plan .Rules [0 ].TimeCreated
340+ plan .TimeModified = plan .Rules [0 ].TimeModified
341+ }
342+
330343 // Save plan into Terraform state
331344 resp .Diagnostics .Append (resp .State .Set (ctx , & plan )... )
332345 if resp .Diagnostics .HasError () {
@@ -384,6 +397,13 @@ func (r *vpcFirewallRulesResource) Read(ctx context.Context, req resource.ReadRe
384397
385398 state .Rules = rules
386399
400+ state .TimeCreated = types .StringNull ()
401+ state .TimeModified = types .StringNull ()
402+ if len (state .Rules ) > 0 {
403+ state .TimeCreated = state .Rules [0 ].TimeCreated
404+ state .TimeModified = state .Rules [0 ].TimeModified
405+ }
406+
387407 // Save updated data into Terraform state
388408 resp .Diagnostics .Append (resp .State .Set (ctx , & state )... )
389409 if resp .Diagnostics .HasError () {
@@ -447,6 +467,13 @@ func (r *vpcFirewallRulesResource) Update(ctx context.Context, req resource.Upda
447467 return
448468 }
449469
470+ plan .TimeCreated = types .StringNull ()
471+ plan .TimeModified = types .StringNull ()
472+ if len (plan .Rules ) > 0 {
473+ plan .TimeCreated = plan .Rules [0 ].TimeCreated
474+ plan .TimeModified = plan .Rules [0 ].TimeModified
475+ }
476+
450477 // Save plan into Terraform state
451478 resp .Diagnostics .Append (resp .State .Set (ctx , & plan )... )
452479 if resp .Diagnostics .HasError () {
@@ -536,7 +563,6 @@ func newVPCFirewallRulesModel(rules []oxide.VpcFirewallRule) ([]vpcFirewallRules
536563 Action : types .StringValue (string (rule .Action )),
537564 Description : types .StringValue (rule .Description ),
538565 Direction : types .StringValue (string (rule .Direction )),
539- ID : types .StringValue (rule .Id ),
540566 Name : types .StringValue (string (rule .Name )),
541567 // We can safely dereference rule.Priority as it's a required field
542568 Priority : types .Int64Value (int64 (* rule .Priority )),
0 commit comments