github.com/grafana/synthetic-monitoring-agent@v0.64.2/internal/tls/tls.go (about)

     1  package tls
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"os"
     7  
     8  	sm "github.com/grafana/synthetic-monitoring-agent/pkg/pb/synthetic_monitoring"
     9  	promconfig "github.com/prometheus/common/config"
    10  	"github.com/rs/zerolog"
    11  )
    12  
    13  func SMtoProm(ctx context.Context, logger zerolog.Logger, tlsConfig *sm.TLSConfig) (promconfig.TLSConfig, error) {
    14  	c := promconfig.TLSConfig{
    15  		InsecureSkipVerify: tlsConfig.InsecureSkipVerify,
    16  		ServerName:         tlsConfig.ServerName,
    17  	}
    18  
    19  	if len(tlsConfig.CACert) > 0 {
    20  		fn, err := newDataProvider(ctx, logger, "ca_cert", tlsConfig.CACert)
    21  		if err != nil {
    22  			return promconfig.TLSConfig{}, err
    23  		}
    24  
    25  		c.CAFile = fn
    26  	}
    27  
    28  	if len(tlsConfig.ClientCert) > 0 {
    29  		fn, err := newDataProvider(ctx, logger, "client_cert", tlsConfig.ClientCert)
    30  		if err != nil {
    31  			return promconfig.TLSConfig{}, err
    32  		}
    33  
    34  		c.CertFile = fn
    35  	}
    36  
    37  	if len(tlsConfig.ClientKey) > 0 {
    38  		fn, err := newDataProvider(ctx, logger, "client_key", tlsConfig.ClientKey)
    39  		if err != nil {
    40  			return promconfig.TLSConfig{}, err
    41  		}
    42  
    43  		c.KeyFile = fn
    44  	}
    45  
    46  	return c, nil
    47  }
    48  
    49  // newDataProvider creates a filesystem object that provides the
    50  // specified data as often as needed. It returns the name under which
    51  // the data can be accessed.
    52  //
    53  // It does NOT try to make guarantees about partial reads. If the reader
    54  // goes away before reaching the end of the data, the next time the
    55  // reader shows up, the writer might continue from the previous
    56  // prosition.
    57  func newDataProvider(ctx context.Context, logger zerolog.Logger, basename string, data []byte) (string, error) {
    58  	fh, err := os.CreateTemp("", basename+".")
    59  	if err != nil {
    60  		logger.Error().Err(err).Str("basename", basename).Msg("creating temporary file")
    61  		return "", fmt.Errorf("creating temporary file: %w", err)
    62  	}
    63  
    64  	defer func() {
    65  		if err := fh.Close(); err != nil {
    66  			// close errors should never happen, but if they
    67  			// do, the most we can do is log them to be able
    68  			// to debug the issue.
    69  			logger.Error().Err(err).Str("filename", fh.Name()).Msg("closing temporary file")
    70  		}
    71  	}()
    72  
    73  	fn := fh.Name()
    74  
    75  	if n, err := fh.Write(data); err != nil {
    76  		logger.Error().Err(err).Str("filename", fn).Int("bytes", n).Int("data", len(data)).Msg("writing temporary file")
    77  		return "", fmt.Errorf("writing temporary file for %s: %w", basename, err)
    78  	}
    79  
    80  	// play nice and make sure this file gets deleted once the
    81  	// context is cancelled, which could be when the program is
    82  	// shutting down or when the scraper stops.
    83  	go func() {
    84  		<-ctx.Done()
    85  
    86  		if err := os.Remove(fn); err != nil {
    87  			logger.Error().Err(err).Str("filename", fn).Msg("removing temporary file")
    88  		}
    89  	}()
    90  
    91  	return fn, nil
    92  }