Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions docs/data-sources/public_ip_ranges.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,30 @@ A list of all public IP ranges that STACKIT uses.

```terraform
data "stackit_public_ip_ranges" "example" {}

locals {
vpn_cidrs = ["X.X.X.X/32", "X.X.X.X/24"]
}

# example usage: allow stackit services and customer vpn cidr to access observability apis
resource "stackit_observability_instance" "example" {
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
name = "example-instance"
plan_name = "Observability-Monitoring-Medium-EU01"
# Allow all stackit services and customer vpn cidr to access observability apis
acl = concat(data.stackit_public_ip_ranges.example.cidr_list, local.vpn_cidrs)
metrics_retention_days = 90
metrics_retention_days_5m_downsampling = 90
metrics_retention_days_1h_downsampling = 90
}
```

<!-- schema generated by tfplugindocs -->
## Schema

### Read-Only

- `cidr_list` (List of String) A list of IP range strings (CIDRs) extracted from the public_ip_ranges for easy consumption.
- `id` (String) Terraform's internal resource ID. It takes the values of "`public_ip_ranges.*.cidr`".
- `public_ip_ranges` (Attributes List) A list of all public IP ranges. (see [below for nested schema](#nestedatt--public_ip_ranges))

Expand Down
18 changes: 17 additions & 1 deletion examples/data-sources/stackit_public_ip_ranges/data-source.tf
Original file line number Diff line number Diff line change
@@ -1 +1,17 @@
data "stackit_public_ip_ranges" "example" {}
data "stackit_public_ip_ranges" "example" {}

locals {
vpn_cidrs = ["X.X.X.X/32", "X.X.X.X/24"]
}

# example usage: allow stackit services and customer vpn cidr to access observability apis
Comment on lines +2 to +7
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR looks in general good. Only a nitpick, can you adjust the comment like in the suggestion, to separate more between the simple example of the datasource and how it can be used with with locals

Suggested change
locals {
vpn_cidrs = ["X.X.X.X/32", "X.X.X.X/24"]
}
# example usage: allow stackit services and customer vpn cidr to access observability apis
# example usage: allow stackit services and customer vpn cidr to access observability apis
locals {
vpn_cidrs = ["X.X.X.X/32", "X.X.X.X/24"]
}

resource "stackit_observability_instance" "example" {
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
name = "example-instance"
plan_name = "Observability-Monitoring-Medium-EU01"
# Allow all stackit services and customer vpn cidr to access observability apis
acl = concat(data.stackit_public_ip_ranges.example.cidr_list, local.vpn_cidrs)
metrics_retention_days = 90
metrics_retention_days_5m_downsampling = 90
metrics_retention_days_1h_downsampling = 90
}
22 changes: 22 additions & 0 deletions stackit/internal/services/iaas/iaas_acc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ var (
//go:embed testdata/datasource-image-v2-variants.tf
dataSourceImageVariants string

//go:embed testdata/datasource-public-ip-ranges.tf
datasourcePublicIpRanges string

//go:embed testdata/resource-image-min.tf
resourceImageMinConfig string

Expand Down Expand Up @@ -4159,6 +4162,25 @@ func TestAccImageV2DatasourceSearchVariants(t *testing.T) {
})
}

func TestAccDatasourcePublicIpRanges(t *testing.T) {
t.Log("TestDataSource STACKIT Public Ip Ranges")
resource.ParallelTest(t, resource.TestCase{
ProtoV6ProviderFactories: testutil.TestAccProtoV6ProviderFactories,
Steps: []resource.TestStep{
// Read
{
ConfigVariables: config.Variables{},
Config: fmt.Sprintf("%s\n%s", datasourcePublicIpRanges, testutil.IaaSProviderConfig()),
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttrSet("data.stackit_public_ip_ranges.example", "id"),
resource.TestCheckResourceAttrSet("data.stackit_public_ip_ranges.example", "public_ip_ranges.0.cidr"),
resource.TestCheckResourceAttrSet("data.stackit_public_ip_ranges.example", "cidr_list.0"),
),
},
},
})
}

func TestAccProject(t *testing.T) {
projectId := testutil.ProjectId
resource.ParallelTest(t, resource.TestCase{
Expand Down
18 changes: 16 additions & 2 deletions stackit/internal/services/iaas/publicipranges/datasource.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ type publicIpRangesDataSource struct {
type Model struct {
Id types.String `tfsdk:"id"` // needed by TF
PublicIpRanges types.List `tfsdk:"public_ip_ranges"`
CidrList types.List `tfsdk:"cidr_list"`
}

var publicIpRangesTypes = map[string]attr.Type{
Expand Down Expand Up @@ -97,6 +98,11 @@ func (d *publicIpRangesDataSource) Schema(_ context.Context, _ datasource.Schema
},
},
},
"cidr_list": schema.ListAttribute{
Description: "A list of IP range strings (CIDRs) extracted from the public_ip_ranges for easy consumption.",
ElementType: types.StringType,
Computed: true,
},
},
}
}
Expand Down Expand Up @@ -155,18 +161,19 @@ func mapFields(ctx context.Context, publicIpRangeResp *iaas.PublicNetworkListRes
}

// mapPublicIpRanges map the response publicIpRanges to the model
func mapPublicIpRanges(_ context.Context, publicIpRanges *[]iaas.PublicNetwork, model *Model) error {
func mapPublicIpRanges(ctx context.Context, publicIpRanges *[]iaas.PublicNetwork, model *Model) error {
if publicIpRanges == nil {
return fmt.Errorf("publicIpRanges input is nil")
}
if len(*publicIpRanges) == 0 {
model.PublicIpRanges = types.ListNull(types.ObjectType{AttrTypes: publicIpRangesTypes})
model.CidrList = types.ListNull(types.StringType)
return nil
}

var apiIpRanges []string
for _, ipRange := range *publicIpRanges {
if ipRange.Cidr != nil || *ipRange.Cidr != "" {
if ipRange.Cidr != nil && *ipRange.Cidr != "" {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch :)

apiIpRanges = append(apiIpRanges, *ipRange.Cidr)
}
}
Expand Down Expand Up @@ -197,5 +204,12 @@ func mapPublicIpRanges(_ context.Context, publicIpRanges *[]iaas.PublicNetwork,
}

model.PublicIpRanges = ipRangesTF

cidrListTF, diags := types.ListValueFrom(ctx, types.StringType, apiIpRanges)
if diags.HasError() {
return core.DiagsToError(diags)
}
model.CidrList = cidrListTF

return nil
}
115 changes: 115 additions & 0 deletions stackit/internal/services/iaas/publicipranges/datasource_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
package publicipranges

import (
"context"
"testing"

"github.com/google/go-cmp/cmp"
"github.com/hashicorp/terraform-plugin-framework/attr"
"github.com/hashicorp/terraform-plugin-framework/types"
coreUtils "github.com/stackitcloud/stackit-sdk-go/core/utils"
"github.com/stackitcloud/stackit-sdk-go/services/iaas"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/utils"
)

func TestMapPublicIpRanges(t *testing.T) {
ctx := context.Background()

tests := []struct {
name string
input *[]iaas.PublicNetwork
expected Model
isValid bool
}{
{
name: "nil input should return error",
input: nil,
isValid: false,
},
{
name: "empty input should return nulls",
input: &[]iaas.PublicNetwork{},
expected: Model{
PublicIpRanges: types.ListNull(types.ObjectType{AttrTypes: publicIpRangesTypes}),
CidrList: types.ListNull(types.StringType),
},
isValid: true,
},
{
name: "valid cidr entries",
input: &[]iaas.PublicNetwork{
{Cidr: coreUtils.Ptr("192.168.0.0/24")},
{Cidr: coreUtils.Ptr("192.168.1.0/24")},
},
expected: func() Model {
cidrs := []string{"192.168.0.0/24", "192.168.1.0/24"}
ipRangesList := make([]attr.Value, 0, len(cidrs))
for _, cidr := range cidrs {
ipRange, _ := types.ObjectValue(publicIpRangesTypes, map[string]attr.Value{
"cidr": types.StringValue(cidr),
})
ipRangesList = append(ipRangesList, ipRange)
}
ipRangesVal, _ := types.ListValue(types.ObjectType{AttrTypes: publicIpRangesTypes}, ipRangesList)
cidrListVal, _ := types.ListValueFrom(ctx, types.StringType, cidrs)

return Model{
PublicIpRanges: ipRangesVal,
CidrList: cidrListVal,
Id: utils.BuildInternalTerraformId(cidrs...),
}
}(),
isValid: true,
},
{
name: "filter out empty CIDRs",
input: &[]iaas.PublicNetwork{
{Cidr: coreUtils.Ptr("")},
{Cidr: nil},
{Cidr: coreUtils.Ptr("10.0.0.0/8")},
},
expected: func() Model {
cidrs := []string{"10.0.0.0/8"}
ipRange, _ := types.ObjectValue(publicIpRangesTypes, map[string]attr.Value{
"cidr": types.StringValue("10.0.0.0/8"),
})
ipRangesVal, _ := types.ListValue(types.ObjectType{AttrTypes: publicIpRangesTypes}, []attr.Value{ipRange})
cidrListVal, _ := types.ListValueFrom(ctx, types.StringType, cidrs)
return Model{
PublicIpRanges: ipRangesVal,
CidrList: cidrListVal,
Id: utils.BuildInternalTerraformId(cidrs...),
}
}(),
isValid: true,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
var model Model
err := mapPublicIpRanges(ctx, tt.input, &model)

if !tt.isValid {
if err == nil {
t.Fatalf("Expected error but got nil")
}
return
} else if err != nil {
t.Fatalf("Unexpected error: %v", err)
}

if diff := cmp.Diff(tt.expected.Id, model.Id); diff != "" {
t.Errorf("ID does not match:\n%s", diff)
}

if diff := cmp.Diff(tt.expected.CidrList, model.CidrList); diff != "" {
t.Errorf("cidr_list does not match:\n%s", diff)
}

if diff := cmp.Diff(tt.expected.PublicIpRanges, model.PublicIpRanges); diff != "" {
t.Errorf("public_ip_ranges does not match:\n%s", diff)
}
})
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
data "stackit_public_ip_ranges" "example" {}
Loading