github.com/Uptycs/basequery-go@v0.8.0/client.go (about)

     1  package osquery
     2  
     3  import (
     4  	"context"
     5  	"time"
     6  
     7  	"github.com/Uptycs/basequery-go/gen/osquery"
     8  	"github.com/Uptycs/basequery-go/transport"
     9  	"github.com/pkg/errors"
    10  
    11  	"github.com/apache/thrift/lib/go/thrift"
    12  )
    13  
    14  // ExtensionManager is the interface for thrift bindings supported by basequery
    15  type ExtensionManager interface {
    16  	Close()
    17  	Ping() (*osquery.ExtensionStatus, error)
    18  	Call(registry, item string, req osquery.ExtensionPluginRequest) (*osquery.ExtensionResponse, error)
    19  	Extensions() (osquery.InternalExtensionList, error)
    20  	RegisterExtension(info *osquery.InternalExtensionInfo, registry osquery.ExtensionRegistry) (*osquery.ExtensionStatus, error)
    21  	Options() (osquery.InternalOptionList, error)
    22  	Query(sql string) (*osquery.ExtensionResponse, error)
    23  	GetQueryColumns(sql string) (*osquery.ExtensionResponse, error)
    24  	StreamEvents(name string, events osquery.ExtensionPluginResponse) (*osquery.ExtensionStatus, error)
    25  	GetNodeKey() (string, error)
    26  }
    27  
    28  // ExtensionManagerClient is a wrapper for the osquery Thrift extensions API.
    29  type ExtensionManagerClient struct {
    30  	Client    osquery.ExtensionManager
    31  	transport thrift.TTransport
    32  }
    33  
    34  // NewClient creates a new client communicating to osquery over the socket at
    35  // the provided path. If resolving the address or connecting to the socket
    36  // fails, this function will error.
    37  func NewClient(path string, timeout time.Duration) (*ExtensionManagerClient, error) {
    38  	trans, err := transport.Open(path, timeout)
    39  	if err != nil {
    40  		return nil, err
    41  	}
    42  
    43  	client := osquery.NewExtensionManagerClientFactory(
    44  		trans,
    45  		thrift.NewTBinaryProtocolFactoryDefault(),
    46  	)
    47  
    48  	return &ExtensionManagerClient{client, trans}, nil
    49  }
    50  
    51  // Close should be called to close the transport when use of the client is
    52  // completed.
    53  func (c *ExtensionManagerClient) Close() {
    54  	if c.transport != nil && c.transport.IsOpen() {
    55  		c.transport.Close()
    56  	}
    57  }
    58  
    59  // Ping requests metadata from the extension manager.
    60  func (c *ExtensionManagerClient) Ping() (*osquery.ExtensionStatus, error) {
    61  	return c.Client.Ping(context.Background())
    62  }
    63  
    64  // Call requests a call to an extension (or core) registry plugin.
    65  func (c *ExtensionManagerClient) Call(registry, item string, request osquery.ExtensionPluginRequest) (*osquery.ExtensionResponse, error) {
    66  	return c.Client.Call(context.Background(), registry, item, request)
    67  }
    68  
    69  // Extensions requests the list of active registered extensions.
    70  func (c *ExtensionManagerClient) Extensions() (osquery.InternalExtensionList, error) {
    71  	return c.Client.Extensions(context.Background())
    72  }
    73  
    74  // RegisterExtension registers the extension plugins with the osquery process.
    75  func (c *ExtensionManagerClient) RegisterExtension(info *osquery.InternalExtensionInfo, registry osquery.ExtensionRegistry) (*osquery.ExtensionStatus, error) {
    76  	return c.Client.RegisterExtension(context.Background(), info, registry)
    77  }
    78  
    79  // Options requests the list of bootstrap or configuration options.
    80  func (c *ExtensionManagerClient) Options() (osquery.InternalOptionList, error) {
    81  	return c.Client.Options(context.Background())
    82  }
    83  
    84  // Query requests a query to be run and returns the extension response.
    85  // Consider using the QueryRow or QueryRows helpers for a more friendly
    86  // interface.
    87  func (c *ExtensionManagerClient) Query(sql string) (*osquery.ExtensionResponse, error) {
    88  	return c.Client.Query(context.Background(), sql)
    89  }
    90  
    91  // QueryRows is a helper that executes the requested query and returns the
    92  // results. It handles checking both the transport level errors and the osquery
    93  // internal errors by returning a normal Go error type.
    94  func (c *ExtensionManagerClient) QueryRows(sql string) ([]map[string]string, error) {
    95  	res, err := c.Query(sql)
    96  	if err != nil {
    97  		return nil, errors.Wrap(err, "transport error in query")
    98  	}
    99  	if res.Status == nil {
   100  		return nil, errors.New("query returned nil status")
   101  	}
   102  	if res.Status.Code != 0 {
   103  		return nil, errors.Errorf("query returned error: %s", res.Status.Message)
   104  	}
   105  	return res.Response, nil
   106  
   107  }
   108  
   109  // QueryRow behaves similarly to QueryRows, but it returns an error if the
   110  // query does not return exactly one row.
   111  func (c *ExtensionManagerClient) QueryRow(sql string) (map[string]string, error) {
   112  	res, err := c.QueryRows(sql)
   113  	if err != nil {
   114  		return nil, err
   115  	}
   116  	if len(res) != 1 {
   117  		return nil, errors.Errorf("expected 1 row, got %d", len(res))
   118  	}
   119  	return res[0], nil
   120  }
   121  
   122  // GetQueryColumns requests the columns returned by the parsed query.
   123  func (c *ExtensionManagerClient) GetQueryColumns(sql string) (*osquery.ExtensionResponse, error) {
   124  	return c.Client.GetQueryColumns(context.Background(), sql)
   125  }
   126  
   127  // StreamEvents sends a batch of events for a event'ed table.
   128  func (c *ExtensionManagerClient) StreamEvents(name string, events osquery.ExtensionPluginResponse) (*osquery.ExtensionStatus, error) {
   129  	return c.Client.StreamEvents(context.Background(), name, events)
   130  }
   131  
   132  // GetNodeKey returns TLS node key when enroll plugin is set to "tls".
   133  func (c *ExtensionManagerClient) GetNodeKey() (string, error) {
   134  	return c.Client.GetNodeKey(context.Background())
   135  }