From 9edc1e281b81d77f0732eb9a9a66c964ac2ff7f7 Mon Sep 17 00:00:00 2001 From: Dimitra Chatzichrysou Date: Tue, 9 Jul 2019 17:06:07 +0200 Subject: [PATCH 1/7] Refactoring ServiceNowAlerter and credentials declaration on config.yaml Add caller_id on required_options on ServiceNowAlerter and remove comments from required_options Add required_credentials as global configuaration options Update username and password on ServiceNowAlerter auth Remove username and password from required fields on ServiceNowAlerter Add snow_password and snow_username as required fields and caller_id as optional Update copy of required_credentials in load_options function --- elastalert/alerts.py | 33 +++++++++++++-------------------- elastalert/config.py | 10 ++++++++++ 2 files changed, 23 insertions(+), 20 deletions(-) diff --git a/elastalert/alerts.py b/elastalert/alerts.py index c0952d5..a097fc0 100644 --- a/elastalert/alerts.py +++ b/elastalert/alerts.py @@ -1764,16 +1764,10 @@ def get_info(self): class ServiceNowAlerter(Alerter): """ Creates a ServiceNow alert """ required_options = set([ - 'username', - 'password', + 'snow_username', + 'snow_password', 'servicenow_rest_url', - 'short_description', - 'comments', - 'assignment_group', - 'category', - 'subcategory', - 'cmdb_ci', - 'caller_id' + 'short_description' ]) def __init__(self, rule): @@ -1792,20 +1786,19 @@ def alert(self, matches): "Accept": "application/json;charset=utf-8" } proxies = {'https': self.servicenow_proxy} if self.servicenow_proxy else None - payload = { - "description": description, - "short_description": self.rule['short_description'], - "comments": self.rule['comments'], - "assignment_group": self.rule['assignment_group'], - "category": self.rule['category'], - "subcategory": self.rule['subcategory'], - "cmdb_ci": self.rule['cmdb_ci'], - "caller_id": self.rule["caller_id"] - } + + key_list = ["caller_id", "comments", "assignment_group", "category", "subcategory", "cmdb_ci", "comments", "u_business_service", "u_functional_element"] + + payload = {"description": description} + + for key in key_list: + if (self.rule.get(key)): + payload.update({key: self.rule[key]}) + try: response = requests.post( self.servicenow_rest_url, - auth=(self.rule['username'], self.rule['password']), + auth=(self.rule['snow_username'], self.rule['snow_password']), headers=headers, data=json.dumps(payload, cls=DateTimeEncoder), proxies=proxies diff --git a/elastalert/config.py b/elastalert/config.py index 7b7fc30..e5714ac 100644 --- a/elastalert/config.py +++ b/elastalert/config.py @@ -33,6 +33,7 @@ # Required global (config.yaml) and local (rule.yaml) configuration options required_globals = frozenset(['run_every', 'rules_folder', 'es_host', 'es_port', 'writeback_index', 'buffer_time']) required_locals = frozenset(['alert', 'type', 'name', 'index']) +required_credentials = frozenset(['snow_username', 'snow_password']) # Settings that can be derived from ENV variables env_settings = {'ES_USE_SSL': 'use_ssl', @@ -211,6 +212,15 @@ def load_options(rule, conf, filename, args=None): except (KeyError, TypeError) as e: raise EAException('Invalid time format used: %s' % (e)) + # Copy required_credentials from config.yaml + try: + for key in required_credentials: + if key not in rule: + rule.update({key: conf[key]}) + except (KeyError, TypeError) as e: + raise EAException('Missing required credentials: %s' % (e)) + + # Set defaults, copy defaults from config.yaml td_fields = ['realert', 'exponential_realert', 'aggregation', 'query_delay'] for td_field in td_fields: From 0a171d32950982f3153aec375c5d0614d59a5030 Mon Sep 17 00:00:00 2001 From: Dimitra Chatzichrysou Date: Mon, 22 Jul 2019 13:28:23 +0200 Subject: [PATCH 2/7] Modify exception for required credentials --- elastalert/config.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/elastalert/config.py b/elastalert/config.py index e5714ac..b749444 100644 --- a/elastalert/config.py +++ b/elastalert/config.py @@ -217,9 +217,12 @@ def load_options(rule, conf, filename, args=None): for key in required_credentials: if key not in rule: rule.update({key: conf[key]}) - except (KeyError, TypeError) as e: - raise EAException('Missing required credentials: %s' % (e)) - + except: + missing_credentials = [] + for key in required_credentials: + if key not in conf: + missing_credentials.append(key) + raise EAException('Missing required credentials: %s' % (missing_credentials)) # Set defaults, copy defaults from config.yaml td_fields = ['realert', 'exponential_realert', 'aggregation', 'query_delay'] From caa00b7b75e56e389d1a958c6534c0974918cc30 Mon Sep 17 00:00:00 2001 From: Dimitra Chatzichrysou Date: Tue, 9 Jul 2019 17:06:07 +0200 Subject: [PATCH 3/7] Refactoring ServiceNowAlerter and credentials declaration on config.yaml Add caller_id on required_options on ServiceNowAlerter and remove comments from required_options Add required_credentials as global configuaration options Update username and password on ServiceNowAlerter auth Remove username and password from required fields on ServiceNowAlerter Add snow_password and snow_username as required fields and caller_id as optional Update copy of required_credentials in load_options function --- elastalert/alerts.py | 33 +++++++++++++-------------------- elastalert/config.py | 13 +++++++++++++ 2 files changed, 26 insertions(+), 20 deletions(-) diff --git a/elastalert/alerts.py b/elastalert/alerts.py index c0952d5..a097fc0 100644 --- a/elastalert/alerts.py +++ b/elastalert/alerts.py @@ -1764,16 +1764,10 @@ def get_info(self): class ServiceNowAlerter(Alerter): """ Creates a ServiceNow alert """ required_options = set([ - 'username', - 'password', + 'snow_username', + 'snow_password', 'servicenow_rest_url', - 'short_description', - 'comments', - 'assignment_group', - 'category', - 'subcategory', - 'cmdb_ci', - 'caller_id' + 'short_description' ]) def __init__(self, rule): @@ -1792,20 +1786,19 @@ def alert(self, matches): "Accept": "application/json;charset=utf-8" } proxies = {'https': self.servicenow_proxy} if self.servicenow_proxy else None - payload = { - "description": description, - "short_description": self.rule['short_description'], - "comments": self.rule['comments'], - "assignment_group": self.rule['assignment_group'], - "category": self.rule['category'], - "subcategory": self.rule['subcategory'], - "cmdb_ci": self.rule['cmdb_ci'], - "caller_id": self.rule["caller_id"] - } + + key_list = ["caller_id", "comments", "assignment_group", "category", "subcategory", "cmdb_ci", "comments", "u_business_service", "u_functional_element"] + + payload = {"description": description} + + for key in key_list: + if (self.rule.get(key)): + payload.update({key: self.rule[key]}) + try: response = requests.post( self.servicenow_rest_url, - auth=(self.rule['username'], self.rule['password']), + auth=(self.rule['snow_username'], self.rule['snow_password']), headers=headers, data=json.dumps(payload, cls=DateTimeEncoder), proxies=proxies diff --git a/elastalert/config.py b/elastalert/config.py index 7b7fc30..b749444 100644 --- a/elastalert/config.py +++ b/elastalert/config.py @@ -33,6 +33,7 @@ # Required global (config.yaml) and local (rule.yaml) configuration options required_globals = frozenset(['run_every', 'rules_folder', 'es_host', 'es_port', 'writeback_index', 'buffer_time']) required_locals = frozenset(['alert', 'type', 'name', 'index']) +required_credentials = frozenset(['snow_username', 'snow_password']) # Settings that can be derived from ENV variables env_settings = {'ES_USE_SSL': 'use_ssl', @@ -211,6 +212,18 @@ def load_options(rule, conf, filename, args=None): except (KeyError, TypeError) as e: raise EAException('Invalid time format used: %s' % (e)) + # Copy required_credentials from config.yaml + try: + for key in required_credentials: + if key not in rule: + rule.update({key: conf[key]}) + except: + missing_credentials = [] + for key in required_credentials: + if key not in conf: + missing_credentials.append(key) + raise EAException('Missing required credentials: %s' % (missing_credentials)) + # Set defaults, copy defaults from config.yaml td_fields = ['realert', 'exponential_realert', 'aggregation', 'query_delay'] for td_field in td_fields: From d7e76d9a5a8af1efd5420ac7e157b06eb315ff88 Mon Sep 17 00:00:00 2001 From: Dimitra Chatzichrysou Date: Mon, 22 Jul 2019 14:40:44 +0200 Subject: [PATCH 4/7] Modify requiered and optional fields on ServiceNow --- docs/source/ruletypes.rst | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/docs/source/ruletypes.rst b/docs/source/ruletypes.rst index f8452dc..d7fc3c6 100644 --- a/docs/source/ruletypes.rst +++ b/docs/source/ruletypes.rst @@ -1900,16 +1900,22 @@ The alerter requires the following options: ``servicenow_rest_url``: The ServiceNow RestApi url, this will look like https://instancename.service-now.com/api/now/v1/table/incident -``username``: The ServiceNow Username to access the api. +``snow_username``: The ServiceNow Username to access the api. -``password``: The ServiceNow password to access the api. +``snow_password``: The ServiceNow password to access the api. ``short_description``: The ServiceNow password to access the api. +Optional: + ``comments``: Comments to be attached to the incident, this is the equivilant of work notes. ``assignment_group``: The group to assign the incident to. +``Service Element (u_business_service)``: This is the 32-character long ID of the Service Element that will take care of theincident. + +``Functional Element (u_functional_element)``: The 32-character long ID of the FE that will take care of the incident. + ``category``: The category to attach the incident to, use an existing category. ``subcategory``: The subcategory to attach the incident to, use an existing subcategory. @@ -1918,9 +1924,6 @@ The alerter requires the following options: ``caller_id``: The caller id (email address) of the user that created the incident (elastalert@somewhere.com). - -Optional: - ``servicenow_proxy``: By default ElastAlert will not use a network proxy to send notifications to ServiceNow. Set this option using ``hostname:port`` if you need to use a proxy. From 8710af19ed8da9249991e147618c30d3f56d8973 Mon Sep 17 00:00:00 2001 From: Dimitra Chatzichrysou Date: Mon, 22 Jul 2019 14:58:11 +0200 Subject: [PATCH 5/7] Update the description of required fields on ServiceNow --- docs/source/ruletypes.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/source/ruletypes.rst b/docs/source/ruletypes.rst index d7fc3c6..b19f6ea 100644 --- a/docs/source/ruletypes.rst +++ b/docs/source/ruletypes.rst @@ -1900,11 +1900,11 @@ The alerter requires the following options: ``servicenow_rest_url``: The ServiceNow RestApi url, this will look like https://instancename.service-now.com/api/now/v1/table/incident -``snow_username``: The ServiceNow Username to access the api. +``snow_username``: The ServiceNow Username to access the api. This option allows the rule to override the buffer_time global setting defined in config.yaml. -``snow_password``: The ServiceNow password to access the api. +``snow_password``: The ServiceNow password to access the api. This option allows the rule to override the buffer_time global setting defined in config.yaml. -``short_description``: The ServiceNow password to access the api. +``short_description``: The ServiceNow password to access the api. This option allows the rule to override the buffer_time global setting defined in config.yaml. Optional: From 93afce264653191236eab97b73132c783cb38ac8 Mon Sep 17 00:00:00 2001 From: Dimitra Chatzichrysou Date: Mon, 22 Jul 2019 15:15:32 +0200 Subject: [PATCH 6/7] Add servicenow_rest_url on required_credentials set --- elastalert/config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/elastalert/config.py b/elastalert/config.py index b749444..1db0e7c 100644 --- a/elastalert/config.py +++ b/elastalert/config.py @@ -33,7 +33,7 @@ # Required global (config.yaml) and local (rule.yaml) configuration options required_globals = frozenset(['run_every', 'rules_folder', 'es_host', 'es_port', 'writeback_index', 'buffer_time']) required_locals = frozenset(['alert', 'type', 'name', 'index']) -required_credentials = frozenset(['snow_username', 'snow_password']) +required_credentials = frozenset(['snow_username', 'snow_password', 'servicenow_rest_url']) # Settings that can be derived from ENV variables env_settings = {'ES_USE_SSL': 'use_ssl', From be8d619b5519b4442d5a7adc4cf1f1ce81e632f8 Mon Sep 17 00:00:00 2001 From: Dimitra Chatzichrysou Date: Tue, 23 Jul 2019 17:35:22 +0200 Subject: [PATCH 7/7] Add short_description at payload --- elastalert/alerts.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/elastalert/alerts.py b/elastalert/alerts.py index a097fc0..9d174cb 100644 --- a/elastalert/alerts.py +++ b/elastalert/alerts.py @@ -1789,7 +1789,7 @@ def alert(self, matches): key_list = ["caller_id", "comments", "assignment_group", "category", "subcategory", "cmdb_ci", "comments", "u_business_service", "u_functional_element"] - payload = {"description": description} + payload = {"description": description, "short_description": self.rule['short_description']} for key in key_list: if (self.rule.get(key)):