Extend network resource fields (#576)

* deprecate nameservers filed

* onboard routed field

* onboard new ipv4 fields

* onboard new ipv6 fields

* update examples

* update examples

* update examples

* remove nameserver(deprecated) mapping

* make fields computed

* Revert "remove nameserver(deprecated) mapping"

This reverts commit e4bf1dc184289f3bddc10c5d3b2320966b529649.

* remove routed from update payload (not yet supported)

* Update docs/resources/network.md

Co-authored-by: João Palet <joao.palet@outlook.com>

* Update stackit/internal/services/iaas/network/resource.go

Co-authored-by: João Palet <joao.palet@outlook.com>

* fix the field descriptions

* remove ipv6 from examples

* use nameservers as rollback value to support deprecated field

* extend acceptance tests

* add condition that nameserver and ipv4_nameserver cannot be provided at the same time

* extend acc test

* improve conditions in create payload

* adapt modify plan to support update and delete operations

* fix acceptance test

* deprecate prefixes and create ipv4_prefixes field

* fix unit tests

* fix update issues

* fix linter issues

* extend modifyPlan condition

* add validateConfig function

* Update stackit/internal/services/iaas/network/resource.go

Co-authored-by: João Palet <joao.palet@outlook.com>

* Update stackit/internal/services/iaas/network/resource.go

Co-authored-by: João Palet <joao.palet@outlook.com>

* update descriptions

* Update stackit/internal/services/iaas/network/resource.go

Co-authored-by: João Palet <joao.palet@outlook.com>

* Update stackit/internal/services/iaas/network/resource.go

Co-authored-by: João Palet <joao.palet@outlook.com>

* implement no_gateway field and condition check

* implement no_ipv6_gateway field and condition check

* update examples

* update examples and descriptions

* fix linter issues

* Update stackit/internal/services/iaas/network/resource.go

Co-authored-by: João Palet <joao.palet@outlook.com>

* adapt descriptions

* apply acceptance comments

* adapt conditions in create and update

* add plan modifiers

* add requiresReplace

---------

Co-authored-by: João Palet <joao.palet@outlook.com>
This commit is contained in:
GokceGK 2024-11-19 15:25:56 +01:00 committed by GitHub
parent 3ac1d50253
commit b1fb9ab9b6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 857 additions and 60 deletions

View file

@ -30,9 +30,19 @@ data "stackit_network" "example" {
### Read-Only
- `id` (String) Terraform's internal resource ID. It is structured as "`project_id`,`network_id`".
- `ipv4_gateway` (String) The IPv4 gateway of a network. If not specified, the first IP of the network will be assigned as the gateway.
- `ipv4_nameservers` (List of String) The IPv4 nameservers of the network.
- `ipv4_prefix` (String) The IPv4 prefix of the network (CIDR).
- `ipv4_prefix_length` (Number) The IPv4 prefix length of the network.
- `ipv4_prefixes` (List of String) The IPv4 prefixes of the network.
- `ipv6_gateway` (String) The IPv6 gateway of a network. If not specified, the first IP of the network will be assigned as the gateway.
- `ipv6_nameservers` (List of String) The IPv6 nameservers of the network.
- `ipv6_prefix` (String) The IPv6 prefix of the network (CIDR).
- `ipv6_prefix_length` (Number) The IPv6 prefix length of the network.
- `ipv6_prefixes` (List of String) The IPv6 prefixes of the network.
- `labels` (Map of String) Labels are key-value string pairs which can be attached to a resource container
- `name` (String) The name of the network.
- `nameservers` (List of String) The nameservers of the network.
- `prefixes` (List of String) The prefixes of the network.
- `nameservers` (List of String, Deprecated) The nameservers of the network. This field is deprecated and will be removed soon, use `ipv4_nameservers` to configure the nameservers for IPv4.
- `prefixes` (List of String, Deprecated) The prefixes of the network. This field is deprecated and will be removed soon, use `ipv4_prefixes` to read the prefixes of the IPv4 networks.
- `public_ip` (String) The public IP of the network.
- `routed` (Boolean) Shows if the network is routed and therefore accessible from other networks.

View file

@ -13,14 +13,31 @@ Network resource schema. Must have a `region` specified in the provider configur
## Example Usage
```terraform
resource "stackit_network" "example" {
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
name = "example-network"
nameservers = ["1.2.3.4", "5.6.7.8"]
ipv4_prefix_length = 24
resource "stackit_network" "example_with_name" {
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
name = "example-with-name"
}
resource "stackit_network" "example_routed_network" {
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
name = "example-routed-network"
labels = {
"key" = "value"
}
routed = true
}
resource "stackit_network" "example_non_routed_network" {
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
name = "example-non-routed-network"
ipv4_nameservers = ["1.2.3.4", "5.6.7.8"]
ipv4_prefix_length = 24
ipv4_gateway = "10.1.2.3"
ipv4_prefix = "10.1.2.0/24"
labels = {
"key" = "value"
}
routed = false
}
```
@ -34,13 +51,25 @@ resource "stackit_network" "example" {
### Optional
- `ipv4_gateway` (String) The IPv4 gateway of a network. If not specified, the first IP of the network will be assigned as the gateway.
- `ipv4_nameservers` (List of String) The IPv4 nameservers of the network.
- `ipv4_prefix` (String) The IPv4 prefix of the network (CIDR).
- `ipv4_prefix_length` (Number) The IPv4 prefix length of the network.
- `ipv6_gateway` (String) The IPv6 gateway of a network. If not specified, the first IP of the network will be assigned as the gateway.
- `ipv6_nameservers` (List of String) The IPv6 nameservers of the network.
- `ipv6_prefix` (String) The IPv6 prefix of the network (CIDR).
- `ipv6_prefix_length` (Number) The IPv6 prefix length of the network.
- `labels` (Map of String) Labels are key-value string pairs which can be attached to a resource container
- `nameservers` (List of String) The nameservers of the network.
- `nameservers` (List of String, Deprecated) The nameservers of the network. This field is deprecated and will be removed soon, use `ipv4_nameservers` to configure the nameservers for IPv4.
- `no_ipv4_gateway` (Boolean) If set to `true`, the network doesn't have a gateway.
- `no_ipv6_gateway` (Boolean) If set to `true`, the network doesn't have a gateway.
- `routed` (Boolean) If set to `true`, the network is routed and therefore accessible from other networks.
### Read-Only
- `id` (String) Terraform's internal resource ID. It is structured as "`project_id`,`network_id`".
- `ipv4_prefixes` (List of String) The IPv4 prefixes of the network.
- `ipv6_prefixes` (List of String) The IPv6 prefixes of the network.
- `network_id` (String) The network ID.
- `prefixes` (List of String) The prefixes of the network.
- `prefixes` (List of String, Deprecated) The prefixes of the network. This field is deprecated and will be removed soon, use `ipv4_prefixes` to read the prefixes of the IPv4 networks.
- `public_ip` (String) The public IP of the network.

View file

@ -1,9 +1,26 @@
resource "stackit_network" "example" {
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
name = "example-network"
nameservers = ["1.2.3.4", "5.6.7.8"]
ipv4_prefix_length = 24
resource "stackit_network" "example_with_name" {
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
name = "example-with-name"
}
resource "stackit_network" "example_routed_network" {
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
name = "example-routed-network"
labels = {
"key" = "value"
}
routed = true
}
resource "stackit_network" "example_non_routed_network" {
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
name = "example-non-routed-network"
ipv4_nameservers = ["1.2.3.4", "5.6.7.8"]
ipv4_prefix_length = 24
ipv4_gateway = "10.1.2.3"
ipv4_prefix = "10.1.2.0/24"
labels = {
"key" = "value"
}
routed = false
}

View file

@ -29,6 +29,9 @@ var networkResource = map[string]string{
"ipv4_prefix_length": "24",
"nameserver0": "1.2.3.4",
"nameserver1": "5.6.7.8",
"ipv4_gateway": "10.1.2.1",
"ipv4_prefix": "10.1.2.1/24",
"routed": "false",
}
var networkAreaResource = map[string]string{
@ -113,13 +116,19 @@ func networkResourceConfig(name, nameservers string) string {
project_id = "%s"
name = "%s"
ipv4_prefix_length = "%s"
nameservers = %s
ipv4_nameservers = %s
ipv4_gateway = "%s"
ipv4_prefix = "%s"
routed = "%s"
}
`,
networkResource["project_id"],
name,
networkResource["ipv4_prefix_length"],
nameservers,
networkResource["ipv4_gateway"],
networkResource["ipv4_prefix"],
networkResource["routed"],
)
}
@ -616,6 +625,9 @@ func TestAccServer(t *testing.T) {
resource.TestCheckResourceAttr("stackit_network.network", "name", networkResource["name"]),
resource.TestCheckResourceAttr("stackit_network.network", "nameservers.#", "1"),
resource.TestCheckResourceAttr("stackit_network.network", "nameservers.0", networkResource["nameserver0"]),
resource.TestCheckResourceAttr("stackit_network.network", "ipv4_gateway", networkResource["ipv4_gateway"]),
resource.TestCheckResourceAttr("stackit_network.network", "ipv4_prefix", networkResource["ipv4_prefix"]),
resource.TestCheckResourceAttr("stackit_network.network", "routed", networkResource["routed"]),
// Server
resource.TestCheckResourceAttr("stackit_server.server", "project_id", serverResource["project_id"]),
@ -718,6 +730,9 @@ func TestAccServer(t *testing.T) {
),
resource.TestCheckResourceAttr("data.stackit_network.network", "name", networkResource["name"]),
resource.TestCheckResourceAttr("data.stackit_network.network", "nameservers.0", networkResource["nameserver0"]),
resource.TestCheckResourceAttr("data.stackit_network.network", "ipv4_gateway", networkResource["ipv4_gateway"]),
resource.TestCheckResourceAttr("data.stackit_network.network", "ipv4_prefix", networkResource["ipv4_prefix"]),
resource.TestCheckResourceAttr("data.stackit_network.network", "routed", networkResource["routed"]),
// Server
resource.TestCheckResourceAttr("data.stackit_server.server", "project_id", serverResource["project_id"]),
@ -879,6 +894,8 @@ func TestAccServer(t *testing.T) {
resource.TestCheckResourceAttr("stackit_network.network", "nameservers.#", "2"),
resource.TestCheckResourceAttr("stackit_network.network", "nameservers.0", networkResource["nameserver0"]),
resource.TestCheckResourceAttr("stackit_network.network", "nameservers.1", networkResource["nameserver1"]),
resource.TestCheckResourceAttr("stackit_network.network", "ipv4_gateway", networkResource["ipv4_gateway"]),
resource.TestCheckResourceAttr("stackit_network.network", "ipv4_prefix", networkResource["ipv4_prefix"]),
// Server
resource.TestCheckResourceAttr("stackit_server.server", "project_id", serverResource["project_id"]),

View file

@ -107,16 +107,58 @@ func (d *networkDataSource) Schema(_ context.Context, _ datasource.SchemaRequest
},
},
"nameservers": schema.ListAttribute{
Description: "The nameservers of the network.",
Description: "The nameservers of the network. This field is deprecated and will be removed soon, use `ipv4_nameservers` to configure the nameservers for IPv4.",
DeprecationMessage: "Use `ipv4_nameservers` to configure the nameservers for IPv4.",
Computed: true,
ElementType: types.StringType,
},
"ipv4_gateway": schema.StringAttribute{
Description: "The IPv4 gateway of a network. If not specified, the first IP of the network will be assigned as the gateway.",
Computed: true,
},
"ipv4_nameservers": schema.ListAttribute{
Description: "The IPv4 nameservers of the network.",
Computed: true,
ElementType: types.StringType,
},
"ipv4_prefix": schema.StringAttribute{
Description: "The IPv4 prefix of the network (CIDR).",
Computed: true,
},
"ipv4_prefix_length": schema.Int64Attribute{
Description: "The IPv4 prefix length of the network.",
Computed: true,
},
"prefixes": schema.ListAttribute{
Description: "The prefixes of the network.",
Description: "The prefixes of the network. This field is deprecated and will be removed soon, use `ipv4_prefixes` to read the prefixes of the IPv4 networks.",
DeprecationMessage: "Use `ipv4_prefixes` to read the prefixes of the IPv4 networks.",
Computed: true,
ElementType: types.StringType,
},
"ipv4_prefixes": schema.ListAttribute{
Description: "The IPv4 prefixes of the network.",
Computed: true,
ElementType: types.StringType,
},
"ipv6_gateway": schema.StringAttribute{
Description: "The IPv6 gateway of a network. If not specified, the first IP of the network will be assigned as the gateway.",
Computed: true,
},
"ipv6_nameservers": schema.ListAttribute{
Description: "The IPv6 nameservers of the network.",
Computed: true,
ElementType: types.StringType,
},
"ipv6_prefix": schema.StringAttribute{
Description: "The IPv6 prefix of the network (CIDR).",
Computed: true,
},
"ipv6_prefix_length": schema.Int64Attribute{
Description: "The IPv6 prefix length of the network.",
Computed: true,
},
"ipv6_prefixes": schema.ListAttribute{
Description: "The IPv6 prefixes of the network.",
Computed: true,
ElementType: types.StringType,
},
@ -129,6 +171,10 @@ func (d *networkDataSource) Schema(_ context.Context, _ datasource.SchemaRequest
ElementType: types.StringType,
Computed: true,
},
"routed": schema.BoolAttribute{
Description: "Shows if the network is routed and therefore accessible from other networks.",
Computed: true,
},
},
}
}

View file

@ -6,11 +6,14 @@ import (
"net/http"
"strings"
"github.com/hashicorp/terraform-plugin-framework-validators/resourcevalidator"
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
"github.com/hashicorp/terraform-plugin-framework/attr"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/boolplanmodifier"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/listplanmodifier"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
@ -40,10 +43,22 @@ type Model struct {
NetworkId types.String `tfsdk:"network_id"`
Name types.String `tfsdk:"name"`
Nameservers types.List `tfsdk:"nameservers"`
IPv4Gateway types.String `tfsdk:"ipv4_gateway"`
IPv4Nameservers types.List `tfsdk:"ipv4_nameservers"`
IPv4Prefix types.String `tfsdk:"ipv4_prefix"`
IPv4PrefixLength types.Int64 `tfsdk:"ipv4_prefix_length"`
Prefixes types.List `tfsdk:"prefixes"`
IPv4Prefixes types.List `tfsdk:"ipv4_prefixes"`
IPv6Gateway types.String `tfsdk:"ipv6_gateway"`
IPv6Nameservers types.List `tfsdk:"ipv6_nameservers"`
IPv6Prefix types.String `tfsdk:"ipv6_prefix"`
IPv6PrefixLength types.Int64 `tfsdk:"ipv6_prefix_length"`
IPv6Prefixes types.List `tfsdk:"ipv6_prefixes"`
PublicIP types.String `tfsdk:"public_ip"`
Labels types.Map `tfsdk:"labels"`
Routed types.Bool `tfsdk:"routed"`
NoIPv4Gateway types.Bool `tfsdk:"no_ipv4_gateway"`
NoIPv6Gateway types.Bool `tfsdk:"no_ipv6_gateway"`
}
// NewNetworkResource is a helper function to simplify the provider implementation.
@ -98,6 +113,32 @@ func (r *networkResource) Configure(ctx context.Context, req resource.ConfigureR
tflog.Info(ctx, "IaaS client configured")
}
func (r networkResource) ValidateConfig(ctx context.Context, req resource.ValidateConfigRequest, resp *resource.ValidateConfigResponse) {
var model Model
resp.Diagnostics.Append(req.Config.Get(ctx, &model)...)
if resp.Diagnostics.HasError() {
return
}
if !model.Nameservers.IsUnknown() && !model.IPv4Nameservers.IsUnknown() && !model.Nameservers.IsNull() && !model.IPv4Nameservers.IsNull() {
core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring network", "You cannot provide both the `nameservers` and `ipv4_nameservers` fields simultaneously. Please remove the deprecated `nameservers` field, and use `ipv4_nameservers` to configure nameservers for IPv4.")
}
}
// ConfigValidators validates the resource configuration
func (r *networkResource) ConfigValidators(_ context.Context) []resource.ConfigValidator {
return []resource.ConfigValidator{
resourcevalidator.Conflicting(
path.MatchRoot("no_ipv4_gateway"),
path.MatchRoot("ipv4_gateway"),
),
resourcevalidator.Conflicting(
path.MatchRoot("no_ipv6_gateway"),
path.MatchRoot("ipv6_gateway"),
),
}
}
// Schema defines the schema for the resource.
func (r *networkResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = schema.Schema{
@ -141,32 +182,128 @@ func (r *networkResource) Schema(_ context.Context, _ resource.SchemaRequest, re
},
},
"nameservers": schema.ListAttribute{
Description: "The nameservers of the network.",
Description: "The nameservers of the network. This field is deprecated and will be removed soon, use `ipv4_nameservers` to configure the nameservers for IPv4.",
DeprecationMessage: "Use `ipv4_nameservers` to configure the nameservers for IPv4.",
Optional: true,
Computed: true,
ElementType: types.StringType,
},
"no_ipv4_gateway": schema.BoolAttribute{
Description: "If set to `true`, the network doesn't have a gateway.",
Optional: true,
PlanModifiers: []planmodifier.Bool{
boolplanmodifier.UseStateForUnknown(),
},
},
"ipv4_gateway": schema.StringAttribute{
Description: "The IPv4 gateway of a network. If not specified, the first IP of the network will be assigned as the gateway.",
Optional: true,
Computed: true,
PlanModifiers: []planmodifier.List{
listplanmodifier.UseStateForUnknown(),
Validators: []validator.String{
validate.IP(),
},
},
"ipv4_nameservers": schema.ListAttribute{
Description: "The IPv4 nameservers of the network.",
Optional: true,
Computed: true,
ElementType: types.StringType,
},
"ipv4_prefix": schema.StringAttribute{
Description: "The IPv4 prefix of the network (CIDR).",
Optional: true,
Validators: []validator.String{
validate.CIDR(),
},
PlanModifiers: []planmodifier.String{
stringplanmodifier.RequiresReplace(),
},
},
"ipv4_prefix_length": schema.Int64Attribute{
Description: "The IPv4 prefix length of the network.",
Optional: true,
},
"prefixes": schema.ListAttribute{
Description: "The prefixes of the network.",
Description: "The prefixes of the network. This field is deprecated and will be removed soon, use `ipv4_prefixes` to read the prefixes of the IPv4 networks.",
DeprecationMessage: "Use `ipv4_prefixes` to read the prefixes of the IPv4 networks.",
Computed: true,
ElementType: types.StringType,
PlanModifiers: []planmodifier.List{
listplanmodifier.UseStateForUnknown(),
},
},
"ipv4_prefixes": schema.ListAttribute{
Description: "The IPv4 prefixes of the network.",
Computed: true,
ElementType: types.StringType,
PlanModifiers: []planmodifier.List{
listplanmodifier.UseStateForUnknown(),
},
},
"no_ipv6_gateway": schema.BoolAttribute{
Description: "If set to `true`, the network doesn't have a gateway.",
Optional: true,
PlanModifiers: []planmodifier.Bool{
boolplanmodifier.UseStateForUnknown(),
},
},
"ipv6_gateway": schema.StringAttribute{
Description: "The IPv6 gateway of a network. If not specified, the first IP of the network will be assigned as the gateway.",
Optional: true,
Computed: true,
Validators: []validator.String{
validate.IP(),
},
},
"ipv6_nameservers": schema.ListAttribute{
Description: "The IPv6 nameservers of the network.",
Optional: true,
Computed: true,
ElementType: types.StringType,
},
"ipv6_prefix": schema.StringAttribute{
Description: "The IPv6 prefix of the network (CIDR).",
Optional: true,
Validators: []validator.String{
validate.CIDR(),
},
PlanModifiers: []planmodifier.String{
stringplanmodifier.RequiresReplace(),
},
},
"ipv6_prefix_length": schema.Int64Attribute{
Description: "The IPv6 prefix length of the network.",
Optional: true,
},
"ipv6_prefixes": schema.ListAttribute{
Description: "The IPv6 prefixes of the network.",
Computed: true,
ElementType: types.StringType,
PlanModifiers: []planmodifier.List{
listplanmodifier.UseStateForUnknown(),
},
},
"public_ip": schema.StringAttribute{
Description: "The public IP of the network.",
Computed: true,
PlanModifiers: []planmodifier.String{
stringplanmodifier.UseStateForUnknown(),
},
},
"labels": schema.MapAttribute{
Description: "Labels are key-value string pairs which can be attached to a resource container",
ElementType: types.StringType,
Optional: true,
},
"routed": schema.BoolAttribute{
Description: "If set to `true`, the network is routed and therefore accessible from other networks.",
Optional: true,
Computed: true,
PlanModifiers: []planmodifier.Bool{
boolplanmodifier.UseStateForUnknown(),
boolplanmodifier.RequiresReplace(),
},
},
},
}
}
@ -285,7 +422,7 @@ func (r *networkResource) Update(ctx context.Context, req resource.UpdateRequest
}
// Generate API request body from model
payload, err := toUpdatePayload(ctx, &model, stateModel.Labels)
payload, err := toUpdatePayload(ctx, &model, &stateModel)
if err != nil {
core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating network", fmt.Sprintf("Creating API payload: %v", err))
return
@ -407,27 +544,41 @@ func mapFields(ctx context.Context, networkResp *iaas.Network, model *Model) err
labels = types.MapNull(types.StringType)
}
// IPv4
if networkResp.Nameservers == nil {
model.Nameservers = types.ListNull(types.StringType)
model.IPv4Nameservers = types.ListNull(types.StringType)
} else {
respNameservers := *networkResp.Nameservers
modelNameservers, err := utils.ListValuetoStringSlice(model.Nameservers)
modelIPv4Nameservers, errIpv4 := utils.ListValuetoStringSlice(model.IPv4Nameservers)
if err != nil {
return fmt.Errorf("get current network nameservers from model: %w", err)
}
if errIpv4 != nil {
return fmt.Errorf("get current IPv4 network nameservers from model: %w", errIpv4)
}
reconciledNameservers := utils.ReconcileStringSlices(modelNameservers, respNameservers)
reconciledIPv4Nameservers := utils.ReconcileStringSlices(modelIPv4Nameservers, respNameservers)
nameserversTF, diags := types.ListValueFrom(ctx, types.StringType, reconciledNameservers)
ipv4NameserversTF, ipv4Diags := types.ListValueFrom(ctx, types.StringType, reconciledIPv4Nameservers)
if diags.HasError() {
return fmt.Errorf("map network nameservers: %w", core.DiagsToError(diags))
}
if ipv4Diags.HasError() {
return fmt.Errorf("map IPv4 network nameservers: %w", core.DiagsToError(ipv4Diags))
}
model.Nameservers = nameserversTF
model.IPv4Nameservers = ipv4NameserversTF
}
if networkResp.Prefixes == nil {
model.Prefixes = types.ListNull(types.StringType)
model.IPv4Prefixes = types.ListNull(types.StringType)
} else {
respPrefixes := *networkResp.Prefixes
prefixesTF, diags := types.ListValueFrom(ctx, types.StringType, respPrefixes)
@ -436,12 +587,59 @@ func mapFields(ctx context.Context, networkResp *iaas.Network, model *Model) err
}
model.Prefixes = prefixesTF
model.IPv4Prefixes = prefixesTF
}
if networkResp.Gateway != nil {
model.IPv4Gateway = types.StringPointerValue(networkResp.GetGateway())
} else {
model.IPv4Gateway = types.StringNull()
}
// IPv6
if networkResp.NameserversV6 == nil {
model.IPv6Nameservers = types.ListNull(types.StringType)
} else {
respIPv6Nameservers := *networkResp.NameserversV6
modelIPv6Nameservers, errIpv6 := utils.ListValuetoStringSlice(model.IPv6Nameservers)
if errIpv6 != nil {
return fmt.Errorf("get current IPv6 network nameservers from model: %w", errIpv6)
}
reconciledIPv6Nameservers := utils.ReconcileStringSlices(modelIPv6Nameservers, respIPv6Nameservers)
ipv6NameserversTF, ipv6Diags := types.ListValueFrom(ctx, types.StringType, reconciledIPv6Nameservers)
if ipv6Diags.HasError() {
return fmt.Errorf("map IPv6 network nameservers: %w", core.DiagsToError(ipv6Diags))
}
model.IPv6Nameservers = ipv6NameserversTF
}
if networkResp.PrefixesV6 == nil {
model.IPv6Prefixes = types.ListNull(types.StringType)
} else {
respPrefixesV6 := *networkResp.PrefixesV6
prefixesV6TF, diags := types.ListValueFrom(ctx, types.StringType, respPrefixesV6)
if diags.HasError() {
return fmt.Errorf("map network IPv6 prefixes: %w", core.DiagsToError(diags))
}
model.IPv6Prefixes = prefixesV6TF
}
if networkResp.Gatewayv6 != nil {
model.IPv6Gateway = types.StringPointerValue(networkResp.GetGatewayv6())
} else {
model.IPv6Gateway = types.StringNull()
}
model.NetworkId = types.StringValue(networkId)
model.Name = types.StringPointerValue(networkResp.Name)
model.PublicIP = types.StringPointerValue(networkResp.PublicIp)
model.Labels = labels
model.Routed = types.BoolPointerValue(networkResp.Routed)
return nil
}
@ -450,14 +648,60 @@ func toCreatePayload(ctx context.Context, model *Model) (*iaas.CreateNetworkPayl
if model == nil {
return nil, fmt.Errorf("nil model")
}
addressFamily := &iaas.CreateNetworkAddressFamily{}
modelNameservers := []string{}
for _, ns := range model.Nameservers.Elements() {
nameserverString, ok := ns.(types.String)
modelIPv6Nameservers := []string{}
for _, ipv6ns := range model.IPv6Nameservers.Elements() {
ipv6NameserverString, ok := ipv6ns.(types.String)
if !ok {
return nil, fmt.Errorf("type assertion failed")
}
modelNameservers = append(modelNameservers, nameserverString.ValueString())
modelIPv6Nameservers = append(modelIPv6Nameservers, ipv6NameserverString.ValueString())
}
if !(model.IPv6Prefix.IsNull() || model.IPv6PrefixLength.IsNull() || model.IPv6Nameservers.IsNull()) {
addressFamily.Ipv6 = &iaas.CreateNetworkIPv6Body{
Nameservers: &modelIPv6Nameservers,
Prefix: conversion.StringValueToPointer(model.IPv6Prefix),
PrefixLength: conversion.Int64ValueToPointer(model.IPv6PrefixLength),
}
if model.NoIPv6Gateway.ValueBool() {
addressFamily.Ipv6.Gateway = iaas.NewNullableString(nil)
} else if !(model.IPv6Gateway.IsUnknown() || model.IPv6Gateway.IsNull()) {
addressFamily.Ipv6.Gateway = iaas.NewNullableString(conversion.StringValueToPointer(model.IPv6Gateway))
}
}
modelIPv4Nameservers := []string{}
var modelIPv4List []attr.Value
if !(model.IPv4Nameservers.IsNull() || model.IPv4Nameservers.IsUnknown()) {
modelIPv4List = model.IPv4Nameservers.Elements()
} else {
modelIPv4List = model.Nameservers.Elements()
}
for _, ipv4ns := range modelIPv4List {
ipv4NameserverString, ok := ipv4ns.(types.String)
if !ok {
return nil, fmt.Errorf("type assertion failed")
}
modelIPv4Nameservers = append(modelIPv4Nameservers, ipv4NameserverString.ValueString())
}
if !model.IPv4Prefix.IsNull() || !model.IPv4PrefixLength.IsNull() || !model.IPv4Nameservers.IsNull() || !model.Nameservers.IsNull() {
addressFamily.Ipv4 = &iaas.CreateNetworkIPv4Body{
Nameservers: &modelIPv4Nameservers,
Prefix: conversion.StringValueToPointer(model.IPv4Prefix),
PrefixLength: conversion.Int64ValueToPointer(model.IPv4PrefixLength),
}
if model.NoIPv4Gateway.ValueBool() {
addressFamily.Ipv4.Gateway = iaas.NewNullableString(nil)
} else if !(model.IPv4Gateway.IsUnknown() || model.IPv4Gateway.IsNull()) {
addressFamily.Ipv4.Gateway = iaas.NewNullableString(conversion.StringValueToPointer(model.IPv4Gateway))
}
}
labels, err := conversion.ToStringInterfaceMap(ctx, model.Labels)
@ -465,44 +709,88 @@ func toCreatePayload(ctx context.Context, model *Model) (*iaas.CreateNetworkPayl
return nil, fmt.Errorf("converting to Go map: %w", err)
}
return &iaas.CreateNetworkPayload{
Name: conversion.StringValueToPointer(model.Name),
AddressFamily: &iaas.CreateNetworkAddressFamily{
Ipv4: &iaas.CreateNetworkIPv4Body{
PrefixLength: conversion.Int64ValueToPointer(model.IPv4PrefixLength),
Nameservers: &modelNameservers,
},
},
payload := iaas.CreateNetworkPayload{
Name: conversion.StringValueToPointer(model.Name),
Labels: &labels,
}, nil
Routed: conversion.BoolValueToPointer(model.Routed),
}
if addressFamily.Ipv6 != nil || addressFamily.Ipv4 != nil {
payload.AddressFamily = addressFamily
}
return &payload, nil
}
func toUpdatePayload(ctx context.Context, model *Model, currentLabels types.Map) (*iaas.PartialUpdateNetworkPayload, error) {
func toUpdatePayload(ctx context.Context, model, stateModel *Model) (*iaas.PartialUpdateNetworkPayload, error) {
if model == nil {
return nil, fmt.Errorf("nil model")
}
addressFamily := &iaas.UpdateNetworkAddressFamily{}
modelNameservers := []string{}
for _, ns := range model.Nameservers.Elements() {
nameserverString, ok := ns.(types.String)
modelIPv6Nameservers := []string{}
for _, ipv6ns := range model.IPv6Nameservers.Elements() {
ipv6NameserverString, ok := ipv6ns.(types.String)
if !ok {
return nil, fmt.Errorf("type assertion failed")
}
modelNameservers = append(modelNameservers, nameserverString.ValueString())
modelIPv6Nameservers = append(modelIPv6Nameservers, ipv6NameserverString.ValueString())
}
if !(model.IPv6Nameservers.IsNull() || model.IPv6Nameservers.IsUnknown()) {
addressFamily.Ipv6 = &iaas.UpdateNetworkIPv6Body{
Nameservers: &modelIPv6Nameservers,
}
if model.NoIPv6Gateway.ValueBool() {
addressFamily.Ipv6.Gateway = iaas.NewNullableString(nil)
} else if !(model.IPv6Gateway.IsUnknown() || model.IPv6Gateway.IsNull()) {
addressFamily.Ipv6.Gateway = iaas.NewNullableString(conversion.StringValueToPointer(model.IPv6Gateway))
}
}
modelIPv4Nameservers := []string{}
var modelIPv4List []attr.Value
if !(model.IPv4Nameservers.IsNull() || model.IPv4Nameservers.IsUnknown()) {
modelIPv4List = model.IPv4Nameservers.Elements()
} else {
modelIPv4List = model.Nameservers.Elements()
}
for _, ipv4ns := range modelIPv4List {
ipv4NameserverString, ok := ipv4ns.(types.String)
if !ok {
return nil, fmt.Errorf("type assertion failed")
}
modelIPv4Nameservers = append(modelIPv4Nameservers, ipv4NameserverString.ValueString())
}
if !model.IPv4Nameservers.IsNull() || !model.Nameservers.IsNull() {
addressFamily.Ipv4 = &iaas.UpdateNetworkIPv4Body{
Nameservers: &modelIPv4Nameservers,
}
if model.NoIPv4Gateway.ValueBool() {
addressFamily.Ipv4.Gateway = iaas.NewNullableString(nil)
} else if !(model.IPv4Gateway.IsUnknown() || model.IPv4Gateway.IsNull()) {
addressFamily.Ipv4.Gateway = iaas.NewNullableString(conversion.StringValueToPointer(model.IPv4Gateway))
}
}
currentLabels := stateModel.Labels
labels, err := conversion.ToJSONMapPartialUpdatePayload(ctx, currentLabels, model.Labels)
if err != nil {
return nil, fmt.Errorf("converting to Go map: %w", err)
}
return &iaas.PartialUpdateNetworkPayload{
Name: conversion.StringValueToPointer(model.Name),
AddressFamily: &iaas.UpdateNetworkAddressFamily{
Ipv4: &iaas.UpdateNetworkIPv4Body{
Nameservers: &modelNameservers,
},
},
payload := iaas.PartialUpdateNetworkPayload{
Name: conversion.StringValueToPointer(model.Name),
Labels: &labels,
}, nil
}
if addressFamily.Ipv6 != nil || addressFamily.Ipv4 != nil {
payload.AddressFamily = addressFamily
}
return &payload, nil
}

View file

@ -27,6 +27,7 @@ func TestMapFields(t *testing.T) {
},
&iaas.Network{
NetworkId: utils.Ptr("nid"),
Gateway: iaas.NewNullableString(nil),
},
Model{
Id: types.StringValue("pid,nid"),
@ -34,10 +35,20 @@ func TestMapFields(t *testing.T) {
NetworkId: types.StringValue("nid"),
Name: types.StringNull(),
Nameservers: types.ListNull(types.StringType),
IPv4Nameservers: types.ListNull(types.StringType),
IPv4PrefixLength: types.Int64Null(),
IPv4Gateway: types.StringNull(),
IPv4Prefix: types.StringNull(),
Prefixes: types.ListNull(types.StringType),
IPv4Prefixes: types.ListNull(types.StringType),
IPv6Nameservers: types.ListNull(types.StringType),
IPv6PrefixLength: types.Int64Null(),
IPv6Gateway: types.StringNull(),
IPv6Prefix: types.StringNull(),
IPv6Prefixes: types.ListNull(types.StringType),
PublicIP: types.StringNull(),
Labels: types.MapNull(types.StringType),
Routed: types.BoolNull(),
},
true,
},
@ -58,10 +69,21 @@ func TestMapFields(t *testing.T) {
"prefix1",
"prefix2",
},
NameserversV6: &[]string{
"ns1",
"ns2",
},
PrefixesV6: &[]string{
"prefix1",
"prefix2",
},
PublicIp: utils.Ptr("publicIp"),
Labels: &map[string]interface{}{
"key": "value",
},
Routed: utils.Ptr(true),
Gateway: iaas.NewNullableString(utils.Ptr("gateway")),
Gatewayv6: iaas.NewNullableString(utils.Ptr("gateway")),
},
Model{
Id: types.StringValue("pid,nid"),
@ -72,20 +94,40 @@ func TestMapFields(t *testing.T) {
types.StringValue("ns1"),
types.StringValue("ns2"),
}),
IPv4Nameservers: types.ListValueMust(types.StringType, []attr.Value{
types.StringValue("ns1"),
types.StringValue("ns2"),
}),
IPv4PrefixLength: types.Int64Null(),
Prefixes: types.ListValueMust(types.StringType, []attr.Value{
types.StringValue("prefix1"),
types.StringValue("prefix2"),
}),
IPv4Prefixes: types.ListValueMust(types.StringType, []attr.Value{
types.StringValue("prefix1"),
types.StringValue("prefix2"),
}),
IPv6Nameservers: types.ListValueMust(types.StringType, []attr.Value{
types.StringValue("ns1"),
types.StringValue("ns2"),
}),
IPv6PrefixLength: types.Int64Null(),
IPv6Prefixes: types.ListValueMust(types.StringType, []attr.Value{
types.StringValue("prefix1"),
types.StringValue("prefix2"),
}),
PublicIP: types.StringValue("publicIp"),
Labels: types.MapValueMust(types.StringType, map[string]attr.Value{
"key": types.StringValue("value"),
}),
Routed: types.BoolValue(true),
IPv4Gateway: types.StringValue("gateway"),
IPv6Gateway: types.StringValue("gateway"),
},
true,
},
{
"nameservers_changed_outside_tf",
"ipv4_nameservers_changed_outside_tf",
Model{
ProjectId: types.StringValue("pid"),
NetworkId: types.StringValue("nid"),
@ -93,6 +135,10 @@ func TestMapFields(t *testing.T) {
types.StringValue("ns1"),
types.StringValue("ns2"),
}),
IPv4Nameservers: types.ListValueMust(types.StringType, []attr.Value{
types.StringValue("ns1"),
types.StringValue("ns2"),
}),
},
&iaas.Network{
NetworkId: utils.Ptr("nid"),
@ -102,21 +148,63 @@ func TestMapFields(t *testing.T) {
},
},
Model{
Id: types.StringValue("pid,nid"),
ProjectId: types.StringValue("pid"),
NetworkId: types.StringValue("nid"),
Name: types.StringNull(),
Prefixes: types.ListNull(types.StringType),
Id: types.StringValue("pid,nid"),
ProjectId: types.StringValue("pid"),
NetworkId: types.StringValue("nid"),
Name: types.StringNull(),
IPv6Prefixes: types.ListNull(types.StringType),
IPv6Nameservers: types.ListNull(types.StringType),
Prefixes: types.ListNull(types.StringType),
IPv4Prefixes: types.ListNull(types.StringType),
Nameservers: types.ListValueMust(types.StringType, []attr.Value{
types.StringValue("ns2"),
types.StringValue("ns3"),
}),
IPv4Nameservers: types.ListValueMust(types.StringType, []attr.Value{
types.StringValue("ns2"),
types.StringValue("ns3"),
}),
Labels: types.MapNull(types.StringType),
},
true,
},
{
"prefixes_changed_outisde_tf",
"ipv6_nameservers_changed_outside_tf",
Model{
ProjectId: types.StringValue("pid"),
NetworkId: types.StringValue("nid"),
IPv6Nameservers: types.ListValueMust(types.StringType, []attr.Value{
types.StringValue("ns1"),
types.StringValue("ns2"),
}),
},
&iaas.Network{
NetworkId: utils.Ptr("nid"),
NameserversV6: &[]string{
"ns2",
"ns3",
},
},
Model{
Id: types.StringValue("pid,nid"),
ProjectId: types.StringValue("pid"),
NetworkId: types.StringValue("nid"),
Name: types.StringNull(),
IPv6Prefixes: types.ListNull(types.StringType),
IPv4Nameservers: types.ListNull(types.StringType),
Prefixes: types.ListNull(types.StringType),
IPv4Prefixes: types.ListNull(types.StringType),
Nameservers: types.ListNull(types.StringType),
IPv6Nameservers: types.ListValueMust(types.StringType, []attr.Value{
types.StringValue("ns2"),
types.StringValue("ns3"),
}),
Labels: types.MapNull(types.StringType),
},
true,
},
{
"ipv4_prefixes_changed_outside_tf",
Model{
ProjectId: types.StringValue("pid"),
NetworkId: types.StringValue("nid"),
@ -137,13 +225,88 @@ func TestMapFields(t *testing.T) {
ProjectId: types.StringValue("pid"),
NetworkId: types.StringValue("nid"),
Name: types.StringNull(),
IPv6Nameservers: types.ListNull(types.StringType),
IPv6PrefixLength: types.Int64Null(),
IPv6Prefixes: types.ListNull(types.StringType),
Labels: types.MapNull(types.StringType),
Nameservers: types.ListNull(types.StringType),
IPv4Nameservers: types.ListNull(types.StringType),
IPv4PrefixLength: types.Int64Null(),
Prefixes: types.ListValueMust(types.StringType, []attr.Value{
types.StringValue("prefix2"),
types.StringValue("prefix3"),
}),
Labels: types.MapNull(types.StringType),
IPv4Prefixes: types.ListValueMust(types.StringType, []attr.Value{
types.StringValue("prefix2"),
types.StringValue("prefix3"),
}),
},
true,
},
{
"ipv6_prefixes_changed_outside_tf",
Model{
ProjectId: types.StringValue("pid"),
NetworkId: types.StringValue("nid"),
IPv6Prefixes: types.ListValueMust(types.StringType, []attr.Value{
types.StringValue("prefix1"),
types.StringValue("prefix2"),
}),
},
&iaas.Network{
NetworkId: utils.Ptr("nid"),
PrefixesV6: &[]string{
"prefix2",
"prefix3",
},
},
Model{
Id: types.StringValue("pid,nid"),
ProjectId: types.StringValue("pid"),
NetworkId: types.StringValue("nid"),
Name: types.StringNull(),
IPv4Nameservers: types.ListNull(types.StringType),
IPv4PrefixLength: types.Int64Null(),
Prefixes: types.ListNull(types.StringType),
IPv4Prefixes: types.ListNull(types.StringType),
Labels: types.MapNull(types.StringType),
Nameservers: types.ListNull(types.StringType),
IPv6Nameservers: types.ListNull(types.StringType),
IPv6PrefixLength: types.Int64Null(),
IPv6Prefixes: types.ListValueMust(types.StringType, []attr.Value{
types.StringValue("prefix2"),
types.StringValue("prefix3"),
}),
},
true,
},
{
"ipv4_ipv6_gateway_nil",
Model{
ProjectId: types.StringValue("pid"),
NetworkId: types.StringValue("nid"),
},
&iaas.Network{
NetworkId: utils.Ptr("nid"),
},
Model{
Id: types.StringValue("pid,nid"),
ProjectId: types.StringValue("pid"),
NetworkId: types.StringValue("nid"),
Name: types.StringNull(),
Nameservers: types.ListNull(types.StringType),
IPv4Nameservers: types.ListNull(types.StringType),
IPv4PrefixLength: types.Int64Null(),
IPv4Gateway: types.StringNull(),
Prefixes: types.ListNull(types.StringType),
IPv4Prefixes: types.ListNull(types.StringType),
IPv6Nameservers: types.ListNull(types.StringType),
IPv6PrefixLength: types.Int64Null(),
IPv6Gateway: types.StringNull(),
IPv6Prefixes: types.ListNull(types.StringType),
PublicIP: types.StringNull(),
Labels: types.MapNull(types.StringType),
Routed: types.BoolNull(),
},
true,
},
@ -194,7 +357,7 @@ func TestToCreatePayload(t *testing.T) {
"default_ok",
&Model{
Name: types.StringValue("name"),
Nameservers: types.ListValueMust(types.StringType, []attr.Value{
IPv4Nameservers: types.ListValueMust(types.StringType, []attr.Value{
types.StringValue("ns1"),
types.StringValue("ns2"),
}),
@ -202,6 +365,9 @@ func TestToCreatePayload(t *testing.T) {
Labels: types.MapValueMust(types.StringType, map[string]attr.Value{
"key": types.StringValue("value"),
}),
Routed: types.BoolValue(false),
IPv4Gateway: types.StringValue("gateway"),
IPv4Prefix: types.StringValue("prefix"),
},
&iaas.CreateNetworkPayload{
Name: utils.Ptr("name"),
@ -212,11 +378,86 @@ func TestToCreatePayload(t *testing.T) {
"ns2",
},
PrefixLength: utils.Ptr(int64(24)),
Gateway: iaas.NewNullableString(utils.Ptr("gateway")),
Prefix: utils.Ptr("prefix"),
},
},
Labels: &map[string]interface{}{
"key": "value",
},
Routed: utils.Ptr(false),
},
true,
},
{
"ipv4_nameservers_okay",
&Model{
Name: types.StringValue("name"),
Nameservers: types.ListValueMust(types.StringType, []attr.Value{
types.StringValue("ns1"),
types.StringValue("ns2"),
}),
IPv4PrefixLength: types.Int64Value(24),
Labels: types.MapValueMust(types.StringType, map[string]attr.Value{
"key": types.StringValue("value"),
}),
Routed: types.BoolValue(false),
IPv4Gateway: types.StringValue("gateway"),
IPv4Prefix: types.StringValue("prefix"),
},
&iaas.CreateNetworkPayload{
Name: utils.Ptr("name"),
AddressFamily: &iaas.CreateNetworkAddressFamily{
Ipv4: &iaas.CreateNetworkIPv4Body{
Nameservers: &[]string{
"ns1",
"ns2",
},
PrefixLength: utils.Ptr(int64(24)),
Gateway: iaas.NewNullableString(utils.Ptr("gateway")),
Prefix: utils.Ptr("prefix"),
},
},
Labels: &map[string]interface{}{
"key": "value",
},
Routed: utils.Ptr(false),
},
true,
},
{
"ipv6_default_ok",
&Model{
Name: types.StringValue("name"),
IPv6Nameservers: types.ListValueMust(types.StringType, []attr.Value{
types.StringValue("ns1"),
types.StringValue("ns2"),
}),
IPv6PrefixLength: types.Int64Value(24),
Labels: types.MapValueMust(types.StringType, map[string]attr.Value{
"key": types.StringValue("value"),
}),
Routed: types.BoolValue(false),
IPv6Gateway: types.StringValue("gateway"),
IPv6Prefix: types.StringValue("prefix"),
},
&iaas.CreateNetworkPayload{
Name: utils.Ptr("name"),
AddressFamily: &iaas.CreateNetworkAddressFamily{
Ipv6: &iaas.CreateNetworkIPv6Body{
Nameservers: &[]string{
"ns1",
"ns2",
},
PrefixLength: utils.Ptr(int64(24)),
Gateway: iaas.NewNullableString(utils.Ptr("gateway")),
Prefix: utils.Ptr("prefix"),
},
},
Labels: &map[string]interface{}{
"key": "value",
},
Routed: utils.Ptr(false),
},
true,
},
@ -231,7 +472,7 @@ func TestToCreatePayload(t *testing.T) {
t.Fatalf("Should not have failed: %v", err)
}
if tt.isValid {
diff := cmp.Diff(output, tt.expected)
diff := cmp.Diff(output, tt.expected, cmp.AllowUnexported(iaas.NullableString{}))
if diff != "" {
t.Fatalf("Data does not match: %s", diff)
}
@ -244,11 +485,48 @@ func TestToUpdatePayload(t *testing.T) {
tests := []struct {
description string
input *Model
state Model
expected *iaas.PartialUpdateNetworkPayload
isValid bool
}{
{
"default_ok",
&Model{
Name: types.StringValue("name"),
IPv4Nameservers: types.ListValueMust(types.StringType, []attr.Value{
types.StringValue("ns1"),
types.StringValue("ns2"),
}),
Labels: types.MapValueMust(types.StringType, map[string]attr.Value{
"key": types.StringValue("value"),
}),
Routed: types.BoolValue(true),
IPv4Gateway: types.StringValue("gateway"),
},
Model{
ProjectId: types.StringValue("pid"),
NetworkId: types.StringValue("nid"),
Labels: types.MapNull(types.StringType),
},
&iaas.PartialUpdateNetworkPayload{
Name: utils.Ptr("name"),
AddressFamily: &iaas.UpdateNetworkAddressFamily{
Ipv4: &iaas.UpdateNetworkIPv4Body{
Nameservers: &[]string{
"ns1",
"ns2",
},
Gateway: iaas.NewNullableString(utils.Ptr("gateway")),
},
},
Labels: &map[string]interface{}{
"key": "value",
},
},
true,
},
{
"ipv4_nameservers_okay",
&Model{
Name: types.StringValue("name"),
Nameservers: types.ListValueMust(types.StringType, []attr.Value{
@ -258,6 +536,48 @@ func TestToUpdatePayload(t *testing.T) {
Labels: types.MapValueMust(types.StringType, map[string]attr.Value{
"key": types.StringValue("value"),
}),
Routed: types.BoolValue(true),
IPv4Gateway: types.StringValue("gateway"),
},
Model{
ProjectId: types.StringValue("pid"),
NetworkId: types.StringValue("nid"),
Labels: types.MapNull(types.StringType),
},
&iaas.PartialUpdateNetworkPayload{
Name: utils.Ptr("name"),
AddressFamily: &iaas.UpdateNetworkAddressFamily{
Ipv4: &iaas.UpdateNetworkIPv4Body{
Nameservers: &[]string{
"ns1",
"ns2",
},
Gateway: iaas.NewNullableString(utils.Ptr("gateway")),
},
},
Labels: &map[string]interface{}{
"key": "value",
},
},
true,
},
{
"ipv4_gateway_nil",
&Model{
Name: types.StringValue("name"),
IPv4Nameservers: types.ListValueMust(types.StringType, []attr.Value{
types.StringValue("ns1"),
types.StringValue("ns2"),
}),
Labels: types.MapValueMust(types.StringType, map[string]attr.Value{
"key": types.StringValue("value"),
}),
Routed: types.BoolValue(true),
},
Model{
ProjectId: types.StringValue("pid"),
NetworkId: types.StringValue("nid"),
Labels: types.MapNull(types.StringType),
},
&iaas.PartialUpdateNetworkPayload{
Name: utils.Ptr("name"),
@ -275,10 +595,80 @@ func TestToUpdatePayload(t *testing.T) {
},
true,
},
{
"ipv6_default_ok",
&Model{
Name: types.StringValue("name"),
IPv6Nameservers: types.ListValueMust(types.StringType, []attr.Value{
types.StringValue("ns1"),
types.StringValue("ns2"),
}),
Labels: types.MapValueMust(types.StringType, map[string]attr.Value{
"key": types.StringValue("value"),
}),
Routed: types.BoolValue(true),
IPv6Gateway: types.StringValue("gateway"),
},
Model{
ProjectId: types.StringValue("pid"),
NetworkId: types.StringValue("nid"),
Labels: types.MapNull(types.StringType),
},
&iaas.PartialUpdateNetworkPayload{
Name: utils.Ptr("name"),
AddressFamily: &iaas.UpdateNetworkAddressFamily{
Ipv6: &iaas.UpdateNetworkIPv6Body{
Nameservers: &[]string{
"ns1",
"ns2",
},
Gateway: iaas.NewNullableString(utils.Ptr("gateway")),
},
},
Labels: &map[string]interface{}{
"key": "value",
},
},
true,
},
{
"ipv6_gateway_nil",
&Model{
Name: types.StringValue("name"),
IPv6Nameservers: types.ListValueMust(types.StringType, []attr.Value{
types.StringValue("ns1"),
types.StringValue("ns2"),
}),
Labels: types.MapValueMust(types.StringType, map[string]attr.Value{
"key": types.StringValue("value"),
}),
Routed: types.BoolValue(true),
},
Model{
ProjectId: types.StringValue("pid"),
NetworkId: types.StringValue("nid"),
Labels: types.MapNull(types.StringType),
},
&iaas.PartialUpdateNetworkPayload{
Name: utils.Ptr("name"),
AddressFamily: &iaas.UpdateNetworkAddressFamily{
Ipv6: &iaas.UpdateNetworkIPv6Body{
Nameservers: &[]string{
"ns1",
"ns2",
},
},
},
Labels: &map[string]interface{}{
"key": "value",
},
},
true,
},
}
for _, tt := range tests {
t.Run(tt.description, func(t *testing.T) {
output, err := toUpdatePayload(context.Background(), tt.input, types.MapNull(types.StringType))
output, err := toUpdatePayload(context.Background(), tt.input, &tt.state)
if !tt.isValid && err == nil {
t.Fatalf("Should have failed")
}
@ -286,7 +676,7 @@ func TestToUpdatePayload(t *testing.T) {
t.Fatalf("Should not have failed: %v", err)
}
if tt.isValid {
diff := cmp.Diff(output, tt.expected)
diff := cmp.Diff(output, tt.expected, cmp.AllowUnexported(iaas.NullableString{}))
if diff != "" {
t.Fatalf("Data does not match: %s", diff)
}