Skip to content

Commit c1a46d9

Browse files
committed
Enhance ThreatReport model, add sensor_group_operations example script
1 parent 721724c commit c1a46d9

File tree

2 files changed

+139
-11
lines changed

2 files changed

+139
-11
lines changed
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
#!/usr/bin/env python
2+
#
3+
4+
import sys
5+
from cbapi.response.models import SensorGroup, Site
6+
from cbapi.example_helpers import build_cli_parser, get_cb_response_object
7+
from cbapi.errors import ServerError
8+
import logging
9+
10+
log = logging.getLogger(__name__)
11+
12+
13+
def list_sensor_groups(cb, parser, args):
14+
for g in cb.select(SensorGroup):
15+
print(g)
16+
print("")
17+
18+
19+
def add_sensor_group(cb, parser, args):
20+
g = cb.create(SensorGroup)
21+
22+
if args.site_name:
23+
site = cb.select(Site).where("name:{0}".format(args.site_name)).first()
24+
if not site:
25+
print("Could not find site named {0}".format(args.site_name))
26+
return 1
27+
elif args.site_id:
28+
site = cb.select(Site).where("id:{0}".format(args.site_id)).first()
29+
if not site:
30+
print("Could not find site ID {0}".format(args.site_id))
31+
return 1
32+
else:
33+
# Just pick the first site by the lowest ID
34+
site = min(cb.select(Site), key=lambda x: x.id)
35+
36+
g.name = args.new_group_name
37+
g.site = site
38+
39+
try:
40+
g.save()
41+
except ServerError as se:
42+
print("Received HTTP error {0} when attempting to add sensor group: {1}".format(se.error_code, str(se)))
43+
except Exception as e:
44+
print("Could not add sensor group: {0:s}".format(str(e)))
45+
else:
46+
log.debug("New Sensor Group: {0:s}".format(str(g)))
47+
print("Added sensor group. New sensor group ID is {0:d}".format(g.id))
48+
49+
50+
def delete_sensor_group(cb, parser, args):
51+
try:
52+
if args.id:
53+
attempted_to_find = "ID of {0:d}".format(args.id)
54+
groups = [cb.select(SensorGroup, args.id, force_init=True)]
55+
else:
56+
attempted_to_find = "name {0:s}".format(args.groupname)
57+
groups = cb.select(SensorGroup).where("name:{0:s}".format(args.groupname))[::]
58+
if not len(groups):
59+
raise Exception("No sensor groups match")
60+
except Exception as e:
61+
print("Could not find sensor group with {0:s}: {1:s}".format(attempted_to_find, str(e)))
62+
return
63+
64+
num_matching_sensor_groups = len(groups)
65+
if num_matching_sensor_groups > 1 and not args.force:
66+
print("{0:d} sensor groups match {1:s} and --force not specified. No action taken.".format(num_matching_sensor_groups,
67+
attempted_to_find))
68+
return
69+
70+
for g in groups:
71+
try:
72+
g.delete()
73+
except Exception as e:
74+
print("Could not delete sensor group with {0:s}: {1:s}".format(attempted_to_find, str(e)))
75+
else:
76+
print("Deleted sensor group id {0:d} with name {1:s}".format(g.id, g.name))
77+
78+
79+
def main():
80+
parser = build_cli_parser()
81+
commands = parser.add_subparsers(help="Sensor Group commands", dest="command_name")
82+
83+
list_command = commands.add_parser("list", help="List all configured sensor groups")
84+
85+
add_command = commands.add_parser("add", help="Add new sensor group")
86+
add_command.add_argument("-n", "--name", action="store", help="Sensor group name", required=True,
87+
dest="new_group_name")
88+
site_group = add_command.add_mutually_exclusive_group(required=False)
89+
site_group.add_argument("-s", "--site", action="store", help="Site name", dest="site_name")
90+
site_group.add_argument("-i", "--site-id", action="store", help="Site ID", dest="site_id")
91+
92+
del_command = commands.add_parser("delete", help="Delete sensor groups")
93+
del_sensor_group_specifier = del_command.add_mutually_exclusive_group(required=True)
94+
del_sensor_group_specifier.add_argument("-i", "--id", type=int, help="ID of sensor group to delete")
95+
del_sensor_group_specifier.add_argument("-n", "--name", help="Name of sensor group to delete. Specify --force to delete"
96+
" multiple sensor groups that have the same name", dest="groupname")
97+
del_command.add_argument("--force", help="If NAME matches multiple sensor groups, delete all matching sensor groups",
98+
action="store_true", default=False)
99+
100+
args = parser.parse_args()
101+
cb = get_cb_response_object(args)
102+
103+
if args.command_name == "list":
104+
return list_sensor_groups(cb, parser, args)
105+
elif args.command_name == "add":
106+
return add_sensor_group(cb, parser, args)
107+
elif args.command_name == "delete":
108+
return delete_sensor_group(cb, parser, args)
109+
110+
111+
if __name__ == "__main__":
112+
sys.exit(main())

src/cbapi/response/models.py

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -114,8 +114,8 @@ def _query_implementation(cls, cb):
114114
return SimpleQuery(cls, cb)
115115

116116
def _parse(self, info):
117-
if len(info) != 1:
118-
raise ApiError("Expecting Site response to be array of size 1")
117+
if info is None or len(info) != 1:
118+
raise ObjectNotFoundError(uri=self._build_api_request_uri())
119119
return info[0]
120120

121121
@property
@@ -343,7 +343,10 @@ def _query_implementation(cls, cb):
343343

344344
def _parse(self, obj):
345345
# for some reason, these are returned as an array of size one
346-
return obj[0]
346+
if obj and len(obj):
347+
return obj[0]
348+
else:
349+
raise ObjectNotFoundError(uri=self._build_api_request_uri())
347350

348351
@property
349352
def sensors(self):
@@ -615,11 +618,30 @@ def tag_info(self, tag_name):
615618
return self._tags.get(tag_name, {})
616619

617620

618-
class ThreatReport(MutableModel):
621+
class ThreatReport(MutableBaseModel):
619622
urlobject = '/api/v1/threat_report'
623+
primary_key = "_internal_id"
624+
625+
@property
626+
def _model_unique_id(self):
627+
feed_id = getattr(self, "feed_id")
628+
report_id = getattr(self, "id")
629+
630+
if feed_id and report_id:
631+
return "{0}:{1}".format(feed_id, report_id)
632+
else:
633+
return None
634+
635+
def disable(self):
636+
self.is_ignored = True
637+
self.save()
638+
639+
def enable(self):
640+
self.is_ignored = False
641+
self.save()
620642

621643
@classmethod
622-
def new_object(cls, cb, item):
644+
def new_object(cls, cb, item, **kwargs):
623645
return cb.select(ThreatReport, "%s:%s" % (item["feed_id"], item["id"]), initial_data=item)
624646

625647
def _build_api_request_uri(self):
@@ -640,9 +662,6 @@ def __init__(self, cb, full_id, initial_data=None):
640662
def feed(self):
641663
return self._join(Feed, "feed_id")
642664

643-
def _set_model_unique_id(self):
644-
self._model_unique_id = "%s:%s" % (self.feed_id, self.id)
645-
646665
def _update_object(self):
647666
update_content = { "ids": { str(self.feed_id): [str(self.id)] }, "updates": {}}
648667
for k in self._dirty_attributes.keys():
@@ -675,9 +694,6 @@ def _update_object(self):
675694
except:
676695
self.refresh()
677696

678-
if not self._model_unique_id:
679-
self._set_model_unique_id()
680-
681697
self._dirty_attributes = {}
682698
return self._model_unique_id
683699

0 commit comments

Comments
 (0)