From 9fee8c1e2e24a61cd8e75c3744227f5d44662c0f Mon Sep 17 00:00:00 2001 From: Serge Date: Sun, 24 Mar 2024 02:17:09 +0200 Subject: [PATCH] feat(vm): add proxmox_virtual_environment_node datasource (#1151) * feat(vm): add proxmox_virtual_environment_node datasource It helps to get CPU model, number of cores and sockets. Signed-off-by: Serge Logvinov * fix node_name ref * add acceptance test Signed-off-by: Pavel Boldyrev <627562+bpg@users.noreply.github.com> --------- Signed-off-by: Serge Logvinov Signed-off-by: Pavel Boldyrev <627562+bpg@users.noreply.github.com> Co-authored-by: Pavel Boldyrev <627562+bpg@users.noreply.github.com> --- docs/data-sources/virtual_environment_node.md | 30 ++++ .../data_source_virtual_environment_node.tf | 35 +++++ fwprovider/tests/datasource_node_test.go | 52 +++++++ proxmox/nodes/nodes.go | 16 ++ proxmox/nodes/nodes_types.go | 20 +++ proxmoxtf/datasource/node.go | 145 ++++++++++++++++++ proxmoxtf/provider/datasources.go | 1 + 7 files changed, 299 insertions(+) create mode 100644 docs/data-sources/virtual_environment_node.md create mode 100644 example/data_source_virtual_environment_node.tf create mode 100644 fwprovider/tests/datasource_node_test.go create mode 100644 proxmoxtf/datasource/node.go diff --git a/docs/data-sources/virtual_environment_node.md b/docs/data-sources/virtual_environment_node.md new file mode 100644 index 00000000..14485076 --- /dev/null +++ b/docs/data-sources/virtual_environment_node.md @@ -0,0 +1,30 @@ +--- +layout: page +title: proxmox_virtual_environment_node +parent: Data Sources +subcategory: Virtual Environment +--- + +# Data Source: proxmox_virtual_environment_node + +Retrieves information about node. + +## Example Usage + +```terraform +data "proxmox_virtual_environment_node" "node" {} +``` + +## Argument Reference + +- `node_name` - (Required) The node name. + +## Attribute Reference + +- `cpu_count` - The CPU count on the node. +- `cpu_sockets` - The CPU utilization on the node. +- `cpu_model` - The CPU model on the node. +- `memory_available` - The memory available on the node. +- `memory_used` - The memory used on the node. +- `memory_total` - The total memory on the node. +- `uptime` - The uptime in seconds on the node. diff --git a/example/data_source_virtual_environment_node.tf b/example/data_source_virtual_environment_node.tf new file mode 100644 index 00000000..2f12477b --- /dev/null +++ b/example/data_source_virtual_environment_node.tf @@ -0,0 +1,35 @@ +data "proxmox_virtual_environment_node" "example" { + node_name = data.proxmox_virtual_environment_nodes.example.names[0] +} + +output "data_proxmox_virtual_environment_node_example_cpu_count" { + value = data.proxmox_virtual_environment_node.example.cpu_count +} + +output "data_proxmox_virtual_environment_node_example_cpu_sockets" { + value = data.proxmox_virtual_environment_node.example.cpu_sockets +} + +output "data_proxmox_virtual_environment_node_example_cpu_model" { + value = data.proxmox_virtual_environment_node.example.cpu_model +} + +output "data_proxmox_virtual_environment_node_example_memory_available" { + value = data.proxmox_virtual_environment_node.example.memory_available +} + +output "data_proxmox_virtual_environment_node_example_memory_used" { + value = data.proxmox_virtual_environment_node.example.memory_used +} + +output "data_proxmox_virtual_environment_node_example_memory_total" { + value = data.proxmox_virtual_environment_node.example.memory_total +} + +output "data_proxmox_virtual_environment_node_example_node_name" { + value = data.proxmox_virtual_environment_node.example.node_name +} + +output "data_proxmox_virtual_environment_node_example_uptime" { + value = data.proxmox_virtual_environment_node.example.uptime +} diff --git a/fwprovider/tests/datasource_node_test.go b/fwprovider/tests/datasource_node_test.go new file mode 100644 index 00000000..75264928 --- /dev/null +++ b/fwprovider/tests/datasource_node_test.go @@ -0,0 +1,52 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" +) + +func TestAccDatasourceNode(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + steps []resource.TestStep + }{ + {"read node attributes", []resource.TestStep{{ + Config: fmt.Sprintf(`data "proxmox_virtual_environment_node" "test" { node_name = "%s" }`, accTestNodeName), + Check: resource.ComposeTestCheckFunc( + testResourceAttributesSet("data.proxmox_virtual_environment_node.test", []string{ + "cpu_count", + "cpu_sockets", + "cpu_model", + "memory_available", + "memory_used", + "memory_total", + "uptime", + }), + ), + }}}, + } + + accProviders := testAccMuxProviders(context.Background(), t) + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + resource.Test(t, resource.TestCase{ + ProtoV6ProviderFactories: accProviders, + Steps: tt.steps, + }) + }) + } +} diff --git a/proxmox/nodes/nodes.go b/proxmox/nodes/nodes.go index d11519ee..d848a457 100644 --- a/proxmox/nodes/nodes.go +++ b/proxmox/nodes/nodes.go @@ -60,3 +60,19 @@ func (c *Client) UpdateTime(ctx context.Context, d *UpdateTimeRequestBody) error return nil } + +// GetInfo retrieves the information of the node. +func (c *Client) GetInfo(ctx context.Context) (*GetInfoResponseData, error) { + resBody := &GetInfoResponseBody{} + + err := c.DoRequest(ctx, http.MethodGet, c.ExpandPath("status"), nil, resBody) + if err != nil { + return nil, fmt.Errorf("failed to get status of the node \"%s\": %w", c.NodeName, err) + } + + if resBody.Data == nil { + return nil, api.ErrNoDataObjectInResponse + } + + return resBody.Data, nil +} diff --git a/proxmox/nodes/nodes_types.go b/proxmox/nodes/nodes_types.go index b6671f75..7343d481 100644 --- a/proxmox/nodes/nodes_types.go +++ b/proxmox/nodes/nodes_types.go @@ -34,6 +34,26 @@ type GetTimeResponseData struct { UTCTime types.CustomTimestamp `json:"time"` } +// GetInfoResponseBody contains the body from a node info get response. +type GetInfoResponseBody struct { + Data *GetInfoResponseData `json:"data,omitempty"` +} + +// GetInfoResponseData contains the data from a node info response. +type GetInfoResponseData struct { + CPUInfo struct { + CPUCores *int `json:"cores,omitempty"` + CPUSockets *int `json:"sockets,omitempty"` + CPUModel *string `json:"model"` + } `json:"cpuinfo"` + MemoryInfo struct { + Free *int `json:"free,omitempty"` + Used *int `json:"used,omitempty"` + Total *int `json:"total,omitempty"` + } `json:"memory"` + Uptime *int `json:"uptime"` +} + // ListResponseBody contains the body from a node list response. type ListResponseBody struct { Data []*ListResponseData `json:"data,omitempty"` diff --git a/proxmoxtf/datasource/node.go b/proxmoxtf/datasource/node.go new file mode 100644 index 00000000..e88d2250 --- /dev/null +++ b/proxmoxtf/datasource/node.go @@ -0,0 +1,145 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +package datasource + +import ( + "context" + + "github.com/bpg/terraform-provider-proxmox/proxmoxtf" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const ( + mkDataSourceVirtualEnvironmentNodeCPUCores = "cpu_count" + mkDataSourceVirtualEnvironmentNodeCPUSockets = "cpu_sockets" + mkDataSourceVirtualEnvironmentNodeCPUModel = "cpu_model" + mkDataSourceVirtualEnvironmentNodeMemoryAvailable = "memory_available" + mkDataSourceVirtualEnvironmentNodeMemoryUsed = "memory_used" + mkDataSourceVirtualEnvironmentNodeMemoryTotal = "memory_total" + mkDataSourceVirtualEnvironmentNodeUptime = "uptime" + mkDataSourceVirtualEnvironmentNodeName = "node_name" +) + +// Node returns a resource for the Proxmox node. +func Node() *schema.Resource { + return &schema.Resource{ + Schema: map[string]*schema.Schema{ + mkDataSourceVirtualEnvironmentNodeCPUCores: { + Type: schema.TypeInt, + Description: "The CPU count on the node", + Computed: true, + }, + mkDataSourceVirtualEnvironmentNodeCPUSockets: { + Type: schema.TypeInt, + Description: "The CPU sockets on the node", + Computed: true, + }, + mkDataSourceVirtualEnvironmentNodeCPUModel: { + Type: schema.TypeString, + Description: "The CPU model on the node", + Computed: true, + }, + mkDataSourceVirtualEnvironmentNodeMemoryAvailable: { + Type: schema.TypeInt, + Description: "The available memory in bytes on the node", + Computed: true, + }, + mkDataSourceVirtualEnvironmentNodeMemoryUsed: { + Type: schema.TypeInt, + Description: "The used memory in bytes on the node", + Computed: true, + }, + mkDataSourceVirtualEnvironmentNodeMemoryTotal: { + Type: schema.TypeInt, + Description: "The total memory in bytes on the node", + Computed: true, + }, + mkDataSourceVirtualEnvironmentNodeUptime: { + Type: schema.TypeInt, + Description: "The uptime in seconds on the node", + Computed: true, + }, + mkDataSourceVirtualEnvironmentNodeName: { + Type: schema.TypeString, + Description: "The node name", + Required: true, + }, + }, + ReadContext: nodeRead, + } +} + +func nodeRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + var diags diag.Diagnostics + + config := m.(proxmoxtf.ProviderConfiguration) + + api, err := config.GetClient() + if err != nil { + return diag.FromErr(err) + } + + nodeID := d.Get(mkDataSourceVirtualEnvironmentNodeName).(string) + + node, err := api.Node(nodeID).GetInfo(ctx) + if err != nil { + return diag.FromErr(err) + } + + d.SetId(nodeID) + + if node.CPUInfo.CPUCores != nil { + err = d.Set(mkDataSourceVirtualEnvironmentNodeCPUCores, *node.CPUInfo.CPUCores) + } else { + err = d.Set(mkDataSourceVirtualEnvironmentNodeCPUCores, 1) + } + + diags = append(diags, diag.FromErr(err)...) + + if node.CPUInfo.CPUSockets != nil { + err = d.Set(mkDataSourceVirtualEnvironmentNodeCPUSockets, *node.CPUInfo.CPUSockets) + } else { + err = d.Set(mkDataSourceVirtualEnvironmentNodeCPUSockets, 1) + } + + diags = append(diags, diag.FromErr(err)...) + + if node.CPUInfo.CPUModel != nil { + err = d.Set(mkDataSourceVirtualEnvironmentNodeCPUModel, *node.CPUInfo.CPUModel) + } else { + err = d.Set(mkDataSourceVirtualEnvironmentNodeCPUModel, "") + } + + diags = append(diags, diag.FromErr(err)...) + + if node.MemoryInfo.Total != nil { + err = d.Set(mkDataSourceVirtualEnvironmentNodeMemoryAvailable, node.MemoryInfo.Free) + diags = append(diags, diag.FromErr(err)...) + err = d.Set(mkDataSourceVirtualEnvironmentNodeMemoryUsed, node.MemoryInfo.Used) + diags = append(diags, diag.FromErr(err)...) + err = d.Set(mkDataSourceVirtualEnvironmentNodeMemoryTotal, node.MemoryInfo.Total) + diags = append(diags, diag.FromErr(err)...) + } else { + err = d.Set(mkDataSourceVirtualEnvironmentNodeMemoryAvailable, 0) + diags = append(diags, diag.FromErr(err)...) + err = d.Set(mkDataSourceVirtualEnvironmentNodeMemoryUsed, 0) + diags = append(diags, diag.FromErr(err)...) + err = d.Set(mkDataSourceVirtualEnvironmentNodeMemoryTotal, 0) + diags = append(diags, diag.FromErr(err)...) + } + + if node.Uptime != nil { + err = d.Set(mkDataSourceVirtualEnvironmentNodeUptime, *node.Uptime) + } else { + err = d.Set(mkDataSourceVirtualEnvironmentNodeUptime, 0) + } + + diags = append(diags, diag.FromErr(err)...) + + return diags +} diff --git a/proxmoxtf/provider/datasources.go b/proxmoxtf/provider/datasources.go index d1ab5c7e..57bfa2d1 100644 --- a/proxmoxtf/provider/datasources.go +++ b/proxmoxtf/provider/datasources.go @@ -19,6 +19,7 @@ func createDatasourceMap() map[string]*schema.Resource { "proxmox_virtual_environment_group": datasource.Group(), "proxmox_virtual_environment_groups": datasource.Groups(), "proxmox_virtual_environment_hosts": datasource.Hosts(), + "proxmox_virtual_environment_node": datasource.Node(), "proxmox_virtual_environment_nodes": datasource.Nodes(), "proxmox_virtual_environment_pool": datasource.Pool(), "proxmox_virtual_environment_pools": datasource.Pools(),