mirror of
https://github.com/bpg/terraform-provider-proxmox.git
synced 2025-06-30 02:31:10 +00:00
feat(cluster): add proxmox_virtual_environment_metrics_server
resource (#1719)
Signed-off-by: rafsaf <rafal.safin@rafsaf.pl>
This commit is contained in:
parent
4166f66731
commit
d1cc2144f8
@ -54,6 +54,7 @@ The following assumptions are made about the test environment:
|
|||||||
- It has one node named `pve`
|
- It has one node named `pve`
|
||||||
- The node has local storages named `local` and `local-lvm`
|
- The node has local storages named `local` and `local-lvm`
|
||||||
- The "Snippets" content type is enabled in the `local` storage
|
- The "Snippets" content type is enabled in the `local` storage
|
||||||
|
- Default Linux Bridge "vmbr0" is VLAN aware (datacenter -> pve -> network -> edit & apply)
|
||||||
|
|
||||||
Create `example/terraform.tfvars` with the following variables:
|
Create `example/terraform.tfvars` with the following variables:
|
||||||
|
|
||||||
|
42
docs/data-sources/virtual_environment_metrics_server.md
Normal file
42
docs/data-sources/virtual_environment_metrics_server.md
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
---
|
||||||
|
layout: page
|
||||||
|
title: proxmox_virtual_environment_metrics_server
|
||||||
|
parent: Data Sources
|
||||||
|
subcategory: Virtual Environment
|
||||||
|
description: |-
|
||||||
|
Retrieves information about a specific PVE metric server.
|
||||||
|
---
|
||||||
|
|
||||||
|
# Data Source: proxmox_virtual_environment_metrics_server
|
||||||
|
|
||||||
|
Retrieves information about a specific PVE metric server.
|
||||||
|
|
||||||
|
## Example Usage
|
||||||
|
|
||||||
|
```terraform
|
||||||
|
data "proxmox_virtual_environment_metrics_server" "example" {
|
||||||
|
name = "example_influxdb"
|
||||||
|
}
|
||||||
|
|
||||||
|
output "data_proxmox_virtual_environment_metrics_server" {
|
||||||
|
value = {
|
||||||
|
server = data.proxmox_virtual_environment_metrics_server.example.server
|
||||||
|
port = data.proxmox_virtual_environment_metrics_server.example.port
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
<!-- schema generated by tfplugindocs -->
|
||||||
|
## Schema
|
||||||
|
|
||||||
|
### Required
|
||||||
|
|
||||||
|
- `name` (String) Unique name that will be ID of this metric server in PVE.
|
||||||
|
|
||||||
|
### Read-Only
|
||||||
|
|
||||||
|
- `disable` (Boolean) Indicates if the metric server is disabled.
|
||||||
|
- `id` (String) The unique identifier of this resource.
|
||||||
|
- `port` (Number) Server network port.
|
||||||
|
- `server` (String) Server dns name or IP address.
|
||||||
|
- `type` (String) Plugin type. Either `graphite` or `influxdb`.
|
68
docs/resources/virtual_environment_metrics_server.md
Normal file
68
docs/resources/virtual_environment_metrics_server.md
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
---
|
||||||
|
layout: page
|
||||||
|
title: proxmox_virtual_environment_metrics_server
|
||||||
|
parent: Resources
|
||||||
|
subcategory: Virtual Environment
|
||||||
|
description: |-
|
||||||
|
Manages PVE metrics server.
|
||||||
|
---
|
||||||
|
|
||||||
|
# Resource: proxmox_virtual_environment_metrics_server
|
||||||
|
|
||||||
|
Manages PVE metrics server.
|
||||||
|
|
||||||
|
## Example Usage
|
||||||
|
|
||||||
|
```terraform
|
||||||
|
resource "proxmox_virtual_environment_metrics_server" "influxdb_server" {
|
||||||
|
name = "example_influxdb_server"
|
||||||
|
server = "192.168.3.2"
|
||||||
|
port = 8089
|
||||||
|
type = "influxdb"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "proxmox_virtual_environment_metrics_server" "graphite_server" {
|
||||||
|
name = "example_graphite_server"
|
||||||
|
server = "192.168.4.2"
|
||||||
|
port = 2003
|
||||||
|
type = "graphite"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
<!-- schema generated by tfplugindocs -->
|
||||||
|
## Schema
|
||||||
|
|
||||||
|
### Required
|
||||||
|
|
||||||
|
- `name` (String) Unique name that will be ID of this metric server in PVE.
|
||||||
|
- `port` (Number) Server network port.
|
||||||
|
- `server` (String) Server dns name or IP address.
|
||||||
|
- `type` (String) Plugin type. Choice is between `graphite` | `influxdb`.
|
||||||
|
|
||||||
|
### Optional
|
||||||
|
|
||||||
|
- `disable` (Boolean) Set this to `true` to disable this metric server.
|
||||||
|
- `graphite_path` (String) Root graphite path (ex: `proxmox.mycluster.mykey`).
|
||||||
|
- `graphite_proto` (String) Protocol to send graphite data. Choice is between `udp` | `tcp`. If not set, PVE default is `udp`.
|
||||||
|
- `influx_api_path_prefix` (String) An API path prefix inserted between `<host>:<port>/` and `/api2/`. Can be useful if the InfluxDB service runs behind a reverse proxy.
|
||||||
|
- `influx_bucket` (String) The InfluxDB bucket/db. Only necessary when using the http v2 api.
|
||||||
|
- `influx_db_proto` (String) Protocol for InfluxDB. Choice is between `udp` | `http` | `https`. If not set, PVE default is `udp`.
|
||||||
|
- `influx_max_body_size` (Number) InfluxDB max-body-size in bytes. Requests are batched up to this size. If not set, PVE default is `25000000`.
|
||||||
|
- `influx_organization` (String) The InfluxDB organization. Only necessary when using the http v2 api. Has no meaning when using v2 compatibility api.
|
||||||
|
- `influx_token` (String, Sensitive) The InfluxDB access token. Only necessary when using the http v2 api. If the v2 compatibility api is used, use `user:password` instead.
|
||||||
|
- `influx_verify` (Boolean) Set to `false` to disable certificate verification for https endpoints.
|
||||||
|
- `mtu` (Number) MTU (maximum transmission unit) for metrics transmission over UDP. If not set, PVE default is `1500` (allowed `512` - `65536`).
|
||||||
|
- `timeout` (Number) TCP socket timeout in seconds. If not set, PVE default is `1`.
|
||||||
|
|
||||||
|
### Read-Only
|
||||||
|
|
||||||
|
- `id` (String) The unique identifier of this resource.
|
||||||
|
|
||||||
|
## Import
|
||||||
|
|
||||||
|
Import is supported using the following syntax:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
#!/usr/bin/env sh
|
||||||
|
terraform import proxmox_virtual_environment_metrics_server.example example
|
||||||
|
```
|
@ -0,0 +1,3 @@
|
|||||||
|
data "proxmox_virtual_environment_metrics_server" "example" {
|
||||||
|
name = proxmox_virtual_environment_metrics_server.influxdb_server.name
|
||||||
|
}
|
24
example/resource_virtual_environment_metrics_server.tf
Normal file
24
example/resource_virtual_environment_metrics_server.tf
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
resource "proxmox_virtual_environment_metrics_server" "influxdb_server" {
|
||||||
|
name = "example_influxdb_server"
|
||||||
|
server = "192.168.3.2"
|
||||||
|
port = 18089
|
||||||
|
type = "influxdb"
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "proxmox_virtual_environment_metrics_server" "graphite_server" {
|
||||||
|
name = "example_graphite_server"
|
||||||
|
server = "192.168.4.2"
|
||||||
|
port = 20033
|
||||||
|
type = "graphite"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "proxmox_virtual_environment_metrics_server" "graphite_server2" {
|
||||||
|
name = "example_graphite_server2"
|
||||||
|
server = "192.168.4.3"
|
||||||
|
port = 20033
|
||||||
|
type = "graphite"
|
||||||
|
mtu = 60000
|
||||||
|
timeout = 5
|
||||||
|
graphite_proto = "udp"
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
data "proxmox_virtual_environment_metrics_server" "example" {
|
||||||
|
name = "example_influxdb"
|
||||||
|
}
|
||||||
|
|
||||||
|
output "data_proxmox_virtual_environment_metrics_server" {
|
||||||
|
value = {
|
||||||
|
server = data.proxmox_virtual_environment_metrics_server.example.server
|
||||||
|
port = data.proxmox_virtual_environment_metrics_server.example.port
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,2 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
terraform import proxmox_virtual_environment_metrics_server.example example
|
@ -0,0 +1,13 @@
|
|||||||
|
resource "proxmox_virtual_environment_metrics_server" "influxdb_server" {
|
||||||
|
name = "example_influxdb_server"
|
||||||
|
server = "192.168.3.2"
|
||||||
|
port = 8089
|
||||||
|
type = "influxdb"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "proxmox_virtual_environment_metrics_server" "graphite_server" {
|
||||||
|
name = "example_graphite_server"
|
||||||
|
server = "192.168.4.2"
|
||||||
|
port = 2003
|
||||||
|
type = "graphite"
|
||||||
|
}
|
130
fwprovider/cluster/metrics/datasource_metrics_server.go
Normal file
130
fwprovider/cluster/metrics/datasource_metrics_server.go
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
/*
|
||||||
|
* 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 metrics
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/bpg/terraform-provider-proxmox/fwprovider/attribute"
|
||||||
|
"github.com/bpg/terraform-provider-proxmox/fwprovider/config"
|
||||||
|
"github.com/bpg/terraform-provider-proxmox/proxmox/cluster/metrics"
|
||||||
|
"github.com/hashicorp/terraform-plugin-framework/datasource"
|
||||||
|
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Ensure the implementation satisfies the expected interfaces.
|
||||||
|
var (
|
||||||
|
_ datasource.DataSource = &metricsServerDatasource{}
|
||||||
|
_ datasource.DataSourceWithConfigure = &metricsServerDatasource{}
|
||||||
|
)
|
||||||
|
|
||||||
|
type metricsServerDatasource struct {
|
||||||
|
client *metrics.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewMetricsServerDatasource creates new metrics server data source.
|
||||||
|
func NewMetricsServerDatasource() datasource.DataSource {
|
||||||
|
return &metricsServerDatasource{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *metricsServerDatasource) Metadata(
|
||||||
|
_ context.Context,
|
||||||
|
req datasource.MetadataRequest,
|
||||||
|
resp *datasource.MetadataResponse,
|
||||||
|
) {
|
||||||
|
resp.TypeName = req.ProviderTypeName + "_metrics_server"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *metricsServerDatasource) Configure(
|
||||||
|
_ context.Context,
|
||||||
|
req datasource.ConfigureRequest,
|
||||||
|
resp *datasource.ConfigureResponse,
|
||||||
|
) {
|
||||||
|
if req.ProviderData == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg, ok := req.ProviderData.(config.DataSource)
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
resp.Diagnostics.AddError(
|
||||||
|
"Unexpected Resource Configure Type",
|
||||||
|
fmt.Sprintf("Expected *proxmox.Client, got: %T", req.ProviderData),
|
||||||
|
)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
r.client = cfg.Client.Cluster().Metrics()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *metricsServerDatasource) Schema(
|
||||||
|
_ context.Context,
|
||||||
|
_ datasource.SchemaRequest,
|
||||||
|
resp *datasource.SchemaResponse,
|
||||||
|
) {
|
||||||
|
resp.Schema = schema.Schema{
|
||||||
|
Description: "Retrieves information about a specific PVE metric server.",
|
||||||
|
Attributes: map[string]schema.Attribute{
|
||||||
|
"id": attribute.ID(),
|
||||||
|
"name": schema.StringAttribute{
|
||||||
|
Description: "Unique name that will be ID of this metric server in PVE.",
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
"disable": schema.BoolAttribute{
|
||||||
|
Description: "Indicates if the metric server is disabled.",
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"port": schema.Int64Attribute{
|
||||||
|
Description: "Server network port.",
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"server": schema.StringAttribute{
|
||||||
|
Description: "Server dns name or IP address.",
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"type": schema.StringAttribute{
|
||||||
|
Description: "Plugin type. Either `graphite` or `influxdb`.",
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *metricsServerDatasource) Read(
|
||||||
|
ctx context.Context,
|
||||||
|
req datasource.ReadRequest,
|
||||||
|
resp *datasource.ReadResponse,
|
||||||
|
) {
|
||||||
|
var state metricsServerDatasourceModel
|
||||||
|
|
||||||
|
resp.Diagnostics.Append(req.Config.Get(ctx, &state)...)
|
||||||
|
|
||||||
|
if resp.Diagnostics.HasError() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
state.ID = state.Name
|
||||||
|
|
||||||
|
data, err := r.client.GetServer(ctx, state.ID.ValueString())
|
||||||
|
if err != nil {
|
||||||
|
resp.Diagnostics.AddError(
|
||||||
|
"Unable to Refresh Resource",
|
||||||
|
"An unexpected error occurred while attempting to refresh datasource state. "+
|
||||||
|
"Please retry the operation or report this issue to the provider developers.\n\n"+
|
||||||
|
"Error: "+err.Error(),
|
||||||
|
)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
readModel := &metricsServerDatasourceModel{}
|
||||||
|
readModel.importFromAPI(state.ID.ValueString(), data)
|
||||||
|
|
||||||
|
resp.Diagnostics.Append(resp.State.Set(ctx, readModel)...)
|
||||||
|
}
|
133
fwprovider/cluster/metrics/metrics_server_model.go
Normal file
133
fwprovider/cluster/metrics/metrics_server_model.go
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
/*
|
||||||
|
* 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 metrics
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/bpg/terraform-provider-proxmox/proxmox/cluster/metrics"
|
||||||
|
"github.com/hashicorp/terraform-plugin-framework/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
type metricsServerModel struct {
|
||||||
|
ID types.String `tfsdk:"id"`
|
||||||
|
Name types.String `tfsdk:"name"`
|
||||||
|
Disable types.Bool `tfsdk:"disable"`
|
||||||
|
MTU types.Int64 `tfsdk:"mtu"`
|
||||||
|
Port types.Int64 `tfsdk:"port"`
|
||||||
|
Server types.String `tfsdk:"server"`
|
||||||
|
Timeout types.Int64 `tfsdk:"timeout"`
|
||||||
|
Type types.String `tfsdk:"type"`
|
||||||
|
InfluxAPIPathPrefix types.String `tfsdk:"influx_api_path_prefix"`
|
||||||
|
InfluxBucket types.String `tfsdk:"influx_bucket"`
|
||||||
|
InfluxDBProto types.String `tfsdk:"influx_db_proto"`
|
||||||
|
InfluxMaxBodySize types.Int64 `tfsdk:"influx_max_body_size"`
|
||||||
|
InfluxOrganization types.String `tfsdk:"influx_organization"`
|
||||||
|
InfluxToken types.String `tfsdk:"influx_token"`
|
||||||
|
InfluxVerify types.Bool `tfsdk:"influx_verify"`
|
||||||
|
GraphitePath types.String `tfsdk:"graphite_path"`
|
||||||
|
GraphiteProto types.String `tfsdk:"graphite_proto"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func boolToInt64Ptr(boolPtr *bool) *int64 {
|
||||||
|
if boolPtr != nil {
|
||||||
|
var result int64
|
||||||
|
|
||||||
|
if *boolPtr {
|
||||||
|
result = int64(1)
|
||||||
|
} else {
|
||||||
|
result = int64(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &result
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func int64ToBoolPtr(int64ptr *int64) *bool {
|
||||||
|
if int64ptr != nil {
|
||||||
|
var result bool
|
||||||
|
|
||||||
|
if *int64ptr == 0 {
|
||||||
|
result = false
|
||||||
|
} else {
|
||||||
|
result = true
|
||||||
|
}
|
||||||
|
|
||||||
|
return &result
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// importFromAPI takes data from metrics server PVE API response and set fields based on it.
|
||||||
|
// Note: API response does not contain name so it must be passed directly.
|
||||||
|
func (m *metricsServerModel) importFromAPI(name string, data *metrics.ServerData) {
|
||||||
|
m.ID = types.StringValue(name)
|
||||||
|
m.Name = types.StringValue(name)
|
||||||
|
|
||||||
|
m.Disable = types.BoolPointerValue(int64ToBoolPtr(data.Disable))
|
||||||
|
m.MTU = types.Int64PointerValue(data.MTU)
|
||||||
|
m.Port = types.Int64Value(data.Port)
|
||||||
|
m.Server = types.StringValue(data.Server)
|
||||||
|
m.Timeout = types.Int64PointerValue(data.Timeout)
|
||||||
|
m.Type = types.StringPointerValue(data.Type)
|
||||||
|
m.InfluxAPIPathPrefix = types.StringPointerValue(data.APIPathPrefix)
|
||||||
|
m.InfluxBucket = types.StringPointerValue(data.Bucket)
|
||||||
|
m.InfluxDBProto = types.StringPointerValue(data.InfluxDBProto)
|
||||||
|
m.InfluxMaxBodySize = types.Int64PointerValue(data.MaxBodySize)
|
||||||
|
m.InfluxOrganization = types.StringPointerValue(data.Organization)
|
||||||
|
m.InfluxToken = types.StringPointerValue(data.Token)
|
||||||
|
m.InfluxVerify = types.BoolPointerValue(int64ToBoolPtr(data.Verify))
|
||||||
|
m.GraphitePath = types.StringPointerValue(data.Path)
|
||||||
|
m.GraphiteProto = types.StringPointerValue(data.Proto)
|
||||||
|
}
|
||||||
|
|
||||||
|
// toAPIRequestBody creates metrics server request data for PUT and POST requests.
|
||||||
|
func (m *metricsServerModel) toAPIRequestBody() *metrics.ServerRequestData {
|
||||||
|
data := &metrics.ServerRequestData{}
|
||||||
|
|
||||||
|
data.ID = m.Name.ValueString()
|
||||||
|
|
||||||
|
data.Disable = boolToInt64Ptr(m.Disable.ValueBoolPointer())
|
||||||
|
data.MTU = m.MTU.ValueInt64Pointer()
|
||||||
|
data.Port = m.Port.ValueInt64()
|
||||||
|
data.Server = m.Server.ValueString()
|
||||||
|
data.Timeout = m.Timeout.ValueInt64Pointer()
|
||||||
|
data.Type = m.Type.ValueStringPointer()
|
||||||
|
data.APIPathPrefix = m.InfluxAPIPathPrefix.ValueStringPointer()
|
||||||
|
data.Bucket = m.InfluxBucket.ValueStringPointer()
|
||||||
|
data.InfluxDBProto = m.InfluxDBProto.ValueStringPointer()
|
||||||
|
data.MaxBodySize = m.InfluxMaxBodySize.ValueInt64Pointer()
|
||||||
|
data.Organization = m.InfluxOrganization.ValueStringPointer()
|
||||||
|
data.Token = m.InfluxToken.ValueStringPointer()
|
||||||
|
data.Verify = boolToInt64Ptr(m.InfluxVerify.ValueBoolPointer())
|
||||||
|
data.Path = m.GraphitePath.ValueStringPointer()
|
||||||
|
data.Proto = m.GraphiteProto.ValueStringPointer()
|
||||||
|
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
|
type metricsServerDatasourceModel struct {
|
||||||
|
ID types.String `tfsdk:"id"`
|
||||||
|
Name types.String `tfsdk:"name"`
|
||||||
|
Disable types.Bool `tfsdk:"disable"`
|
||||||
|
Port types.Int64 `tfsdk:"port"`
|
||||||
|
Server types.String `tfsdk:"server"`
|
||||||
|
Type types.String `tfsdk:"type"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// importFromAPI takes data from metrics server PVE API response and set fields based on it.
|
||||||
|
// Note: API response does not contain name so it must be passed directly.
|
||||||
|
func (m *metricsServerDatasourceModel) importFromAPI(name string, data *metrics.ServerData) {
|
||||||
|
m.ID = types.StringValue(name)
|
||||||
|
m.Name = types.StringValue(name)
|
||||||
|
|
||||||
|
m.Disable = types.BoolPointerValue(int64ToBoolPtr(data.Disable))
|
||||||
|
m.Port = types.Int64Value(data.Port)
|
||||||
|
m.Server = types.StringValue(data.Server)
|
||||||
|
m.Type = types.StringPointerValue(data.Type)
|
||||||
|
}
|
366
fwprovider/cluster/metrics/resource_metrics_server.go
Normal file
366
fwprovider/cluster/metrics/resource_metrics_server.go
Normal file
@ -0,0 +1,366 @@
|
|||||||
|
/*
|
||||||
|
* 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 metrics
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/bpg/terraform-provider-proxmox/fwprovider/attribute"
|
||||||
|
"github.com/bpg/terraform-provider-proxmox/fwprovider/config"
|
||||||
|
"github.com/bpg/terraform-provider-proxmox/proxmox/api"
|
||||||
|
"github.com/bpg/terraform-provider-proxmox/proxmox/cluster/metrics"
|
||||||
|
"github.com/hashicorp/terraform-plugin-framework-validators/int64validator"
|
||||||
|
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
|
||||||
|
"github.com/hashicorp/terraform-plugin-framework/attr"
|
||||||
|
"github.com/hashicorp/terraform-plugin-framework/resource"
|
||||||
|
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
|
||||||
|
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
|
||||||
|
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
|
||||||
|
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
_ resource.Resource = &metricsServerResource{}
|
||||||
|
_ resource.ResourceWithConfigure = &metricsServerResource{}
|
||||||
|
_ resource.ResourceWithImportState = &metricsServerResource{}
|
||||||
|
)
|
||||||
|
|
||||||
|
type metricsServerResource struct {
|
||||||
|
client *metrics.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewMetricsServerResource creates new metrics server resource.
|
||||||
|
func NewMetricsServerResource() resource.Resource {
|
||||||
|
return &metricsServerResource{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *metricsServerResource) Metadata(
|
||||||
|
_ context.Context,
|
||||||
|
req resource.MetadataRequest,
|
||||||
|
resp *resource.MetadataResponse,
|
||||||
|
) {
|
||||||
|
resp.TypeName = req.ProviderTypeName + "_metrics_server"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *metricsServerResource) Configure(
|
||||||
|
_ context.Context,
|
||||||
|
req resource.ConfigureRequest,
|
||||||
|
resp *resource.ConfigureResponse,
|
||||||
|
) {
|
||||||
|
if req.ProviderData == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg, ok := req.ProviderData.(config.Resource)
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
resp.Diagnostics.AddError(
|
||||||
|
"Unexpected Resource Configure Type",
|
||||||
|
fmt.Sprintf("Expected *proxmox.Client, got: %T", req.ProviderData),
|
||||||
|
)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
r.client = cfg.Client.Cluster().Metrics()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *metricsServerResource) Schema(
|
||||||
|
_ context.Context,
|
||||||
|
_ resource.SchemaRequest,
|
||||||
|
resp *resource.SchemaResponse,
|
||||||
|
) {
|
||||||
|
resp.Schema = schema.Schema{
|
||||||
|
Description: "Manages PVE metrics server.",
|
||||||
|
Attributes: map[string]schema.Attribute{
|
||||||
|
"id": attribute.ID(),
|
||||||
|
"name": schema.StringAttribute{
|
||||||
|
Description: "Unique name that will be ID of this metric server in PVE.",
|
||||||
|
Required: true,
|
||||||
|
PlanModifiers: []planmodifier.String{
|
||||||
|
stringplanmodifier.RequiresReplace(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"disable": schema.BoolAttribute{
|
||||||
|
Description: "Set this to `true` to disable this metric server.",
|
||||||
|
Optional: true,
|
||||||
|
Default: nil,
|
||||||
|
},
|
||||||
|
"mtu": schema.Int64Attribute{
|
||||||
|
Description: "MTU (maximum transmission unit) for metrics transmission over UDP. " +
|
||||||
|
"If not set, PVE default is `1500` (allowed `512` - `65536`).",
|
||||||
|
Validators: []validator.Int64{int64validator.Between(512, 65536)},
|
||||||
|
Optional: true,
|
||||||
|
Default: nil,
|
||||||
|
},
|
||||||
|
"port": schema.Int64Attribute{
|
||||||
|
Description: "Server network port.",
|
||||||
|
Required: true,
|
||||||
|
Validators: []validator.Int64{int64validator.Between(1, 65536)},
|
||||||
|
},
|
||||||
|
"server": schema.StringAttribute{
|
||||||
|
Description: "Server dns name or IP address.",
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
"timeout": schema.Int64Attribute{
|
||||||
|
Description: "TCP socket timeout in seconds. If not set, PVE default is `1`.",
|
||||||
|
Optional: true,
|
||||||
|
Default: nil,
|
||||||
|
},
|
||||||
|
"type": schema.StringAttribute{
|
||||||
|
Description: "Plugin type. Choice is between `graphite` | `influxdb`.",
|
||||||
|
Required: true,
|
||||||
|
Validators: []validator.String{stringvalidator.OneOf("graphite", "influxdb")},
|
||||||
|
PlanModifiers: []planmodifier.String{
|
||||||
|
stringplanmodifier.RequiresReplace(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"influx_api_path_prefix": schema.StringAttribute{
|
||||||
|
Description: "An API path prefix inserted between `<host>:<port>/` and `/api2/`." +
|
||||||
|
" Can be useful if the InfluxDB service runs behind a reverse proxy.",
|
||||||
|
Optional: true,
|
||||||
|
Default: nil,
|
||||||
|
},
|
||||||
|
"influx_bucket": schema.StringAttribute{
|
||||||
|
Description: "The InfluxDB bucket/db. Only necessary when using the http v2 api.",
|
||||||
|
Optional: true,
|
||||||
|
Default: nil,
|
||||||
|
},
|
||||||
|
"influx_db_proto": schema.StringAttribute{
|
||||||
|
Description: "Protocol for InfluxDB. Choice is between `udp` | `http` | `https`. " +
|
||||||
|
"If not set, PVE default is `udp`.",
|
||||||
|
Validators: []validator.String{stringvalidator.OneOf("udp", "http", "https")},
|
||||||
|
Optional: true,
|
||||||
|
Default: nil,
|
||||||
|
},
|
||||||
|
"influx_max_body_size": schema.Int64Attribute{
|
||||||
|
Description: "InfluxDB max-body-size in bytes. Requests are batched up to this " +
|
||||||
|
"size. If not set, PVE default is `25000000`.",
|
||||||
|
Optional: true,
|
||||||
|
Default: nil,
|
||||||
|
},
|
||||||
|
"influx_organization": schema.StringAttribute{
|
||||||
|
Description: "The InfluxDB organization. Only necessary when using the http v2 " +
|
||||||
|
"api. Has no meaning when using v2 compatibility api.",
|
||||||
|
Optional: true,
|
||||||
|
Default: nil,
|
||||||
|
},
|
||||||
|
"influx_token": schema.StringAttribute{
|
||||||
|
Description: "The InfluxDB access token. Only necessary when using the http v2 " +
|
||||||
|
"api. If the v2 compatibility api is used, use `user:password` instead.",
|
||||||
|
Optional: true,
|
||||||
|
Default: nil,
|
||||||
|
Sensitive: true,
|
||||||
|
},
|
||||||
|
"influx_verify": schema.BoolAttribute{
|
||||||
|
Description: "Set to `false` to disable certificate verification for https " +
|
||||||
|
"endpoints.",
|
||||||
|
Optional: true,
|
||||||
|
Default: nil,
|
||||||
|
},
|
||||||
|
"graphite_path": schema.StringAttribute{
|
||||||
|
Description: "Root graphite path (ex: `proxmox.mycluster.mykey`).",
|
||||||
|
Optional: true,
|
||||||
|
Default: nil,
|
||||||
|
},
|
||||||
|
"graphite_proto": schema.StringAttribute{
|
||||||
|
Description: "Protocol to send graphite data. Choice is between `udp` | `tcp`. " +
|
||||||
|
"If not set, PVE default is `udp`.",
|
||||||
|
Validators: []validator.String{stringvalidator.OneOf("udp", "tcp")},
|
||||||
|
Optional: true,
|
||||||
|
Default: nil,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *metricsServerResource) Read(
|
||||||
|
ctx context.Context,
|
||||||
|
req resource.ReadRequest,
|
||||||
|
resp *resource.ReadResponse,
|
||||||
|
) {
|
||||||
|
var state metricsServerModel
|
||||||
|
|
||||||
|
resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
|
||||||
|
|
||||||
|
if resp.Diagnostics.HasError() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := r.client.GetServer(ctx, state.ID.ValueString())
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, api.ErrResourceDoesNotExist) {
|
||||||
|
resp.State.RemoveResource(ctx)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
resp.Diagnostics.AddError(
|
||||||
|
"Unable to Refresh Resource",
|
||||||
|
"An unexpected error occurred while attempting to refresh resource state. "+
|
||||||
|
"Please retry the operation or report this issue to the provider developers.\n\n"+
|
||||||
|
"Error: "+err.Error(),
|
||||||
|
)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
readModel := &metricsServerModel{}
|
||||||
|
readModel.importFromAPI(state.ID.ValueString(), data)
|
||||||
|
|
||||||
|
resp.Diagnostics.Append(resp.State.Set(ctx, readModel)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *metricsServerResource) Create(
|
||||||
|
ctx context.Context,
|
||||||
|
req resource.CreateRequest,
|
||||||
|
resp *resource.CreateResponse,
|
||||||
|
) {
|
||||||
|
var plan metricsServerModel
|
||||||
|
|
||||||
|
resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
|
||||||
|
|
||||||
|
if resp.Diagnostics.HasError() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
reqData := plan.toAPIRequestBody()
|
||||||
|
|
||||||
|
err := r.client.CreateServer(ctx, reqData)
|
||||||
|
if err != nil {
|
||||||
|
resp.Diagnostics.AddError(
|
||||||
|
"Unable to Create Resource",
|
||||||
|
"An unexpected error occurred while creating the resource create request.\n\n"+
|
||||||
|
"Error: "+err.Error(),
|
||||||
|
)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
plan.ID = plan.Name
|
||||||
|
|
||||||
|
resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkDelete(planField, stateField attr.Value, toDelete *[]string, apiName string) {
|
||||||
|
// we need to remove field via api field if there is value in state
|
||||||
|
// but someone decided to use PVE default and removed value from resource
|
||||||
|
if planField.IsNull() && !stateField.IsNull() {
|
||||||
|
*toDelete = append(*toDelete, apiName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *metricsServerResource) Update(
|
||||||
|
ctx context.Context,
|
||||||
|
req resource.UpdateRequest,
|
||||||
|
resp *resource.UpdateResponse,
|
||||||
|
) {
|
||||||
|
var plan metricsServerModel
|
||||||
|
|
||||||
|
var state metricsServerModel
|
||||||
|
|
||||||
|
resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
|
||||||
|
resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
|
||||||
|
|
||||||
|
if resp.Diagnostics.HasError() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var toDelete []string
|
||||||
|
|
||||||
|
checkDelete(plan.Disable, state.Disable, &toDelete, "disable")
|
||||||
|
checkDelete(plan.MTU, state.MTU, &toDelete, "mtu")
|
||||||
|
checkDelete(plan.Timeout, state.Timeout, &toDelete, "timeout")
|
||||||
|
checkDelete(plan.InfluxAPIPathPrefix, state.InfluxAPIPathPrefix, &toDelete, "api-path-prefix")
|
||||||
|
checkDelete(plan.InfluxBucket, state.InfluxBucket, &toDelete, "bucket")
|
||||||
|
checkDelete(plan.InfluxDBProto, state.InfluxDBProto, &toDelete, "influxdbproto")
|
||||||
|
checkDelete(plan.InfluxMaxBodySize, state.InfluxMaxBodySize, &toDelete, "max-body-size")
|
||||||
|
checkDelete(plan.InfluxOrganization, state.InfluxOrganization, &toDelete, "organization")
|
||||||
|
checkDelete(plan.InfluxToken, state.InfluxToken, &toDelete, "token")
|
||||||
|
checkDelete(plan.InfluxVerify, state.InfluxVerify, &toDelete, "verify-certificate")
|
||||||
|
checkDelete(plan.GraphitePath, state.GraphitePath, &toDelete, "path")
|
||||||
|
checkDelete(plan.GraphiteProto, state.GraphiteProto, &toDelete, "proto")
|
||||||
|
|
||||||
|
reqData := plan.toAPIRequestBody()
|
||||||
|
reqData.Delete = &toDelete
|
||||||
|
|
||||||
|
err := r.client.UpdateServer(ctx, reqData)
|
||||||
|
if err != nil {
|
||||||
|
resp.Diagnostics.AddError(
|
||||||
|
"Unable to Update Resource",
|
||||||
|
"An unexpected error occurred while creating the resource update request.\n\n"+
|
||||||
|
"Error: "+err.Error(),
|
||||||
|
)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *metricsServerResource) Delete(
|
||||||
|
ctx context.Context,
|
||||||
|
req resource.DeleteRequest,
|
||||||
|
resp *resource.DeleteResponse,
|
||||||
|
) {
|
||||||
|
var state metricsServerModel
|
||||||
|
|
||||||
|
resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
|
||||||
|
|
||||||
|
if resp.Diagnostics.HasError() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err := r.client.DeleteServer(ctx, state.ID.ValueString())
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, api.ErrResourceDoesNotExist) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
resp.Diagnostics.AddError(
|
||||||
|
"Unable to Delete Resource",
|
||||||
|
"An unexpected error occurred while creating the resource delete request.\n\n"+
|
||||||
|
"Error: "+err.Error(),
|
||||||
|
)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *metricsServerResource) ImportState(
|
||||||
|
ctx context.Context,
|
||||||
|
req resource.ImportStateRequest,
|
||||||
|
resp *resource.ImportStateResponse,
|
||||||
|
) {
|
||||||
|
data, err := r.client.GetServer(ctx, req.ID)
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, api.ErrResourceDoesNotExist) {
|
||||||
|
resp.Diagnostics.AddError(
|
||||||
|
"Resource does not exist",
|
||||||
|
"Resource you try to import does not exist.\n\n"+
|
||||||
|
"Error: "+err.Error(),
|
||||||
|
)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
resp.Diagnostics.AddError(
|
||||||
|
"Unable to Import Resource",
|
||||||
|
"An unexpected error occurred while attempting to import resource state.\n\n"+
|
||||||
|
"Error: "+err.Error(),
|
||||||
|
)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
readModel := &metricsServerModel{}
|
||||||
|
readModel.importFromAPI(req.ID, data)
|
||||||
|
|
||||||
|
resp.Diagnostics.Append(resp.State.Set(ctx, readModel)...)
|
||||||
|
}
|
177
fwprovider/cluster/metrics/resource_metrics_server_test.go
Normal file
177
fwprovider/cluster/metrics/resource_metrics_server_test.go
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
//go:build acceptance || all
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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 metrics_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/bpg/terraform-provider-proxmox/fwprovider/test"
|
||||||
|
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAccResourceMetricsServer(t *testing.T) {
|
||||||
|
te := test.InitEnvironment(t)
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
steps []resource.TestStep
|
||||||
|
}{
|
||||||
|
{"create influxdb udp server & update it & again to default mtu", []resource.TestStep{
|
||||||
|
{
|
||||||
|
Config: te.RenderConfig(`
|
||||||
|
resource "proxmox_virtual_environment_metrics_server" "acc_influxdb_server" {
|
||||||
|
name = "acc_example_influxdb_server"
|
||||||
|
server = "192.168.3.2"
|
||||||
|
port = 18089
|
||||||
|
type = "influxdb"
|
||||||
|
mtu = 1000
|
||||||
|
}`),
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
test.ResourceAttributes("proxmox_virtual_environment_metrics_server.acc_influxdb_server", map[string]string{
|
||||||
|
"id": "acc_example_influxdb_server",
|
||||||
|
"name": "acc_example_influxdb_server",
|
||||||
|
"mtu": "1000",
|
||||||
|
"port": "18089",
|
||||||
|
"server": "192.168.3.2",
|
||||||
|
"type": "influxdb",
|
||||||
|
}),
|
||||||
|
test.NoResourceAttributesSet("proxmox_virtual_environment_metrics_server.acc_influxdb_server", []string{
|
||||||
|
"disable",
|
||||||
|
"timeout",
|
||||||
|
"influx_api_path_prefix",
|
||||||
|
"influx_bucket",
|
||||||
|
"influx_db_proto",
|
||||||
|
"influx_max_body_size",
|
||||||
|
"influx_organization",
|
||||||
|
"influx_token",
|
||||||
|
"influx_verify",
|
||||||
|
"graphite_path",
|
||||||
|
"graphite_proto",
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Config: te.RenderConfig(`
|
||||||
|
resource "proxmox_virtual_environment_metrics_server" "acc_influxdb_server" {
|
||||||
|
name = "acc_example_influxdb_server"
|
||||||
|
server = "192.168.3.2"
|
||||||
|
port = 18089
|
||||||
|
type = "influxdb"
|
||||||
|
mtu = 1000
|
||||||
|
influx_bucket = "xxxxx"
|
||||||
|
}`),
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
test.ResourceAttributes("proxmox_virtual_environment_metrics_server.acc_influxdb_server", map[string]string{
|
||||||
|
"id": "acc_example_influxdb_server",
|
||||||
|
"name": "acc_example_influxdb_server",
|
||||||
|
"mtu": "1000",
|
||||||
|
"port": "18089",
|
||||||
|
"server": "192.168.3.2",
|
||||||
|
"type": "influxdb",
|
||||||
|
"influx_bucket": "xxxxx",
|
||||||
|
}),
|
||||||
|
test.NoResourceAttributesSet("proxmox_virtual_environment_metrics_server.acc_influxdb_server", []string{
|
||||||
|
"disable",
|
||||||
|
"timeout",
|
||||||
|
"influx_api_path_prefix",
|
||||||
|
"influx_db_proto",
|
||||||
|
"influx_max_body_size",
|
||||||
|
"influx_organization",
|
||||||
|
"influx_token",
|
||||||
|
"influx_verify",
|
||||||
|
"graphite_path",
|
||||||
|
"graphite_proto",
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Config: te.RenderConfig(`
|
||||||
|
resource "proxmox_virtual_environment_metrics_server" "acc_influxdb_server" {
|
||||||
|
name = "acc_example_influxdb_server"
|
||||||
|
server = "192.168.3.2"
|
||||||
|
port = 18089
|
||||||
|
type = "influxdb"
|
||||||
|
influx_bucket = "xxxxx"
|
||||||
|
}`),
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
test.ResourceAttributes("proxmox_virtual_environment_metrics_server.acc_influxdb_server", map[string]string{
|
||||||
|
"id": "acc_example_influxdb_server",
|
||||||
|
"name": "acc_example_influxdb_server",
|
||||||
|
"port": "18089",
|
||||||
|
"server": "192.168.3.2",
|
||||||
|
"type": "influxdb",
|
||||||
|
"influx_bucket": "xxxxx",
|
||||||
|
}),
|
||||||
|
test.NoResourceAttributesSet("proxmox_virtual_environment_metrics_server.acc_influxdb_server", []string{
|
||||||
|
"disable",
|
||||||
|
"timeout",
|
||||||
|
"mtu",
|
||||||
|
"influx_api_path_prefix",
|
||||||
|
"influx_db_proto",
|
||||||
|
"influx_max_body_size",
|
||||||
|
"influx_organization",
|
||||||
|
"influx_token",
|
||||||
|
"influx_verify",
|
||||||
|
"graphite_path",
|
||||||
|
"graphite_proto",
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
{"create graphite udp metrics server & import it", []resource.TestStep{
|
||||||
|
{
|
||||||
|
ResourceName: "proxmox_virtual_environment_metrics_server.acc_graphite_server",
|
||||||
|
Config: te.RenderConfig(`
|
||||||
|
resource "proxmox_virtual_environment_metrics_server" "acc_graphite_server" {
|
||||||
|
name = "acc_example_graphite_server"
|
||||||
|
server = "192.168.3.2"
|
||||||
|
port = 18089
|
||||||
|
type = "graphite"
|
||||||
|
}`),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ResourceName: "proxmox_virtual_environment_metrics_server.acc_graphite_server",
|
||||||
|
ImportState: true,
|
||||||
|
ImportStateVerify: true,
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
{"create graphite udp metrics server & test datasource", []resource.TestStep{
|
||||||
|
{
|
||||||
|
Config: te.RenderConfig(`
|
||||||
|
resource "proxmox_virtual_environment_metrics_server" "acc_graphite_server2" {
|
||||||
|
name = "acc_example_graphite_server2"
|
||||||
|
server = "192.168.3.2"
|
||||||
|
port = 18089
|
||||||
|
type = "graphite"
|
||||||
|
}
|
||||||
|
data "proxmox_virtual_environment_metrics_server" "acc_graphite_server2" {
|
||||||
|
name = proxmox_virtual_environment_metrics_server.acc_graphite_server2.name
|
||||||
|
}`),
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
test.ResourceAttributes("data.proxmox_virtual_environment_metrics_server.acc_graphite_server2", map[string]string{
|
||||||
|
"id": "acc_example_graphite_server2",
|
||||||
|
"name": "acc_example_graphite_server2",
|
||||||
|
"port": "18089",
|
||||||
|
"server": "192.168.3.2",
|
||||||
|
"type": "graphite",
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
resource.ParallelTest(t, resource.TestCase{
|
||||||
|
ProtoV6ProviderFactories: te.AccProviders,
|
||||||
|
Steps: tt.steps,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@ -26,6 +26,7 @@ import (
|
|||||||
|
|
||||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/access"
|
"github.com/bpg/terraform-provider-proxmox/fwprovider/access"
|
||||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/acme"
|
"github.com/bpg/terraform-provider-proxmox/fwprovider/acme"
|
||||||
|
"github.com/bpg/terraform-provider-proxmox/fwprovider/cluster/metrics"
|
||||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/config"
|
"github.com/bpg/terraform-provider-proxmox/fwprovider/config"
|
||||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/ha"
|
"github.com/bpg/terraform-provider-proxmox/fwprovider/ha"
|
||||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/hardwaremapping"
|
"github.com/bpg/terraform-provider-proxmox/fwprovider/hardwaremapping"
|
||||||
@ -509,6 +510,7 @@ func (p *proxmoxProvider) Resources(_ context.Context) []func() resource.Resourc
|
|||||||
network.NewLinuxBridgeResource,
|
network.NewLinuxBridgeResource,
|
||||||
network.NewLinuxVLANResource,
|
network.NewLinuxVLANResource,
|
||||||
vm.NewResource,
|
vm.NewResource,
|
||||||
|
metrics.NewMetricsServerResource,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -529,6 +531,7 @@ func (p *proxmoxProvider) DataSources(_ context.Context) []func() datasource.Dat
|
|||||||
hardwaremapping.NewPCIDataSource,
|
hardwaremapping.NewPCIDataSource,
|
||||||
hardwaremapping.NewUSBDataSource,
|
hardwaremapping.NewUSBDataSource,
|
||||||
vm.NewDataSource,
|
vm.NewDataSource,
|
||||||
|
metrics.NewMetricsServerDatasource,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@ import (
|
|||||||
clusterfirewall "github.com/bpg/terraform-provider-proxmox/proxmox/cluster/firewall"
|
clusterfirewall "github.com/bpg/terraform-provider-proxmox/proxmox/cluster/firewall"
|
||||||
"github.com/bpg/terraform-provider-proxmox/proxmox/cluster/ha"
|
"github.com/bpg/terraform-provider-proxmox/proxmox/cluster/ha"
|
||||||
"github.com/bpg/terraform-provider-proxmox/proxmox/cluster/mapping"
|
"github.com/bpg/terraform-provider-proxmox/proxmox/cluster/mapping"
|
||||||
|
"github.com/bpg/terraform-provider-proxmox/proxmox/cluster/metrics"
|
||||||
"github.com/bpg/terraform-provider-proxmox/proxmox/firewall"
|
"github.com/bpg/terraform-provider-proxmox/proxmox/firewall"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -48,3 +49,8 @@ func (c *Client) HardwareMapping() *mapping.Client {
|
|||||||
func (c *Client) ACME() *acme.Client {
|
func (c *Client) ACME() *acme.Client {
|
||||||
return &acme.Client{Client: c}
|
return &acme.Client{Client: c}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Metrics returns a client for managing the cluster's metrics features.
|
||||||
|
func (c *Client) Metrics() *metrics.Client {
|
||||||
|
return &metrics.Client{Client: c}
|
||||||
|
}
|
||||||
|
23
proxmox/cluster/metrics/client.go
Normal file
23
proxmox/cluster/metrics/client.go
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
* 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 metrics
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/bpg/terraform-provider-proxmox/proxmox/api"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Client is an interface for accessing the Proxmox metrics management API.
|
||||||
|
type Client struct {
|
||||||
|
api.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExpandPath expands a relative path to the Proxmox metrics server management API path.
|
||||||
|
func (c *Client) ExpandPath(path string) string {
|
||||||
|
return fmt.Sprintf("cluster/metrics/server/%s", path)
|
||||||
|
}
|
82
proxmox/cluster/metrics/server.go
Normal file
82
proxmox/cluster/metrics/server.go
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
/*
|
||||||
|
* 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 metrics
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/bpg/terraform-provider-proxmox/proxmox/api"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetServer retrieves the metrics server data.
|
||||||
|
func (c *Client) GetServer(ctx context.Context, id string) (*ServerData, error) {
|
||||||
|
resBody := &ServerResponseBody{}
|
||||||
|
|
||||||
|
err := c.DoRequest(ctx, http.MethodGet, c.ExpandPath(id), nil, resBody)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error reading metrics server: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if resBody.Data == nil {
|
||||||
|
return nil, api.ErrNoDataObjectInResponse
|
||||||
|
}
|
||||||
|
|
||||||
|
return resBody.Data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetServers lists the metrics servers.
|
||||||
|
func (c *Client) GetServers(ctx context.Context) (*[]ServerData, error) {
|
||||||
|
resBody := &ServersResponseBody{}
|
||||||
|
|
||||||
|
err := c.DoRequest(ctx, http.MethodGet, c.ExpandPath(""), nil, resBody)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error reading list of metrics servers: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if resBody.Data == nil {
|
||||||
|
return nil, api.ErrNoDataObjectInResponse
|
||||||
|
}
|
||||||
|
|
||||||
|
return resBody.Data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateServer updates the metrics server.
|
||||||
|
func (c *Client) UpdateServer(ctx context.Context, data *ServerRequestData) error {
|
||||||
|
// PVE API does not allow to pass "type" in PUT requests, this doesn't makes any sense
|
||||||
|
// since other required params like port, server must still be there
|
||||||
|
// while we could spawn another struct, let's just fix it silently
|
||||||
|
data.Type = nil
|
||||||
|
|
||||||
|
err := c.DoRequest(ctx, http.MethodPut, c.ExpandPath(data.ID), data, nil)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error updating metrics server: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateServer creates the metrics server.
|
||||||
|
func (c *Client) CreateServer(ctx context.Context, data *ServerRequestData) error {
|
||||||
|
err := c.DoRequest(ctx, http.MethodPost, c.ExpandPath(data.ID), data, nil)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error creating metrics server: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteServer deletes the metrics server.
|
||||||
|
func (c *Client) DeleteServer(ctx context.Context, id string) error {
|
||||||
|
err := c.DoRequest(ctx, http.MethodDelete, c.ExpandPath(id), nil, nil)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error updating metrics server: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
47
proxmox/cluster/metrics/server_types.go
Normal file
47
proxmox/cluster/metrics/server_types.go
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* 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 metrics
|
||||||
|
|
||||||
|
// ServerData contains the data from a metrics server response.
|
||||||
|
type ServerData struct {
|
||||||
|
Disable *int64 `json:"disable,omitempty" url:"disable,omitempty"`
|
||||||
|
ID string `json:"id,omitempty" url:"id,omitempty"`
|
||||||
|
MTU *int64 `json:"mtu" url:"mtu,omitempty"`
|
||||||
|
Port int64 `json:"port" url:"port"`
|
||||||
|
Server string `json:"server" url:"server"`
|
||||||
|
Timeout *int64 `json:"timeout,omitempty" url:"timeout,omitempty"`
|
||||||
|
Type *string `json:"type,omitempty" url:"type,omitempty"`
|
||||||
|
|
||||||
|
// influxdb only options
|
||||||
|
APIPathPrefix *string `json:"api-path-prefix,omitempty" url:"api-path-prefix,omitempty"`
|
||||||
|
Bucket *string `json:"bucket,omitempty" url:"bucket,omitempty"`
|
||||||
|
InfluxDBProto *string `json:"influxdbproto,omitempty" url:"influxdbproto,omitempty"`
|
||||||
|
MaxBodySize *int64 `json:"max-body-size,omitempty" url:"max-body-size,omitempty"`
|
||||||
|
Organization *string `json:"organization,omitempty" url:"organization,omitempty"`
|
||||||
|
Token *string `json:"token,omitempty" url:"token,omitempty"`
|
||||||
|
Verify *int64 `json:"verify-certificate,omitempty" url:"verify-certificate,omitempty"`
|
||||||
|
|
||||||
|
// graphite only options
|
||||||
|
Path *string `json:"path,omitempty" url:"path,omitempty"`
|
||||||
|
Proto *string `json:"proto,omitempty" url:"proto,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ServerResponseBody contains the body from a metrics server response.
|
||||||
|
type ServerResponseBody struct {
|
||||||
|
Data *ServerData `json:"data,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ServersResponseBody contains the body from a metrics server list response.
|
||||||
|
type ServersResponseBody struct {
|
||||||
|
Data *[]ServerData `json:"data,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ServerRequestData contains the data for a metric server post/put request.
|
||||||
|
type ServerRequestData struct {
|
||||||
|
ServerData
|
||||||
|
Delete *[]string `url:"delete,omitempty"`
|
||||||
|
}
|
@ -43,6 +43,7 @@ import (
|
|||||||
//go:generate cp ../build/docs-gen/data-sources/virtual_environment_haresources.md ../docs/data-sources/
|
//go:generate cp ../build/docs-gen/data-sources/virtual_environment_haresources.md ../docs/data-sources/
|
||||||
//go:generate cp ../build/docs-gen/data-sources/virtual_environment_version.md ../docs/data-sources/
|
//go:generate cp ../build/docs-gen/data-sources/virtual_environment_version.md ../docs/data-sources/
|
||||||
//go:generate cp ../build/docs-gen/data-sources/virtual_environment_vm2.md ../docs/data-sources/
|
//go:generate cp ../build/docs-gen/data-sources/virtual_environment_vm2.md ../docs/data-sources/
|
||||||
|
//go:generate cp ../build/docs-gen/data-sources/virtual_environment_metrics_server.md ../docs/data-sources/
|
||||||
//go:generate cp ../build/docs-gen/resources/virtual_environment_acl.md ../docs/resources/
|
//go:generate cp ../build/docs-gen/resources/virtual_environment_acl.md ../docs/resources/
|
||||||
//go:generate cp ../build/docs-gen/resources/virtual_environment_acme_account.md ../docs/resources/
|
//go:generate cp ../build/docs-gen/resources/virtual_environment_acme_account.md ../docs/resources/
|
||||||
//go:generate cp ../build/docs-gen/resources/virtual_environment_acme_dns_plugin.md ../docs/resources/
|
//go:generate cp ../build/docs-gen/resources/virtual_environment_acme_dns_plugin.md ../docs/resources/
|
||||||
@ -58,3 +59,4 @@ import (
|
|||||||
//go:generate cp ../build/docs-gen/resources/virtual_environment_network_linux_vlan.md ../docs/resources/
|
//go:generate cp ../build/docs-gen/resources/virtual_environment_network_linux_vlan.md ../docs/resources/
|
||||||
//go:generate cp ../build/docs-gen/resources/virtual_environment_user_token.md ../docs/resources/
|
//go:generate cp ../build/docs-gen/resources/virtual_environment_user_token.md ../docs/resources/
|
||||||
//go:generate cp ../build/docs-gen/resources/virtual_environment_vm2.md ../docs/resources/
|
//go:generate cp ../build/docs-gen/resources/virtual_environment_vm2.md ../docs/resources/
|
||||||
|
//go:generate cp ../build/docs-gen/resources/virtual_environment_metrics_server.md ../docs/resources/
|
||||||
|
Loading…
Reference in New Issue
Block a user