github.com/aporeto-inc/trireme-lib@v10.358.0+incompatible/controller/pkg/remoteenforcer/internal/client/reportsclient/client.go (about)

     1  package reports
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"os"
     7  
     8  	"go.aporeto.io/enforcerd/trireme-lib/controller/constants"
     9  	"go.aporeto.io/enforcerd/trireme-lib/controller/internal/enforcer/utils/rpcwrapper"
    10  	"go.aporeto.io/enforcerd/trireme-lib/controller/pkg/remoteenforcer/internal/client"
    11  	"go.aporeto.io/enforcerd/trireme-lib/controller/pkg/remoteenforcer/internal/statscollector"
    12  	"go.uber.org/zap"
    13  )
    14  
    15  const (
    16  	reportContextID  = "UNUSED"
    17  	reportRPCCommand = "ProxyRPCServer.PostReportEvent"
    18  )
    19  
    20  // reportClient  This is the struct for storing state for the rpc client
    21  // which reports events back to the controller process
    22  type reportsClient struct {
    23  	collector     statscollector.Collector
    24  	rpchdl        *rpcwrapper.RPCWrapper
    25  	secret        string
    26  	reportChannel string
    27  	stop          chan bool
    28  }
    29  
    30  // NewClient initializes a new ping report client
    31  func NewClient(cr statscollector.Collector) (client.Reporter, error) {
    32  
    33  	p := &reportsClient{
    34  		collector:     cr,
    35  		rpchdl:        rpcwrapper.NewRPCWrapper(),
    36  		secret:        os.Getenv(constants.EnvStatsSecret),
    37  		reportChannel: os.Getenv(constants.EnvStatsChannel),
    38  		stop:          make(chan bool),
    39  	}
    40  
    41  	if p.reportChannel == "" {
    42  		return nil, errors.New("no path to stats socket provided")
    43  	}
    44  
    45  	if p.secret == "" {
    46  		return nil, errors.New("no secret provided for stats channel")
    47  	}
    48  
    49  	return p, nil
    50  }
    51  
    52  func (p *reportsClient) sendStats(ctx context.Context) {
    53  
    54  	for {
    55  		select {
    56  		case <-ctx.Done():
    57  			return
    58  		case r := <-p.collector.GetReports():
    59  			p.sendRequest(r)
    60  		}
    61  	}
    62  }
    63  
    64  func (p *reportsClient) sendRequest(report *statscollector.Report) {
    65  
    66  	request := rpcwrapper.Request{
    67  		PayloadType: reportTypeToPayloadType(report.Type),
    68  		Payload:     report.Payload,
    69  	}
    70  
    71  	if err := p.rpchdl.RemoteCall(
    72  		reportContextID,
    73  		reportRPCCommand,
    74  		&request,
    75  		&rpcwrapper.Response{},
    76  	); err != nil {
    77  		zap.L().Error("unable to execute rpc", zap.Error(err))
    78  	}
    79  }
    80  
    81  // Start This is an private function called by the remoteenforcer to connect back
    82  // to the controller over a stats channel
    83  func (p *reportsClient) Run(ctx context.Context) error {
    84  	if err := p.rpchdl.NewRPCClient(reportContextID, p.reportChannel, p.secret); err != nil {
    85  		zap.L().Error("unable to create new rpc client", zap.Error(err))
    86  		return err
    87  	}
    88  
    89  	go p.sendStats(ctx)
    90  
    91  	return nil
    92  }
    93  
    94  // Send is unimplemented.
    95  func (p *reportsClient) Send() error {
    96  	return nil
    97  }
    98  
    99  func reportTypeToPayloadType(rtype statscollector.ReportType) (ptype rpcwrapper.PayloadType) {
   100  
   101  	switch rtype {
   102  	case statscollector.PacketReport:
   103  		ptype = rpcwrapper.PacketReport
   104  	case statscollector.CounterReport:
   105  		ptype = rpcwrapper.CounterReport
   106  	case statscollector.DNSReport:
   107  		ptype = rpcwrapper.DNSReport
   108  	case statscollector.PingReport:
   109  		ptype = rpcwrapper.PingReport
   110  	case statscollector.ConnectionExceptionReport:
   111  		ptype = rpcwrapper.ConnectionExceptionReport
   112  	default:
   113  		return
   114  	}
   115  
   116  	return ptype
   117  }