Skip to content

Commit

Permalink
Merge pull request #79 from umich-vci/fix_network_import
Browse files Browse the repository at this point in the history
Fix network import
  • Loading branch information
adarobin authored Mar 26, 2024
2 parents b4d0bbb + 0f2dbc3 commit ec6bfc4
Show file tree
Hide file tree
Showing 4 changed files with 143 additions and 5 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
## 0.4.4 (March 26, 2024)

BUG FIXES:
* Adjust plan modifiers for attributes only required for creation to allow for import.

## 0.4.3 (March 26, 2024)

BREAKING CHANGES:
Expand Down
27 changes: 26 additions & 1 deletion internal/provider/resource_host_record.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,9 @@ func (r *HostRecordResource) Schema(ctx context.Context, req resource.SchemaRequ
"type": schema.StringAttribute{
MarkdownDescription: "The type of the resource.",
Computed: true,
PlanModifiers: []planmodifier.String{
stringplanmodifier.UseStateForUnknown(),
},
},
"properties": schema.StringAttribute{
MarkdownDescription: "The properties of the host record as returned by the API (pipe delimited).",
Expand All @@ -103,7 +106,7 @@ func (r *HostRecordResource) Schema(ctx context.Context, req resource.SchemaRequ
MarkdownDescription: "The object ID of the View that host record should be created in. If changed, forces a new resource.",
Required: true,
PlanModifiers: []planmodifier.Int64{
int64planmodifier.RequiresReplace(),
int64planmodifier.RequiresReplaceIf(hostRecordViewIDPlanModifier, hostRecordViewIDPlanModifierDescription, hostRecordViewIDPlanModifierDescription),
},
},
// These are exposed via the API properties field for objects of type Host Record
Expand Down Expand Up @@ -307,6 +310,10 @@ func (r *HostRecordResource) Read(ctx context.Context, req resource.ReadRequest,
data.TTL = hostRecordProperties.TTL
data.UserDefinedFields = hostRecordProperties.UserDefinedFields

zone := []string{}
zone = append(zone, strings.Split(data.AbsoluteName.ValueString(), ".")[1:]...)
data.DNSZone = types.StringValue(strings.Join(zone, "."))

resp.Diagnostics.Append(clientLogout(ctx, &client, mutex)...)

// Save updated data into Terraform state
Expand Down Expand Up @@ -476,3 +483,21 @@ func (r *HostRecordResource) Delete(ctx context.Context, req resource.DeleteRequ
func (r *HostRecordResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
}

const hostRecordViewIDPlanModifierDescription string = "View ID is required for creation and cannot be changed. Null values in the state are ignored to allow for import."

func hostRecordViewIDPlanModifier(ctx context.Context, p planmodifier.Int64Request, resp *int64planmodifier.RequiresReplaceIfFuncResponse) {
var state *HostRecordResourceModel
resp.Diagnostics.Append(p.State.Get(ctx, &state)...)
if resp.Diagnostics.HasError() {
return
}

if state.ViewID.IsNull() {
// Since this is a required field with required values, it should only be null when doing an import
resp.RequiresReplace = false
return
}

resp.RequiresReplace = true
}
52 changes: 50 additions & 2 deletions internal/provider/resource_ip4_address.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,9 @@ func (r *IP4AddressResource) Schema(ctx context.Context, req resource.SchemaRequ
"type": schema.StringAttribute{
MarkdownDescription: "The type of the resource.",
Computed: true,
PlanModifiers: []planmodifier.String{
stringplanmodifier.UseStateForUnknown(),
},
},
"properties": schema.StringAttribute{
MarkdownDescription: "The properties of the resource as returned by the API (pipe delimited).",
Expand All @@ -104,7 +107,7 @@ func (r *IP4AddressResource) Schema(ctx context.Context, req resource.SchemaRequ
Computed: true,
Default: stringdefault.StaticString("MAKE_STATIC"),
PlanModifiers: []planmodifier.String{
stringplanmodifier.RequiresReplace(),
stringplanmodifier.RequiresReplaceIf(ip4AddressActionPlanModifier, ip4AddressActionPlanModifierDescription, ip4AddressActionPlanModifierDescription),
},
Validators: []validator.String{
stringvalidator.OneOf(gobam.IPAssignmentActions...),
Expand All @@ -114,7 +117,7 @@ func (r *IP4AddressResource) Schema(ctx context.Context, req resource.SchemaRequ
MarkdownDescription: "The object ID of the Configuration that will hold the new address. If changed, forces a new resource.",
Required: true,
PlanModifiers: []planmodifier.Int64{
int64planmodifier.RequiresReplace(),
int64planmodifier.RequiresReplaceIf(ip4AddressConfigurationIDPlanModifier, ip4AddressConfigurationIDPlanModifierDescription, ip4AddressConfigurationIDPlanModifierDescription),
},
},
"parent_id": schema.Int64Attribute{
Expand Down Expand Up @@ -356,6 +359,15 @@ func (r *IP4AddressResource) Read(ctx context.Context, req resource.ReadRequest,
data.LocationInherited = addressProperties.LocationInherited
data.UserDefinedFields = addressProperties.UserDefinedFields

// get the parent id of the address so we can set it in the state so import works
parent, err := client.GetParent(id)
if err != nil {
resp.Diagnostics.Append(clientLogout(ctx, &client, mutex)...)
resp.Diagnostics.AddError("Failed to get parent entity of IP4 address", err.Error())
return
}
data.ParentID = types.Int64Value(*parent.Id)

resp.Diagnostics.Append(clientLogout(ctx, &client, mutex)...)

// Save updated data into Terraform state
Expand Down Expand Up @@ -506,3 +518,39 @@ func (r *IP4AddressResource) Delete(ctx context.Context, req resource.DeleteRequ
func (r *IP4AddressResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
}

const ip4AddressActionPlanModifierDescription string = "action is required for creation and cannot be changed. Null values in the state are ignored to allow for import."

func ip4AddressActionPlanModifier(ctx context.Context, p planmodifier.StringRequest, resp *stringplanmodifier.RequiresReplaceIfFuncResponse) {
var state *IP4AddressResourceModel
resp.Diagnostics.Append(p.State.Get(ctx, &state)...)
if resp.Diagnostics.HasError() {
return
}

if state.Action.IsNull() {
// Since this is a required field with required values, it should only be null when doing an import
resp.RequiresReplace = false
return
}

resp.RequiresReplace = true
}

const ip4AddressConfigurationIDPlanModifierDescription string = "configuration_id is required for creation and cannot be changed. Null values in the state are ignored to allow for import."

func ip4AddressConfigurationIDPlanModifier(ctx context.Context, p planmodifier.Int64Request, resp *int64planmodifier.RequiresReplaceIfFuncResponse) {
var state *IP4AddressResourceModel
resp.Diagnostics.Append(p.State.Get(ctx, &state)...)
if resp.Diagnostics.HasError() {
return
}

if state.ConfigurationID.IsNull() {
// Since this is a required field with required values, it should only be null when doing an import
resp.RequiresReplace = false
return
}

resp.RequiresReplace = true
}
64 changes: 62 additions & 2 deletions internal/provider/resource_ip4_network.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package provider
import (
"context"
"fmt"
"math/big"
"regexp"
"slices"
"strconv"
Expand Down Expand Up @@ -101,6 +102,9 @@ func (r *IP4NetworkResource) Schema(ctx context.Context, req resource.SchemaRequ
"type": schema.StringAttribute{
MarkdownDescription: "The type of the resource.",
Computed: true,
PlanModifiers: []planmodifier.String{
stringplanmodifier.UseStateForUnknown(),
},
},
"properties": schema.StringAttribute{
MarkdownDescription: "The properties of the resource as returned by the API (pipe delimited).",
Expand All @@ -113,7 +117,7 @@ func (r *IP4NetworkResource) Schema(ctx context.Context, req resource.SchemaRequ
Computed: true,
Default: booldefault.StaticBool(false),
PlanModifiers: []planmodifier.Bool{
boolplanmodifier.RequiresReplace(),
boolplanmodifier.RequiresReplaceIf(ip4NetworkIsLargerAllowedPlanModifier, ip4NetworkIsLargerAllowedPlanModifierDescription, ip4NetworkIsLargerAllowedPlanModifierDescription),
},
},
"parent_id": schema.Int64Attribute{
Expand All @@ -139,7 +143,7 @@ func (r *IP4NetworkResource) Schema(ctx context.Context, req resource.SchemaRequ
stringvalidator.OneOf("NO_TRAVERSAL", "DEPTH_FIRST", "BREADTH_FIRST"),
},
PlanModifiers: []planmodifier.String{
stringplanmodifier.RequiresReplace(),
stringplanmodifier.RequiresReplaceIf(ip4NetworkTraversalMethodPlanModifier, ip4NetworkTraversalMethodPlanModifierDescription, ip4NetworkTraversalMethodPlanModifierDescription),
},
},

Expand Down Expand Up @@ -512,6 +516,26 @@ func (r *IP4NetworkResource) Read(ctx context.Context, req resource.ReadRequest,
data.SharedNetwork = networkProperties.SharedNetwork
data.UserDefinedFields = networkProperties.UserDefinedFields

// calculate the size of the network so we can set it in the state so import works
cidrNetmask, err := strconv.ParseInt(strings.Split(networkProperties.CIDR.ValueString(), "/")[1], 10, 64)
if err != nil {
resp.Diagnostics.Append(clientLogout(ctx, &client, mutex)...)
resp.Diagnostics.AddError("Failed to parse CIDR netmask to integer", err.Error())
return
}
var size, e = big.NewInt(2), big.NewInt(32 - cidrNetmask)
size.Exp(size, e, nil)
data.Size = types.Int64Value(size.Int64())

// get the parent id of the network so we can set it in the state so import works
parent, err := client.GetParent(id)
if err != nil {
resp.Diagnostics.Append(clientLogout(ctx, &client, mutex)...)
resp.Diagnostics.AddError("Failed to get parent entity of IP4 Network", err.Error())
return
}
data.ParentID = types.Int64Value(*parent.Id)

resp.Diagnostics.Append(clientLogout(ctx, &client, mutex)...)

// Save updated data into Terraform state
Expand Down Expand Up @@ -845,3 +869,39 @@ func (r IP4NetworkResource) ValidateConfig(ctx context.Context, req resource.Val
)
}
}

const ip4NetworkIsLargerAllowedPlanModifierDescription string = "is_larger_allowed is required for creation and cannot be changed. Null values in the state are ignored to allow for import."

func ip4NetworkIsLargerAllowedPlanModifier(ctx context.Context, p planmodifier.BoolRequest, resp *boolplanmodifier.RequiresReplaceIfFuncResponse) {
var state *IP4NetworkResourceModel
resp.Diagnostics.Append(p.State.Get(ctx, &state)...)
if resp.Diagnostics.HasError() {
return
}

if state.IsLargerAllowed.IsNull() {
// Since this is an optional field with a default value, it should only be null when doing an import
resp.RequiresReplace = false
return
}

resp.RequiresReplace = true
}

const ip4NetworkTraversalMethodPlanModifierDescription string = "traversal_method is required for creation and cannot be changed. Null values in the state are ignored to allow for import."

func ip4NetworkTraversalMethodPlanModifier(ctx context.Context, p planmodifier.StringRequest, resp *stringplanmodifier.RequiresReplaceIfFuncResponse) {
var state *IP4NetworkResourceModel
resp.Diagnostics.Append(p.State.Get(ctx, &state)...)
if resp.Diagnostics.HasError() {
return
}

if state.TraversalMethod.IsNull() {
// Since this is a required field with required values, it should only be null when doing an import
resp.RequiresReplace = false
return
}

resp.RequiresReplace = true
}

0 comments on commit ec6bfc4

Please sign in to comment.