Skip to content

Commit d17198d

Browse files
omerazrDavide Schiera
authored andcommitted
Add support for Sysdig Secure compliance tasks (#77)
As well as adding support to fetch policy events by id.
1 parent 596543a commit d17198d

File tree

4 files changed

+353
-178
lines changed

4 files changed

+353
-178
lines changed

sdcclient/_common.py

Lines changed: 76 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,7 @@ def get_user_info(self):
6666
`examples/print_user_info.py <https://github.com/draios/python-sdc-client/blob/master/examples/print_user_info.py>`_
6767
'''
6868
res = requests.get(self.url + '/api/user/me', headers=self.hdrs, verify=self.ssl_verify)
69-
if not self._checkResponse(res):
70-
return [False, self.lasterr]
71-
return [True, res.json()]
69+
return self._request_result(res)
7270

7371
def get_user_token(self):
7472
'''**Description**
@@ -203,9 +201,7 @@ def create_email_notification_channel(self, channel_name, email_recipients):
203201
}
204202

205203
res = requests.post(self.url + '/api/notificationChannels', headers=self.hdrs, data=json.dumps(channel_json), verify=self.ssl_verify)
206-
if not self._checkResponse(res):
207-
return [False, self.lasterr]
208-
return [True, res.json()]
204+
return self._request_result(res)
209205

210206
def get_notification_channel(self, id):
211207

@@ -220,10 +216,7 @@ def update_notification_channel(self, channel):
220216
return [False, "Invalid channel format"]
221217

222218
res = requests.put(self.url + '/api/notificationChannels/' + str(channel['id']), headers=self.hdrs, data=json.dumps({"notificationChannel": channel}), verify=self.ssl_verify)
223-
if not self._checkResponse(res):
224-
return [False, self.lasterr]
225-
226-
return [True, res.json()]
219+
return self._request_result(res)
227220

228221
def delete_notification_channel(self, channel):
229222
if 'id' not in channel:
@@ -245,9 +238,7 @@ def get_data_retention_info(self):
245238
`examples/print_data_retention_info.py <https://github.com/draios/python-sdc-client/blob/master/examples/print_data_retention_info.py>`_
246239
'''
247240
res = requests.get(self.url + '/api/history/timelines/', headers=self.hdrs, verify=self.ssl_verify)
248-
if not self._checkResponse(res):
249-
return [False, self.lasterr]
250-
return [True, res.json()]
241+
return self._request_result(res)
251242

252243
def get_topology_map(self, grouping_hierarchy, time_window_s, sampling_time_s):
253244
#
@@ -326,9 +317,7 @@ def get_topology_map(self, grouping_hierarchy, time_window_s, sampling_time_s):
326317
#
327318
res = requests.post(self.url + '/api/data?format=map', headers=self.hdrs,
328319
data=json.dumps(req_json), verify=self.ssl_verify)
329-
if not self._checkResponse(res):
330-
return [False, self.lasterr]
331-
return [True, res.json()]
320+
return self._request_result(res)
332321

333322
def post_event(self, name, description=None, severity=None, event_filter=None, tags=None):
334323
'''**Description**
@@ -348,28 +337,18 @@ def post_event(self, name, description=None, severity=None, event_filter=None, t
348337
- `examples/post_event_simple.py <https://github.com/draios/python-sdc-client/blob/master/examples/post_event_simple.py>`_
349338
- `examples/post_event.py <https://github.com/draios/python-sdc-client/blob/master/examples/post_event.py>`_
350339
'''
340+
options = {
341+
'name': name,
342+
'description': description,
343+
'severity': severity,
344+
'filter': event_filter,
345+
'tags': tags
346+
}
351347
edata = {
352-
'event': {
353-
'name': name
354-
}
348+
'event': {k: v for k, v in options.items() if v is not None}
355349
}
356-
357-
if description is not None:
358-
edata['event']['description'] = description
359-
360-
if severity is not None:
361-
edata['event']['severity'] = severity
362-
363-
if event_filter is not None:
364-
edata['event']['filter'] = event_filter
365-
366-
if tags is not None:
367-
edata['event']['tags'] = tags
368-
369350
res = requests.post(self.url + '/api/events/', headers=self.hdrs, data=json.dumps(edata), verify=self.ssl_verify)
370-
if not self._checkResponse(res):
371-
return [False, self.lasterr]
372-
return [True, res.json()]
351+
return self._request_result(res)
373352

374353
def get_events(self, name=None, from_ts=None, to_ts=None, tags=None):
375354
'''**Description**
@@ -387,24 +366,15 @@ def get_events(self, name=None, from_ts=None, to_ts=None, tags=None):
387366
**Example**
388367
`examples/list_events.py <https://github.com/draios/python-sdc-client/blob/master/examples/list_events.py>`_
389368
'''
390-
params = {}
391-
392-
if name is not None:
393-
params['name'] = name
394-
395-
if from_ts is not None:
396-
params['from'] = from_ts
397-
398-
if to_ts is not None:
399-
params['to'] = to_ts
400-
401-
if tags is not None:
402-
params['tags'] = tags
403-
369+
options = {
370+
'name': name,
371+
'from': from_ts,
372+
'to': to_ts,
373+
'tags': tags
374+
}
375+
params = {k: v for k, v in options.items() if v is not None}
404376
res = requests.get(self.url + '/api/events/', headers=self.hdrs, params=params, verify=self.ssl_verify)
405-
if not self._checkResponse(res):
406-
return [False, self.lasterr]
407-
return [True, res.json()]
377+
return self._request_result(res)
408378

409379
def delete_event(self, event):
410380
'''**Description**
@@ -473,24 +443,31 @@ def get_data(self, metrics, start_ts, end_ts=0, sampling_s=0,
473443
reqbody['sampling'] = sampling_s
474444

475445
res = requests.post(self.url + '/api/data/', headers=self.hdrs, data=json.dumps(reqbody), verify=self.ssl_verify)
476-
if not self._checkResponse(res):
477-
return [False, self.lasterr]
478-
return [True, res.json()]
446+
return self._request_result(res)
479447

480-
def get_sysdig_captures(self):
448+
def get_sysdig_captures(self, from_sec=None, to_sec=None, scope_filter=None):
481449
'''**Description**
482450
Returns the list of sysdig captures for the user.
483451
452+
**Arguments**
453+
- from_sec: the start of the timerange for which to get the captures
454+
- end_sec: the end of the timerange for which to get the captures
455+
- scope_filter: this is a SysdigMonitor-like filter (e.g 'container.image=ubuntu'). When provided, events are filtered by their scope, so only a subset will be returned (e.g. 'container.image=ubuntu' will provide only events that have happened on an ubuntu container).
456+
484457
**Success Return Value**
485458
A dictionary containing the list of captures.
486459
487460
**Example**
488461
`examples/list_sysdig_captures.py <https://github.com/draios/python-sdc-client/blob/master/examples/list_sysdig_captures.py>`_
489462
'''
490-
res = requests.get(self.url + '/api/sysdig', headers=self.hdrs, verify=self.ssl_verify)
491-
if not self._checkResponse(res):
492-
return [False, self.lasterr]
493-
return [True, res.json()]
463+
url = '{url}/api/sysdig?source={source}{frm}{to}{scopeFilter}'.format(
464+
url=self.url,
465+
source=self.product,
466+
frm="&from=%d" % (from_sec * 10**6) if from_sec else "",
467+
to="&to=%d" % (to_sec * 10**6) if to_sec else "",
468+
scopeFilter="&scopeFilter=%s" % scope_filter if scope_filter else "")
469+
res = requests.get(url, headers=self.hdrs, verify=self.ssl_verify)
470+
return self._request_result(res)
494471

495472
def poll_sysdig_capture(self, capture):
496473
'''**Description**
@@ -508,10 +485,10 @@ def poll_sysdig_capture(self, capture):
508485
if 'id' not in capture:
509486
return [False, 'Invalid capture format']
510487

511-
res = requests.get(self.url + '/api/sysdig/' + str(capture['id']), headers=self.hdrs, verify=self.ssl_verify)
512-
if not self._checkResponse(res):
513-
return [False, self.lasterr]
514-
return [True, res.json()]
488+
url = '{url}/api/sysdig/{id}?source={source}'.format(
489+
url=self.url, id=capture['id'], source=self.product)
490+
res = requests.get(url, headers=self.hdrs, verify=self.ssl_verify)
491+
return self._request_result(res)
515492

516493
def create_sysdig_capture(self, hostname, capture_name, duration, capture_filter='', folder='/'):
517494
'''**Description**
@@ -550,13 +527,30 @@ def create_sysdig_capture(self, hostname, capture_name, duration, capture_filter
550527
'duration': duration,
551528
'folder': folder,
552529
'filters': capture_filter,
553-
'bucketName': ''
530+
'bucketName': '',
531+
'source': self.product
554532
}
555533

556534
res = requests.post(self.url + '/api/sysdig', headers=self.hdrs, data=json.dumps(data), verify=self.ssl_verify)
535+
return self._request_result(res)
536+
537+
def download_sysdig_capture(self, capture_id):
538+
'''**Description**
539+
Download a sysdig capture by id.
540+
541+
**Arguments**
542+
- **capture_id**: the capture id to download.
543+
544+
**Success Return Value**
545+
The bytes of the scap
546+
'''
547+
url = '{url}/api/sysdig/{id}/download?_product={product}'.format(
548+
url=self.url, id=capture_id, product=self.product)
549+
res = requests.get(url, headers=self.hdrs, verify=self.ssl_verify)
557550
if not self._checkResponse(res):
558-
return [False, self.lasterr]
559-
return [True, res.json()]
551+
return False, self.lasterr
552+
553+
return True, res.content
560554

561555
def create_user_invite(self, user_email, first_name=None, last_name=None, system_role=None):
562556
'''**Description**
@@ -586,21 +580,14 @@ def create_user_invite(self, user_email, first_name=None, last_name=None, system
586580
return [False, 'user ' + user_email + ' already exists']
587581

588582
# Create the user
589-
user_json = {'username': user_email}
590-
591-
if first_name is not None:
592-
user_json['firstName'] = first_name
593-
594-
if last_name is not None:
595-
user_json['lastName'] = last_name
596-
597-
if system_role is not None:
598-
user_json['systemRole'] = system_role
583+
options = {'username': user_email,
584+
'firstName': first_name,
585+
'lastName': last_name,
586+
'systemRole': system_role}
587+
user_json = {k: v for k, v in options.items() if v is not None}
599588

600589
res = requests.post(self.url + '/api/users', headers=self.hdrs, data=json.dumps(user_json), verify=self.ssl_verify)
601-
if not self._checkResponse(res):
602-
return [False, self.lasterr]
603-
return [True, res.json()]
590+
return self._request_result(res)
604591

605592
def delete_user(self, user_email):
606593
'''**Description**
@@ -786,9 +773,7 @@ def create_team(self, name, memberships=None, filter='', description='', show='h
786773
reqbody['filter'] = filter
787774

788775
res = requests.post(self.url + '/api/teams', headers=self.hdrs, data=json.dumps(reqbody), verify=self.ssl_verify)
789-
if not self._checkResponse(res):
790-
return [False, self.lasterr]
791-
return [True, res.json()]
776+
return self._request_result(res)
792777

793778
def edit_team(self, name, memberships=None, filter=None, description=None, show=None, theme=None,
794779
perm_capture=None, perm_custom_events=None, perm_aws_data=None):
@@ -859,9 +844,7 @@ def edit_team(self, name, memberships=None, filter=None, description=None, show=
859844
reqbody['filter'] = t['filter']
860845

861846
res = requests.put(self.url + '/api/teams/' + str(t['id']), headers=self.hdrs, data=json.dumps(reqbody), verify=self.ssl_verify)
862-
if not self._checkResponse(res):
863-
return [False, self.lasterr]
864-
return [True, res.json()]
847+
return self._request_result(res)
865848

866849
def delete_team(self, name):
867850
'''**Description**
@@ -977,9 +960,7 @@ def get_agents_config(self):
977960

978961
def set_agents_config(self, config):
979962
res = requests.put(self.url + '/api/agents/config', headers=self.hdrs, data=json.dumps(config), verify=self.ssl_verify)
980-
if not self._checkResponse(res):
981-
return [False, self.lasterr]
982-
return [True, res.json()]
963+
return self._request_result(res)
983964

984965
def clear_agents_config(self):
985966
data = {'files': []}
@@ -997,3 +978,9 @@ def get_user_api_token(self, username, teamname):
997978
return [False, self.lasterr]
998979
data = res.json()
999980
return [True, data['token']['key']]
981+
982+
def _request_result(self, res):
983+
if not self._checkResponse(res):
984+
return False, self.lasterr
985+
986+
return True, res.json()

0 commit comments

Comments
 (0)