Skip to content

Commit

Permalink
Add options to run metrics endpoint over HTTPS
Browse files Browse the repository at this point in the history
Signed-off-by: Connor Catlett <[email protected]>
  • Loading branch information
ConnorJC3 committed Apr 19, 2024
1 parent 64772f0 commit 88e1b6b
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 6 deletions.
2 changes: 1 addition & 1 deletion cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ func main() {

if options.HttpEndpoint != "" {
r := metrics.InitializeRecorder()
r.InitializeMetricsHandler(options.HttpEndpoint, "/metrics")
r.InitializeMetricsHandler(options.HttpEndpoint, "/metrics", options.MetricsCertFile, options.MetricsKeyFile)
}

cfg := metadata.MetadataServiceConfig{
Expand Down
23 changes: 21 additions & 2 deletions pkg/driver/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ type Options struct {
Endpoint string
// HttpEndpoint is the TCP network address where the HTTP server for metrics will listen
HttpEndpoint string
// MetricsCertFile is the location of the certificate for serving the metrics server over HTTPS
MetricsCertFile string
// MetricsKeyFile is the location of the key for serving the metrics server over HTTPS
MetricsKeyFile string
// EnableOtelTracing is a flag to enable opentelemetry tracing for the driver
EnableOtelTracing bool

Expand Down Expand Up @@ -83,6 +87,8 @@ func (o *Options) AddFlags(f *flag.FlagSet) {
// Server options
f.StringVar(&o.Endpoint, "endpoint", DefaultCSIEndpoint, "Endpoint for the CSI driver server")
f.StringVar(&o.HttpEndpoint, "http-endpoint", "", "The TCP network address where the HTTP server for metrics will listen (example: `:8080`). The default is empty string, which means the server is disabled.")
f.StringVar(&o.MetricsCertFile, "metrics-cert-file", "", "The path to a certificate to use for serving the metrics server over HTTPS. If the certificate is signed by a certificate authority, this file should be the concatenation of the server's certificate, any intermediates, and the CA's certificate. If this is non-empty, --http-endpoint and --metrics-key-file MUST also be non-empty.")
f.StringVar(&o.MetricsKeyFile, "metrics-key-file", "", "The path to a key to use for serving the metrics server over HTTPS. If this is non-empty, --http-endpoint and --metrics-cert-file MUST also be non-empty.")
f.BoolVar(&o.EnableOtelTracing, "enable-otel-tracing", false, "To enable opentelemetry tracing for the driver. The tracing is disabled by default. Configure the exporter endpoint with OTEL_EXPORTER_OTLP_ENDPOINT and other env variables, see https://opentelemetry.io/docs/specs/otel/configuration/sdk-environment-variables/#general-sdk-configuration.")

// Controller options
Expand All @@ -104,8 +110,21 @@ func (o *Options) AddFlags(f *flag.FlagSet) {
}

func (o *Options) Validate() error {
if o.VolumeAttachLimit != -1 && o.ReservedVolumeAttachments != -1 {
return fmt.Errorf("only one of --volume-attach-limit and --reserved-volume-attachments may be specified")
if o.Mode == AllMode || o.Mode == NodeMode {
if o.VolumeAttachLimit != -1 && o.ReservedVolumeAttachments != -1 {
return fmt.Errorf("only one of --volume-attach-limit and --reserved-volume-attachments may be specified")
}
}

if o.MetricsCertFile != "" || o.MetricsKeyFile != "" {
if o.HttpEndpoint == "" {
return fmt.Errorf("--http-endpoint MUST be specififed when using the metrics server with HTTPS")
} else if o.MetricsCertFile == "" {
return fmt.Errorf("--metrics-cert-file MUST be specififed when using the metrics server with HTTPS")
} else if o.MetricsKeyFile == "" {
return fmt.Errorf("--metrics-key-file MUST be specififed when using the metrics server with HTTPS")
}
}

return nil
}
67 changes: 66 additions & 1 deletion pkg/driver/options_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@ func TestAddFlags(t *testing.T) {
if err := f.Set("http-endpoint", ":8080"); err != nil {
t.Errorf("error setting http-endpoint: %v", err)
}
if err := f.Set("metrics-cert-file", "/https.crt"); err != nil {
t.Errorf("error setting metrics-cert-file: %v", err)
}
if err := f.Set("metrics-key-file", "/https.key"); err != nil {
t.Errorf("error setting metrics-key-file: %v", err)
}
if err := f.Set("enable-otel-tracing", "true"); err != nil {
t.Errorf("error setting enable-otel-tracing: %v", err)
}
Expand Down Expand Up @@ -89,7 +95,7 @@ func TestAddFlags(t *testing.T) {
}
}

func TestValidate(t *testing.T) {
func TestValidateAttachmentLimits(t *testing.T) {
tests := []struct {
name string
volumeAttachLimit int64
Expand Down Expand Up @@ -127,6 +133,7 @@ func TestValidate(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
o := &Options{
Mode: NodeMode,
VolumeAttachLimit: tt.volumeAttachLimit,
ReservedVolumeAttachments: tt.reservedAttachments,
}
Expand All @@ -142,3 +149,61 @@ func TestValidate(t *testing.T) {
})
}
}

func TestValidateMetricsHTTPS(t *testing.T) {
tests := []struct {
name string
httpEndpoint string
metricsCertFile string
metricsKeyFile string
expectError bool
}{
{
name: "disabled",
},
{
name: "only http",
httpEndpoint: ":8080",
},
{
name: "https with all",
httpEndpoint: ":443",
metricsCertFile: "/https.crt",
metricsKeyFile: "/https.key",
},
{
name: "https with endpoint missing",
metricsCertFile: "/https.crt",
metricsKeyFile: "/https.key",
expectError: true,
},
{
name: "https with cert missing",
httpEndpoint: ":443",
metricsKeyFile: "/https.key",
expectError: true,
},
{
name: "https with key missing",
httpEndpoint: ":443",
metricsCertFile: "/https.crt",
expectError: true,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
o := &Options{
Mode: ControllerMode,
HttpEndpoint: tt.httpEndpoint,
MetricsCertFile: tt.metricsCertFile,
MetricsKeyFile: tt.metricsKeyFile,
}

err := o.Validate()
if (err != nil) != tt.expectError {
t.Errorf("Options.Validate() error = %v, wantErr %v", err, tt.expectError)
}
})
}
}
11 changes: 9 additions & 2 deletions pkg/metrics/metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ func (m *metricRecorder) ObserveHistogram(name string, value float64, labels map
}

// InitializeMetricsHandler starts a new HTTP server to expose the metrics.
func (m *metricRecorder) InitializeMetricsHandler(address, path string) {
func (m *metricRecorder) InitializeMetricsHandler(address, path, certFile, keyFile string) {
if m == nil {
klog.InfoS("InitializeMetricsHandler: metric recorder is not initialized")
return
Expand All @@ -92,9 +92,16 @@ func (m *metricRecorder) InitializeMetricsHandler(address, path string) {
}

go func() {
var err error
klog.InfoS("Metric server listening", "address", address, "path", path)

if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
if certFile != "" {
err = server.ListenAndServeTLS(certFile, keyFile)
} else {
err = server.ListenAndServe()
}

if err != nil && err != http.ErrServerClosed {
klog.ErrorS(err, "Failed to start metric server", "address", address, "path", path)
klog.FlushAndExit(klog.ExitFlushTimeout, 1)
}
Expand Down

0 comments on commit 88e1b6b

Please sign in to comment.