// Copyright (c) EZSCALE. // SPDX-License-Identifier: MPL-2.0 package provider import ( "context" "encoding/json" "fmt" "terraform-provider-virtfusion/internal/client" "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/datasource/schema" "github.com/hashicorp/terraform-plugin-framework/types" ) var _ datasource.DataSource = &ServersDataSource{} var _ datasource.DataSourceWithConfigure = &ServersDataSource{} // NewServersDataSource returns a new data source for listing all servers. func NewServersDataSource() datasource.DataSource { return &ServersDataSource{} } // ServersDataSource defines the data source implementation. type ServersDataSource struct { client *client.Client } // ServersDataSourceModel describes the data source data model. type ServersDataSourceModel struct { Results types.Int64 `tfsdk:"results"` Servers types.List `tfsdk:"servers"` } func (d *ServersDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { resp.TypeName = req.ProviderTypeName + "_servers" } func (d *ServersDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) { resp.Schema = schema.Schema{ MarkdownDescription: "Use this data source to list all VirtFusion servers.", Attributes: map[string]schema.Attribute{ "results": resultsSchemaAttribute(), "servers": schema.ListNestedAttribute{ MarkdownDescription: "The list of servers.", Computed: true, NestedObject: schema.NestedAttributeObject{ Attributes: serverDataSourceSchemaAttributes(), }, }, }, } } func (d *ServersDataSource) Configure(_ context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { if req.ProviderData == nil { return } c, ok := req.ProviderData.(*client.Client) if !ok { resp.Diagnostics.AddError( "Unexpected Data Source Configure Type", fmt.Sprintf("Expected *client.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData), ) return } d.client = c } func (d *ServersDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { var data ServersDataSourceModel resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) if resp.Diagnostics.HasError() { return } result, err := d.client.GetAllPages(ctx, fmt.Sprintf("/servers?%s", resultsQueryParam(data.Results))) if err != nil { resp.Diagnostics.AddError("Error Reading Servers", err.Error()) return } var listResp client.ServerListResponse if err := json.Unmarshal(result, &listResp); err != nil { resp.Diagnostics.AddError("Error Parsing Servers Response", err.Error()) return } serverObjects := make([]attr.Value, len(listResp.Data)) for i, s := range listResp.Data { obj, diags := types.ObjectValue( serverDataSourceAttrTypes(), serverDataToAttrValues(s), ) resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { return } serverObjects[i] = obj } serversList, diags := types.ListValue(types.ObjectType{AttrTypes: serverDataSourceAttrTypes()}, serverObjects) resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { return } data.Servers = serversList resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) } // serverDataSourceSchemaAttributes returns the schema attributes for a server object // used in list data sources. func serverDataSourceSchemaAttributes() map[string]schema.Attribute { return map[string]schema.Attribute{ "id": schema.Int64Attribute{ MarkdownDescription: "The server ID.", Computed: true, }, "uuid": schema.StringAttribute{ MarkdownDescription: "The server UUID.", Computed: true, }, "name": schema.StringAttribute{ MarkdownDescription: "The server display name.", Computed: true, }, "hostname": schema.StringAttribute{ MarkdownDescription: "The server hostname.", Computed: true, }, "owner_id": schema.Int64Attribute{ MarkdownDescription: "The owner (user) ID who owns the server.", Computed: true, }, "hypervisor_id": schema.Int64Attribute{ MarkdownDescription: "The hypervisor ID where the server is hosted.", Computed: true, }, "suspended": schema.BoolAttribute{ MarkdownDescription: "Whether the server is suspended.", Computed: true, }, } } // serverDataSourceAttrTypes returns the attribute types for a server object. func serverDataSourceAttrTypes() map[string]attr.Type { return map[string]attr.Type{ "id": types.Int64Type, "uuid": types.StringType, "name": types.StringType, "hostname": types.StringType, "owner_id": types.Int64Type, "hypervisor_id": types.Int64Type, "suspended": types.BoolType, } } // serverDataToAttrValues converts a client.ServerData to a map of attribute values. func serverDataToAttrValues(s client.ServerData) map[string]attr.Value { return map[string]attr.Value{ "id": types.Int64Value(s.ID), "uuid": types.StringValue(s.UUID), "name": types.StringValue(s.Name), "hostname": types.StringValue(s.Hostname), "owner_id": types.Int64Value(s.OwnerID), "hypervisor_id": types.Int64Value(s.HypervisorID), "suspended": types.BoolValue(s.Suspended), } }