diff --git a/docs/resources/virtual_environment_metrics_server.md b/docs/resources/virtual_environment_metrics_server.md index c070deaaf..a967504be 100644 --- a/docs/resources/virtual_environment_metrics_server.md +++ b/docs/resources/virtual_environment_metrics_server.md @@ -27,6 +27,15 @@ resource "proxmox_virtual_environment_metrics_server" "graphite_server" { port = 2003 type = "graphite" } + +resource "proxmox_virtual_environment_metrics_server" "opentelemetry_server" { + name = "example_opentelemetry_server" + server = "192.168.5.2" + port = 4318 + type = "opentelemetry" + opentelemetry_proto = "https" + opentelemetry_path = "/v1/metrics" +} ``` @@ -37,7 +46,7 @@ resource "proxmox_virtual_environment_metrics_server" "graphite_server" { - `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`. +- `type` (String) Plugin type. Choice is between `graphite` | `influxdb` | `opentelemetry`. ### Optional @@ -52,6 +61,8 @@ resource "proxmox_virtual_environment_metrics_server" "graphite_server" { - `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`). +- `opentelemetry_path` (String) OpenTelemetry endpoint path (e.g., `/v1/metrics`). +- `opentelemetry_proto` (String) Protocol for OpenTelemetry. Choice is between `http` | `https` | `grpc`. If not set, PVE default is `http`. - `timeout` (Number) TCP socket timeout in seconds. If not set, PVE default is `1`. ### Read-Only diff --git a/example/resource_virtual_environment_metrics_server.tf b/example/resource_virtual_environment_metrics_server.tf index e5f034dfb..e19e44660 100644 --- a/example/resource_virtual_environment_metrics_server.tf +++ b/example/resource_virtual_environment_metrics_server.tf @@ -22,3 +22,21 @@ resource "proxmox_virtual_environment_metrics_server" "graphite_server2" { timeout = 5 graphite_proto = "udp" } + +resource "proxmox_virtual_environment_metrics_server" "opentelemetry_server" { + name = "example_opentelemetry_server" + server = "192.168.5.2" + port = 4318 + type = "opentelemetry" + opentelemetry_proto = "http" + opentelemetry_path = "/v1/metrics" +} + +resource "proxmox_virtual_environment_metrics_server" "opentelemetry_server_https" { + name = "example_opentelemetry_server_https" + server = "192.168.5.3" + port = 4319 + type = "opentelemetry" + opentelemetry_proto = "https" + opentelemetry_path = "/v1/metrics" +} diff --git a/fwprovider/cluster/metrics/datasource_metrics_server.go b/fwprovider/cluster/metrics/datasource_metrics_server.go index aa10996b8..cc27d0124 100644 --- a/fwprovider/cluster/metrics/datasource_metrics_server.go +++ b/fwprovider/cluster/metrics/datasource_metrics_server.go @@ -90,7 +90,15 @@ func (r *metricsServerDatasource) Schema( Computed: true, }, "type": schema.StringAttribute{ - Description: "Plugin type. Either `graphite` or `influxdb`.", + Description: "Plugin type. Either `graphite`, `influxdb`, or `opentelemetry`.", + Computed: true, + }, + "opentelemetry_proto": schema.StringAttribute{ + Description: "Protocol for OpenTelemetry. Choice is between `http` | `https` | `grpc`.", + Computed: true, + }, + "opentelemetry_path": schema.StringAttribute{ + Description: "OpenTelemetry endpoint path (e.g., `/v1/metrics`).", Computed: true, }, }, diff --git a/fwprovider/cluster/metrics/metrics_server_model.go b/fwprovider/cluster/metrics/metrics_server_model.go index 227928952..10e87f398 100644 --- a/fwprovider/cluster/metrics/metrics_server_model.go +++ b/fwprovider/cluster/metrics/metrics_server_model.go @@ -30,6 +30,8 @@ type metricsServerModel struct { InfluxVerify types.Bool `tfsdk:"influx_verify"` GraphitePath types.String `tfsdk:"graphite_path"` GraphiteProto types.String `tfsdk:"graphite_proto"` + OTelProto types.String `tfsdk:"opentelemetry_proto"` + OTelPath types.String `tfsdk:"opentelemetry_path"` } func boolToInt64Ptr(boolPtr *bool) *int64 { @@ -85,6 +87,8 @@ func (m *metricsServerModel) importFromAPI(name string, data *metrics.ServerData m.InfluxVerify = types.BoolPointerValue(int64ToBoolPtr(data.Verify)) m.GraphitePath = types.StringPointerValue(data.Path) m.GraphiteProto = types.StringPointerValue(data.Proto) + m.OTelProto = types.StringPointerValue(data.OTelProto) + m.OTelPath = types.StringPointerValue(data.OTelPath) } // toAPIRequestBody creates metrics server request data for PUT and POST requests. @@ -108,17 +112,21 @@ func (m *metricsServerModel) toAPIRequestBody() *metrics.ServerRequestData { data.Verify = boolToInt64Ptr(m.InfluxVerify.ValueBoolPointer()) data.Path = m.GraphitePath.ValueStringPointer() data.Proto = m.GraphiteProto.ValueStringPointer() + data.OTelProto = m.OTelProto.ValueStringPointer() + data.OTelPath = m.OTelPath.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"` + 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"` + OTelProto types.String `tfsdk:"opentelemetry_proto"` + OTelPath types.String `tfsdk:"opentelemetry_path"` } // importFromAPI takes data from metrics server PVE API response and set fields based on it. @@ -131,4 +139,6 @@ func (m *metricsServerDatasourceModel) importFromAPI(name string, data *metrics. m.Port = types.Int64Value(data.Port) m.Server = types.StringValue(data.Server) m.Type = types.StringPointerValue(data.Type) + m.OTelProto = types.StringPointerValue(data.OTelProto) + m.OTelPath = types.StringPointerValue(data.OTelPath) } diff --git a/fwprovider/cluster/metrics/resource_metrics_server.go b/fwprovider/cluster/metrics/resource_metrics_server.go index b7576ba2b..924f5a0db 100644 --- a/fwprovider/cluster/metrics/resource_metrics_server.go +++ b/fwprovider/cluster/metrics/resource_metrics_server.go @@ -113,9 +113,9 @@ func (r *metricsServerResource) Schema( Default: nil, }, "type": schema.StringAttribute{ - Description: "Plugin type. Choice is between `graphite` | `influxdb`.", + Description: "Plugin type. Choice is between `graphite` | `influxdb` | `opentelemetry`.", Required: true, - Validators: []validator.String{stringvalidator.OneOf("graphite", "influxdb")}, + Validators: []validator.String{stringvalidator.OneOf("graphite", "influxdb", "opentelemetry")}, PlanModifiers: []planmodifier.String{ stringplanmodifier.RequiresReplace(), }, @@ -175,6 +175,18 @@ func (r *metricsServerResource) Schema( Optional: true, Default: nil, }, + "opentelemetry_proto": schema.StringAttribute{ + Description: "Protocol for OpenTelemetry. Choice is between `http` | `https`. " + + "If not set, PVE default is `http`.", + Validators: []validator.String{stringvalidator.OneOf("http", "https")}, + Optional: true, + Default: nil, + }, + "opentelemetry_path": schema.StringAttribute{ + Description: "OpenTelemetry endpoint path (e.g., `/v1/metrics`).", + Optional: true, + Default: nil, + }, }, } } @@ -277,6 +289,8 @@ func (r *metricsServerResource) Update( attribute.CheckDelete(plan.InfluxVerify, state.InfluxVerify, &toDelete, "verify-certificate") attribute.CheckDelete(plan.GraphitePath, state.GraphitePath, &toDelete, "path") attribute.CheckDelete(plan.GraphiteProto, state.GraphiteProto, &toDelete, "proto") + attribute.CheckDelete(plan.OTelProto, state.OTelProto, &toDelete, "otel-protocol") + attribute.CheckDelete(plan.OTelPath, state.OTelPath, &toDelete, "otel-path") reqData := plan.toAPIRequestBody() reqData.Delete = &toDelete diff --git a/fwprovider/cluster/metrics/resource_metrics_server_test.go b/fwprovider/cluster/metrics/resource_metrics_server_test.go index d4a452f01..3d66acae0 100644 --- a/fwprovider/cluster/metrics/resource_metrics_server_test.go +++ b/fwprovider/cluster/metrics/resource_metrics_server_test.go @@ -54,6 +54,8 @@ func TestAccResourceMetricsServer(t *testing.T) { "influx_verify", "graphite_path", "graphite_proto", + "opentelemetry_proto", + "opentelemetry_path", }), ), }, @@ -88,6 +90,8 @@ func TestAccResourceMetricsServer(t *testing.T) { "influx_verify", "graphite_path", "graphite_proto", + "opentelemetry_proto", + "opentelemetry_path", }), ), }, @@ -121,6 +125,8 @@ func TestAccResourceMetricsServer(t *testing.T) { "influx_verify", "graphite_path", "graphite_proto", + "opentelemetry_proto", + "opentelemetry_path", }), ), }, @@ -165,6 +171,51 @@ func TestAccResourceMetricsServer(t *testing.T) { ), }, }}, + {"create opentelemetry metrics server & import it", []resource.TestStep{ + { + ResourceName: "proxmox_virtual_environment_metrics_server.acc_otel_server", + Config: te.RenderConfig(` + resource "proxmox_virtual_environment_metrics_server" "acc_otel_server" { + name = "acc_example_otel_server" + server = "192.168.3.2" + port = 4318 + type = "opentelemetry" + opentelemetry_proto = "http" + }`), + }, + { + ResourceName: "proxmox_virtual_environment_metrics_server.acc_otel_server", + ImportState: true, + ImportStateVerify: true, + }, + }}, + {"create opentelemetry metrics server & test datasource", []resource.TestStep{ + { + Config: te.RenderConfig(` + resource "proxmox_virtual_environment_metrics_server" "acc_otel_server2" { + name = "acc_example_otel_server2" + server = "192.168.3.2" + port = 4318 + type = "opentelemetry" + opentelemetry_proto = "https" + opentelemetry_path = "/v1/metrics" + } + data "proxmox_virtual_environment_metrics_server" "acc_otel_server2" { + name = proxmox_virtual_environment_metrics_server.acc_otel_server2.name + }`), + Check: resource.ComposeTestCheckFunc( + test.ResourceAttributes("data.proxmox_virtual_environment_metrics_server.acc_otel_server2", map[string]string{ + "id": "acc_example_otel_server2", + "name": "acc_example_otel_server2", + "port": "4318", + "server": "192.168.3.2", + "type": "opentelemetry", + "opentelemetry_proto": "https", + "opentelemetry_path": "/v1/metrics", + }), + ), + }, + }}, } for _, tt := range tests { diff --git a/proxmox/cluster/metrics/server_types.go b/proxmox/cluster/metrics/server_types.go index b825588b0..64368dab4 100644 --- a/proxmox/cluster/metrics/server_types.go +++ b/proxmox/cluster/metrics/server_types.go @@ -28,6 +28,10 @@ type ServerData struct { // graphite only options Path *string `json:"path,omitempty" url:"path,omitempty"` Proto *string `json:"proto,omitempty" url:"proto,omitempty"` + + // opentelemetry only options + OTelProto *string `json:"otel-protocol,omitempty" url:"otel-protocol,omitempty"` + OTelPath *string `json:"otel-path,omitempty" url:"otel-path,omitempty"` } // ServerResponseBody contains the body from a metrics server response.