@@ -48,20 +48,27 @@ type vpcFirewallRulesResourceModel struct {
4848 Rules []vpcFirewallRulesResourceRuleModel `tfsdk:"rules"`
4949 Timeouts timeouts.Value `tfsdk:"timeouts"`
5050 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]. The `tfsdk:"-"` struct field tag is used
69+ // to tell Terraform not to populate these values in the schema.
70+ TimeCreated types.String `tfsdk:"-"`
71+ TimeModified types.String `tfsdk:"-"`
6572}
6673
6774type vpcFirewallRulesResourceRuleTargetModel struct {
@@ -110,6 +117,10 @@ func (r *vpcFirewallRulesResource) Schema(ctx context.Context, _ resource.Schema
110117 stringplanmodifier .RequiresReplace (),
111118 },
112119 },
120+ // The rules attribute cannot contain computed attributes since the upstream API
121+ // returns updated attributes for every rule, irrespective of which rules actually
122+ // change. See https://github.com/oxidecomputer/terraform-provider-oxide/issues/453
123+ // for more information.
113124 "rules" : schema.SetNestedAttribute {
114125 Required : true ,
115126 Description : "Associated firewall rules." ,
@@ -202,10 +213,6 @@ func (r *vpcFirewallRulesResource) Schema(ctx context.Context, _ resource.Schema
202213 },
203214 },
204215 },
205- "id" : schema.StringAttribute {
206- Computed : true ,
207- Description : "Unique, immutable, system-controlled identifier of the firewall rule." ,
208- },
209216 "name" : schema.StringAttribute {
210217 Required : true ,
211218 Description : "Name of the VPC firewall rule." ,
@@ -255,14 +262,6 @@ func (r *vpcFirewallRulesResource) Schema(ctx context.Context, _ resource.Schema
255262 },
256263 },
257264 },
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- },
266265 },
267266 },
268267 },
@@ -276,6 +275,14 @@ func (r *vpcFirewallRulesResource) Schema(ctx context.Context, _ resource.Schema
276275 Computed : true ,
277276 Description : "Unique, immutable, system-controlled identifier of the firewall rules. Specific only to Terraform." ,
278277 },
278+ "time_created" : schema.StringAttribute {
279+ Computed : true ,
280+ Description : "Timestamp of when the VPC firewall rules were last created." ,
281+ },
282+ "time_modified" : schema.StringAttribute {
283+ Computed : true ,
284+ Description : "Timestamp of when the VPC firewall rules were last modified." ,
285+ },
279286 },
280287 }
281288}
@@ -327,6 +334,13 @@ func (r *vpcFirewallRulesResource) Create(ctx context.Context, req resource.Crea
327334 return
328335 }
329336
337+ plan .TimeCreated = types .StringNull ()
338+ plan .TimeModified = types .StringNull ()
339+ if len (plan .Rules ) > 0 {
340+ plan .TimeCreated = plan .Rules [0 ].TimeCreated
341+ plan .TimeModified = plan .Rules [0 ].TimeModified
342+ }
343+
330344 // Save plan into Terraform state
331345 resp .Diagnostics .Append (resp .State .Set (ctx , & plan )... )
332346 if resp .Diagnostics .HasError () {
@@ -384,6 +398,13 @@ func (r *vpcFirewallRulesResource) Read(ctx context.Context, req resource.ReadRe
384398
385399 state .Rules = rules
386400
401+ state .TimeCreated = types .StringNull ()
402+ state .TimeModified = types .StringNull ()
403+ if len (state .Rules ) > 0 {
404+ state .TimeCreated = state .Rules [0 ].TimeCreated
405+ state .TimeModified = state .Rules [0 ].TimeModified
406+ }
407+
387408 // Save updated data into Terraform state
388409 resp .Diagnostics .Append (resp .State .Set (ctx , & state )... )
389410 if resp .Diagnostics .HasError () {
@@ -447,6 +468,13 @@ func (r *vpcFirewallRulesResource) Update(ctx context.Context, req resource.Upda
447468 return
448469 }
449470
471+ plan .TimeCreated = types .StringNull ()
472+ plan .TimeModified = types .StringNull ()
473+ if len (plan .Rules ) > 0 {
474+ plan .TimeCreated = plan .Rules [0 ].TimeCreated
475+ plan .TimeModified = plan .Rules [0 ].TimeModified
476+ }
477+
450478 // Save plan into Terraform state
451479 resp .Diagnostics .Append (resp .State .Set (ctx , & plan )... )
452480 if resp .Diagnostics .HasError () {
@@ -536,7 +564,6 @@ func newVPCFirewallRulesModel(rules []oxide.VpcFirewallRule) ([]vpcFirewallRules
536564 Action : types .StringValue (string (rule .Action )),
537565 Description : types .StringValue (rule .Description ),
538566 Direction : types .StringValue (string (rule .Direction )),
539- ID : types .StringValue (rule .Id ),
540567 Name : types .StringValue (string (rule .Name )),
541568 // We can safely dereference rule.Priority as it's a required field
542569 Priority : types .Int64Value (int64 (* rule .Priority )),
0 commit comments