@@ -6,32 +6,76 @@ import (
6
6
7
7
"github.com/osquery/osquery-go/gen/osquery"
8
8
"github.com/osquery/osquery-go/transport"
9
- "github.com/pkg/errors"
10
9
11
10
"github.com/apache/thrift/lib/go/thrift"
11
+ "github.com/pkg/errors"
12
+ )
13
+
14
+ const (
15
+ defaultWaitTime = 200 * time .Millisecond
16
+ defaultMaxWaitTime = 1 * time .Minute
12
17
)
13
18
14
19
// ExtensionManagerClient is a wrapper for the osquery Thrift extensions API.
15
20
type ExtensionManagerClient struct {
16
- Client osquery.ExtensionManager
21
+ client osquery.ExtensionManager
17
22
transport thrift.TTransport
23
+
24
+ waitTime time.Duration
25
+ maxWaitTime time.Duration
26
+ lock * locker
27
+ }
28
+
29
+ type ClientOption func (* ExtensionManagerClient )
30
+
31
+ // WaitTime sets the default amount of wait time for the osquery socket to free up. You can override this on a per
32
+ // call basis by setting a context deadline
33
+ func DefaultWaitTime (d time.Duration ) ClientOption {
34
+ return func (c * ExtensionManagerClient ) {
35
+ c .waitTime = d
36
+ }
37
+ }
38
+
39
+ // MaxWaitTime is the maximum amount of time something is allowed to wait for the osquery socket. This takes precedence
40
+ // over the context deadline.
41
+ func MaxWaitTime (d time.Duration ) ClientOption {
42
+ return func (c * ExtensionManagerClient ) {
43
+ c .maxWaitTime = d
44
+ }
18
45
}
19
46
20
47
// NewClient creates a new client communicating to osquery over the socket at
21
48
// the provided path. If resolving the address or connecting to the socket
22
49
// fails, this function will error.
23
- func NewClient (path string , timeout time.Duration ) (* ExtensionManagerClient , error ) {
24
- trans , err := transport . Open ( path , timeout )
25
- if err != nil {
26
- return nil , err
50
+ func NewClient (path string , socketOpenTimeout time.Duration , opts ... ClientOption ) (* ExtensionManagerClient , error ) {
51
+ c := & ExtensionManagerClient {
52
+ waitTime : defaultWaitTime ,
53
+ maxWaitTime : defaultMaxWaitTime ,
27
54
}
28
55
29
- client := osquery .NewExtensionManagerClientFactory (
30
- trans ,
31
- thrift .NewTBinaryProtocolFactoryDefault (),
32
- )
56
+ for _ , opt := range opts {
57
+ opt (c )
58
+ }
33
59
34
- return & ExtensionManagerClient {client , trans }, nil
60
+ if c .waitTime > c .maxWaitTime {
61
+ return nil , errors .New ("default wait time larger than max wait time" )
62
+ }
63
+
64
+ c .lock = NewLocker (c .waitTime , c .maxWaitTime )
65
+
66
+ if c .client == nil {
67
+ trans , err := transport .Open (path , socketOpenTimeout )
68
+ if err != nil {
69
+ return nil , err
70
+ }
71
+
72
+ c .client = osquery .NewExtensionManagerClientFactory (
73
+ trans ,
74
+ thrift .NewTBinaryProtocolFactoryDefault (),
75
+ )
76
+ }
77
+
78
+ return c , nil
35
79
}
36
80
37
81
// Close should be called to close the transport when use of the client is
@@ -42,48 +86,120 @@ func (c *ExtensionManagerClient) Close() {
42
86
}
43
87
}
44
88
45
- // Ping requests metadata from the extension manager.
89
+ // Ping requests metadata from the extension manager, using a new background context
46
90
func (c * ExtensionManagerClient ) Ping () (* osquery.ExtensionStatus , error ) {
47
- return c .Client . Ping (context .Background ())
91
+ return c .PingContext (context .Background ())
48
92
}
49
93
50
- // Call requests a call to an extension (or core) registry plugin.
94
+ // PingContext requests metadata from the extension manager.
95
+ func (c * ExtensionManagerClient ) PingContext (ctx context.Context ) (* osquery.ExtensionStatus , error ) {
96
+ if err := c .lock .Lock (ctx ); err != nil {
97
+ return nil , err
98
+ }
99
+ defer c .lock .Unlock ()
100
+ return c .client .Ping (ctx )
101
+ }
102
+
103
+ // Call requests a call to an extension (or core) registry plugin, using a new background context
51
104
func (c * ExtensionManagerClient ) Call (registry , item string , request osquery.ExtensionPluginRequest ) (* osquery.ExtensionResponse , error ) {
52
- return c .Client . Call (context .Background (), registry , item , request )
105
+ return c .CallContext (context .Background (), registry , item , request )
53
106
}
54
107
55
- // Extensions requests the list of active registered extensions.
108
+ // CallContext requests a call to an extension (or core) registry plugin.
109
+ func (c * ExtensionManagerClient ) CallContext (ctx context.Context , registry , item string , request osquery.ExtensionPluginRequest ) (* osquery.ExtensionResponse , error ) {
110
+ if err := c .lock .Lock (ctx ); err != nil {
111
+ return nil , err
112
+ }
113
+ defer c .lock .Unlock ()
114
+ return c .client .Call (ctx , registry , item , request )
115
+ }
116
+
117
+ // Extensions requests the list of active registered extensions, using a new background context
56
118
func (c * ExtensionManagerClient ) Extensions () (osquery.InternalExtensionList , error ) {
57
- return c .Client .Extensions (context .Background ())
119
+ return c .ExtensionsContext (context .Background ())
120
+ }
121
+
122
+ // ExtensionsContext requests the list of active registered extensions.
123
+ func (c * ExtensionManagerClient ) ExtensionsContext (ctx context.Context ) (osquery.InternalExtensionList , error ) {
124
+ if err := c .lock .Lock (ctx ); err != nil {
125
+ return nil , err
126
+ }
127
+ defer c .lock .Unlock ()
128
+ return c .client .Extensions (ctx )
58
129
}
59
130
60
- // RegisterExtension registers the extension plugins with the osquery process.
131
+ // RegisterExtension registers the extension plugins with the osquery process, using a new background context
61
132
func (c * ExtensionManagerClient ) RegisterExtension (info * osquery.InternalExtensionInfo , registry osquery.ExtensionRegistry ) (* osquery.ExtensionStatus , error ) {
62
- return c .Client .RegisterExtension (context .Background (), info , registry )
133
+ return c .RegisterExtensionContext (context .Background (), info , registry )
134
+ }
135
+
136
+ // RegisterExtensionContext registers the extension plugins with the osquery process.
137
+ func (c * ExtensionManagerClient ) RegisterExtensionContext (ctx context.Context , info * osquery.InternalExtensionInfo , registry osquery.ExtensionRegistry ) (* osquery.ExtensionStatus , error ) {
138
+ if err := c .lock .Lock (ctx ); err != nil {
139
+ return nil , err
140
+ }
141
+ defer c .lock .Unlock ()
142
+ return c .client .RegisterExtension (ctx , info , registry )
63
143
}
64
144
65
- // DeregisterExtension de-registers the extension plugins with the osquery process.
145
+ // DeregisterExtension de-registers the extension plugins with the osquery process, using a new background context
66
146
func (c * ExtensionManagerClient ) DeregisterExtension (uuid osquery.ExtensionRouteUUID ) (* osquery.ExtensionStatus , error ) {
67
- return c .Client .DeregisterExtension (context .Background (), uuid )
147
+ return c .DeregisterExtensionContext (context .Background (), uuid )
148
+ }
149
+
150
+ // DeregisterExtensionContext de-registers the extension plugins with the osquery process.
151
+ func (c * ExtensionManagerClient ) DeregisterExtensionContext (ctx context.Context , uuid osquery.ExtensionRouteUUID ) (* osquery.ExtensionStatus , error ) {
152
+ if err := c .lock .Lock (ctx ); err != nil {
153
+ return nil , err
154
+ }
155
+ defer c .lock .Unlock ()
156
+ return c .client .DeregisterExtension (ctx , uuid )
68
157
}
69
158
70
- // Options requests the list of bootstrap or configuration options.
159
+ // Options requests the list of bootstrap or configuration options, using a new background context .
71
160
func (c * ExtensionManagerClient ) Options () (osquery.InternalOptionList , error ) {
72
- return c .Client .Options (context .Background ())
161
+ return c .OptionsContext (context .Background ())
162
+ }
163
+
164
+ // OptionsContext requests the list of bootstrap or configuration options.
165
+ func (c * ExtensionManagerClient ) OptionsContext (ctx context.Context ) (osquery.InternalOptionList , error ) {
166
+ if err := c .lock .Lock (ctx ); err != nil {
167
+ return nil , err
168
+ }
169
+ defer c .lock .Unlock ()
170
+ return c .client .Options (ctx )
73
171
}
74
172
75
- // Query requests a query to be run and returns the extension response.
173
+ // Query requests a query to be run and returns the extension
174
+ // response, using a new background context. Consider using the
175
+ // QueryRow or QueryRows helpers for a more friendly interface.
176
+ func (c * ExtensionManagerClient ) Query (sql string ) (* osquery.ExtensionResponse , error ) {
177
+ return c .QueryContext (context .Background (), sql )
178
+ }
179
+
180
+ // QueryContext requests a query to be run and returns the extension response.
76
181
// Consider using the QueryRow or QueryRows helpers for a more friendly
77
182
// interface.
78
- func (c * ExtensionManagerClient ) Query (sql string ) (* osquery.ExtensionResponse , error ) {
79
- return c .Client .Query (context .Background (), sql )
183
+ func (c * ExtensionManagerClient ) QueryContext (ctx context.Context , sql string ) (* osquery.ExtensionResponse , error ) {
184
+ if err := c .lock .Lock (ctx ); err != nil {
185
+ return nil , err
186
+ }
187
+ defer c .lock .Unlock ()
188
+ return c .client .Query (ctx , sql )
80
189
}
81
190
82
191
// QueryRows is a helper that executes the requested query and returns the
83
192
// results. It handles checking both the transport level errors and the osquery
84
193
// internal errors by returning a normal Go error type.
85
194
func (c * ExtensionManagerClient ) QueryRows (sql string ) ([]map [string ]string , error ) {
86
- res , err := c .Query (sql )
195
+ return c .QueryRowsContext (context .Background (), sql )
196
+ }
197
+
198
+ // QueryRowsContext is a helper that executes the requested query and returns the
199
+ // results. It handles checking both the transport level errors and the osquery
200
+ // internal errors by returning a normal Go error type.
201
+ func (c * ExtensionManagerClient ) QueryRowsContext (ctx context.Context , sql string ) ([]map [string ]string , error ) {
202
+ res , err := c .QueryContext (ctx , sql )
87
203
if err != nil {
88
204
return nil , errors .Wrap (err , "transport error in query" )
89
205
}
@@ -100,7 +216,13 @@ func (c *ExtensionManagerClient) QueryRows(sql string) ([]map[string]string, err
100
216
// QueryRow behaves similarly to QueryRows, but it returns an error if the
101
217
// query does not return exactly one row.
102
218
func (c * ExtensionManagerClient ) QueryRow (sql string ) (map [string ]string , error ) {
103
- res , err := c .QueryRows (sql )
219
+ return c .QueryRowContext (context .Background (), sql )
220
+ }
221
+
222
+ // QueryRowContext behaves similarly to QueryRows, but it returns an error if the
223
+ // query does not return exactly one row.
224
+ func (c * ExtensionManagerClient ) QueryRowContext (ctx context.Context , sql string ) (map [string ]string , error ) {
225
+ res , err := c .QueryRowsContext (ctx , sql )
104
226
if err != nil {
105
227
return nil , err
106
228
}
@@ -110,7 +232,16 @@ func (c *ExtensionManagerClient) QueryRow(sql string) (map[string]string, error)
110
232
return res [0 ], nil
111
233
}
112
234
113
- // GetQueryColumns requests the columns returned by the parsed query.
235
+ // GetQueryColumns requests the columns returned by the parsed query, using a new background context .
114
236
func (c * ExtensionManagerClient ) GetQueryColumns (sql string ) (* osquery.ExtensionResponse , error ) {
115
- return c .Client .GetQueryColumns (context .Background (), sql )
237
+ return c .GetQueryColumnsContext (context .Background (), sql )
238
+ }
239
+
240
+ // GetQueryColumnsContext requests the columns returned by the parsed query.
241
+ func (c * ExtensionManagerClient ) GetQueryColumnsContext (ctx context.Context , sql string ) (* osquery.ExtensionResponse , error ) {
242
+ if err := c .lock .Lock (ctx ); err != nil {
243
+ return nil , err
244
+ }
245
+ defer c .lock .Unlock ()
246
+ return c .client .GetQueryColumns (ctx , sql )
116
247
}
0 commit comments