@@ -4,17 +4,20 @@ import (
44 "context"
55 "fmt"
66 "net/http"
7+ "strings"
78
89 "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
910 "github.com/hashicorp/terraform-plugin-framework/datasource"
1011 "github.com/hashicorp/terraform-plugin-framework/datasource/schema"
12+ "github.com/hashicorp/terraform-plugin-framework/diag"
1113 "github.com/hashicorp/terraform-plugin-framework/schema/validator"
1214 "github.com/hashicorp/terraform-plugin-framework/types"
1315 "github.com/hashicorp/terraform-plugin-log/tflog"
1416 "github.com/stackitcloud/stackit-sdk-go/core/config"
1517 "github.com/stackitcloud/stackit-sdk-go/core/oapierror"
1618 "github.com/stackitcloud/stackit-sdk-go/services/iaas"
1719 "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core"
20+ "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/utils"
1821 "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/validate"
1922)
2023
2326 _ datasource.DataSource = & networkDataSource {}
2427)
2528
29+ type DataSourceModel struct {
30+ Id types.String `tfsdk:"id"` // needed by TF
31+ ProjectId types.String `tfsdk:"project_id"`
32+ NetworkId types.String `tfsdk:"network_id"`
33+ Name types.String `tfsdk:"name"`
34+ Nameservers types.List `tfsdk:"nameservers"`
35+ IPv4Gateway types.String `tfsdk:"ipv4_gateway"`
36+ IPv4Nameservers types.List `tfsdk:"ipv4_nameservers"`
37+ IPv4Prefix types.String `tfsdk:"ipv4_prefix"`
38+ IPv4PrefixLength types.Int64 `tfsdk:"ipv4_prefix_length"`
39+ Prefixes types.List `tfsdk:"prefixes"`
40+ IPv4Prefixes types.List `tfsdk:"ipv4_prefixes"`
41+ IPv6Gateway types.String `tfsdk:"ipv6_gateway"`
42+ IPv6Nameservers types.List `tfsdk:"ipv6_nameservers"`
43+ IPv6Prefix types.String `tfsdk:"ipv6_prefix"`
44+ IPv6PrefixLength types.Int64 `tfsdk:"ipv6_prefix_length"`
45+ IPv6Prefixes types.List `tfsdk:"ipv6_prefixes"`
46+ PublicIP types.String `tfsdk:"public_ip"`
47+ Labels types.Map `tfsdk:"labels"`
48+ Routed types.Bool `tfsdk:"routed"`
49+ }
50+
2651// NewNetworkDataSource is a helper function to simplify the provider implementation.
2752func NewNetworkDataSource () datasource.DataSource {
2853 return & networkDataSource {}
@@ -181,7 +206,7 @@ func (d *networkDataSource) Schema(_ context.Context, _ datasource.SchemaRequest
181206
182207// Read refreshes the Terraform state with the latest data.
183208func (d * networkDataSource ) Read (ctx context.Context , req datasource.ReadRequest , resp * datasource.ReadResponse ) { // nolint:gocritic // function signature required by Terraform
184- var model Model
209+ var model DataSourceModel
185210 diags := req .Config .Get (ctx , & model )
186211 resp .Diagnostics .Append (diags ... )
187212 if resp .Diagnostics .HasError () {
@@ -203,7 +228,7 @@ func (d *networkDataSource) Read(ctx context.Context, req datasource.ReadRequest
203228 return
204229 }
205230
206- err = mapFields (ctx , networkResp , & model )
231+ err = mapDataSourceFields (ctx , networkResp , & model )
207232 if err != nil {
208233 core .LogAndAddError (ctx , & resp .Diagnostics , "Error reading network" , fmt .Sprintf ("Processing API payload: %v" , err ))
209234 return
@@ -215,3 +240,142 @@ func (d *networkDataSource) Read(ctx context.Context, req datasource.ReadRequest
215240 }
216241 tflog .Info (ctx , "Network read" )
217242}
243+
244+ func mapDataSourceFields (ctx context.Context , networkResp * iaas.Network , model * DataSourceModel ) error {
245+ if networkResp == nil {
246+ return fmt .Errorf ("response input is nil" )
247+ }
248+ if model == nil {
249+ return fmt .Errorf ("model input is nil" )
250+ }
251+
252+ var networkId string
253+ if model .NetworkId .ValueString () != "" {
254+ networkId = model .NetworkId .ValueString ()
255+ } else if networkResp .NetworkId != nil {
256+ networkId = * networkResp .NetworkId
257+ } else {
258+ return fmt .Errorf ("network id not present" )
259+ }
260+
261+ idParts := []string {
262+ model .ProjectId .ValueString (),
263+ networkId ,
264+ }
265+ model .Id = types .StringValue (
266+ strings .Join (idParts , core .Separator ),
267+ )
268+
269+ labels , diags := types .MapValueFrom (ctx , types .StringType , map [string ]interface {}{})
270+ if diags .HasError () {
271+ return fmt .Errorf ("converting labels to StringValue map: %w" , core .DiagsToError (diags ))
272+ }
273+ if networkResp .Labels != nil && len (* networkResp .Labels ) != 0 {
274+ var diags diag.Diagnostics
275+ labels , diags = types .MapValueFrom (ctx , types .StringType , * networkResp .Labels )
276+ if diags .HasError () {
277+ return fmt .Errorf ("converting labels to StringValue map: %w" , core .DiagsToError (diags ))
278+ }
279+ } else if model .Labels .IsNull () {
280+ labels = types .MapNull (types .StringType )
281+ }
282+
283+ // IPv4
284+
285+ if networkResp .Nameservers == nil {
286+ model .Nameservers = types .ListNull (types .StringType )
287+ model .IPv4Nameservers = types .ListNull (types .StringType )
288+ } else {
289+ respNameservers := * networkResp .Nameservers
290+ modelNameservers , err := utils .ListValuetoStringSlice (model .Nameservers )
291+ modelIPv4Nameservers , errIpv4 := utils .ListValuetoStringSlice (model .IPv4Nameservers )
292+ if err != nil {
293+ return fmt .Errorf ("get current network nameservers from model: %w" , err )
294+ }
295+ if errIpv4 != nil {
296+ return fmt .Errorf ("get current IPv4 network nameservers from model: %w" , errIpv4 )
297+ }
298+
299+ reconciledNameservers := utils .ReconcileStringSlices (modelNameservers , respNameservers )
300+ reconciledIPv4Nameservers := utils .ReconcileStringSlices (modelIPv4Nameservers , respNameservers )
301+
302+ nameserversTF , diags := types .ListValueFrom (ctx , types .StringType , reconciledNameservers )
303+ ipv4NameserversTF , ipv4Diags := types .ListValueFrom (ctx , types .StringType , reconciledIPv4Nameservers )
304+ if diags .HasError () {
305+ return fmt .Errorf ("map network nameservers: %w" , core .DiagsToError (diags ))
306+ }
307+ if ipv4Diags .HasError () {
308+ return fmt .Errorf ("map IPv4 network nameservers: %w" , core .DiagsToError (ipv4Diags ))
309+ }
310+
311+ model .Nameservers = nameserversTF
312+ model .IPv4Nameservers = ipv4NameserversTF
313+ }
314+
315+ if networkResp .Prefixes == nil {
316+ model .Prefixes = types .ListNull (types .StringType )
317+ model .IPv4Prefixes = types .ListNull (types .StringType )
318+ } else {
319+ respPrefixes := * networkResp .Prefixes
320+ prefixesTF , diags := types .ListValueFrom (ctx , types .StringType , respPrefixes )
321+ if diags .HasError () {
322+ return fmt .Errorf ("map network prefixes: %w" , core .DiagsToError (diags ))
323+ }
324+
325+ model .Prefixes = prefixesTF
326+ model .IPv4Prefixes = prefixesTF
327+ }
328+
329+ if networkResp .Gateway != nil {
330+ model .IPv4Gateway = types .StringPointerValue (networkResp .GetGateway ())
331+ } else {
332+ model .IPv4Gateway = types .StringNull ()
333+ }
334+
335+ // IPv6
336+
337+ if networkResp .NameserversV6 == nil {
338+ model .IPv6Nameservers = types .ListNull (types .StringType )
339+ } else {
340+ respIPv6Nameservers := * networkResp .NameserversV6
341+ modelIPv6Nameservers , errIpv6 := utils .ListValuetoStringSlice (model .IPv6Nameservers )
342+ if errIpv6 != nil {
343+ return fmt .Errorf ("get current IPv6 network nameservers from model: %w" , errIpv6 )
344+ }
345+
346+ reconciledIPv6Nameservers := utils .ReconcileStringSlices (modelIPv6Nameservers , respIPv6Nameservers )
347+
348+ ipv6NameserversTF , ipv6Diags := types .ListValueFrom (ctx , types .StringType , reconciledIPv6Nameservers )
349+ if ipv6Diags .HasError () {
350+ return fmt .Errorf ("map IPv6 network nameservers: %w" , core .DiagsToError (ipv6Diags ))
351+ }
352+
353+ model .IPv6Nameservers = ipv6NameserversTF
354+ }
355+
356+ if networkResp .PrefixesV6 == nil {
357+ model .IPv6Prefixes = types .ListNull (types .StringType )
358+ } else {
359+ respPrefixesV6 := * networkResp .PrefixesV6
360+ prefixesV6TF , diags := types .ListValueFrom (ctx , types .StringType , respPrefixesV6 )
361+ if diags .HasError () {
362+ return fmt .Errorf ("map network IPv6 prefixes: %w" , core .DiagsToError (diags ))
363+ }
364+
365+ model .IPv6Prefixes = prefixesV6TF
366+ }
367+
368+ if networkResp .Gatewayv6 != nil {
369+ model .IPv6Gateway = types .StringPointerValue (networkResp .GetGatewayv6 ())
370+ } else {
371+ model .IPv6Gateway = types .StringNull ()
372+ }
373+
374+ model .NetworkId = types .StringValue (networkId )
375+ model .Name = types .StringPointerValue (networkResp .Name )
376+ model .PublicIP = types .StringPointerValue (networkResp .PublicIp )
377+ model .Labels = labels
378+ model .Routed = types .BoolPointerValue (networkResp .Routed )
379+
380+ return nil
381+ }
0 commit comments