Skip to content

Commit

Permalink
Email notification should include only specified info legos in the ya…
Browse files Browse the repository at this point in the history
…ml file (#1015)
  • Loading branch information
shloka-bhalgat-unskript authored Mar 18, 2024
1 parent 5115a9c commit 2068f85
Show file tree
Hide file tree
Showing 2 changed files with 113 additions and 57 deletions.
40 changes: 29 additions & 11 deletions unskript-ctl/unskript_ctl_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -280,23 +280,41 @@ def get_info_action_params(self):
def get_info(self):
return self.get_jobs().get('info',{})

def get_email_fmt(self):
notification_config = self.get_notification()
email_config = notification_config.get('Email', {})
email_fmt = email_config.get('email_fmt', {})
return email_fmt

def get_checks_section(self):
# Get the checks_section from email_fmt
checks_section = self.get_email_fmt().get('checks_section', {})
return checks_section.get('priority', {})

def get_info_section(self):
# Get the info_section from email_fmt
return self.get_email_fmt().get('info_section', [])

def get_checks_priority(self)->dict:
# This function reads the priority part of the config and converts it
# into a dict with check_name as the key and priority as the value.
# If the check is not found in the dict, its assigned priority P2.

# Read P0 priority if configured
email_fmt = self.get_email_fmt()
checks_section = email_fmt.get('checks_section', {})
priority_config = checks_section.get('priority', {})

checks_priority = {}
priority_config = self._get('checks').get('priority')
if priority_config is None:

# Check if the 'priority' configuration is properly set; if not, return None
if not priority_config:
return None
p0_priority = priority_config.get(CHECK_PRIORITY_P0)
if p0_priority is not None:
for c in p0_priority:
checks_priority[c] = CHECK_PRIORITY_P0
p1_priority = priority_config.get(CHECK_PRIORITY_P1)
if p1_priority is not None:
for c in p1_priority:
checks_priority[c] = CHECK_PRIORITY_P1

# Explicitly fetch and map checks for each priority level using the constants
for priority_level in [CHECK_PRIORITY_P0, CHECK_PRIORITY_P1, CHECK_PRIORITY_P2]:
priority_checks = priority_config.get(priority_level, [])
for check_name in priority_checks:
checks_priority[check_name] = priority_level

return checks_priority

130 changes: 84 additions & 46 deletions unskript-ctl/unskript_ctl_notification.py
Original file line number Diff line number Diff line change
Expand Up @@ -234,26 +234,61 @@ def create_script_summary_message(self, output_metadata_file: str):

return ''

def create_info_legos_output_file(self):
"""create_info_legos_output_file: This function creates a file that will
be added to the final tarball
"""
parent_folder = self.execution_dir
if self.uglobals.get('CURRENT_EXECUTION_RUN_DIRECTORY'):
parent_folder = self.uglobals.get('CURRENT_EXECUTION_RUN_DIRECTORY')
info_legos_output_file_path = os.path.join(parent_folder, "info_legos_output.txt")
info_action_results = self.uglobals.get('info_action_results')

# Write all info lego outputs to a single file
if info_action_results:
with open(info_legos_output_file_path, 'w', encoding='utf-8') as f:
for action_name, action_output in info_action_results.items():
content = f"{action_name}:\n{action_output if action_output else 'NO OUTPUT'}\n\n"
f.write(content)
else:
self.logger.error("No information gathering action result available")
return None

return info_legos_output_file_path


def create_info_gathering_action_result(self):
"""create_info_gathering_action_result: This function creates an inline
results of all the output from info gathering action
"""
message = ''
if self.uglobals.get('info_action_results'):
message = f'''
# Fetch the list of actions specified in the YAML under info_section
specified_actions = self._config.get_email_fmt().get('info_section', [])
info_action_results = self.uglobals.get('info_action_results')
if not specified_actions:
return message

if info_action_results:
message += '''
<br>
<h3> Information Gathering Action Result </h3>
<br>
'''
for k,v in self.uglobals.get('info_action_results').items():
message += '<h4>' + k + '</h4> <pre>'
if v:
for line in v:
message += line
else:
message += 'NO OUTPUT \n'
message += '###'
message += '</pre>'
for specified_action in specified_actions:
action_found = False
for full_action_name, action_output in info_action_results.items():
# Extract the part of the action name after '/'
_, action_name_suffix = full_action_name.split('/', 1)
if action_name_suffix == specified_action:
message += f'<h4>{specified_action}</h4> <pre>'
message += action_output if action_output else 'NO OUTPUT'
message += '</pre>'
action_found = True
break # Stop looking once found
if not action_found:
# If the specified action was not found in the results, show no output
message += f'<h4>{specified_action}</h4> <pre>Action not executed</pre>'

message += '<br>'

return message
Expand Down Expand Up @@ -412,30 +447,45 @@ def prepare_combined_email(self,
failed_result=failed_result)
if len(failed_result) and self.send_failed_objects_as_attachment:
self.create_temp_files_of_failed_check_results(failed_result=failed_result)
if self.create_tarball_archive(tar_file_name=tar_file_name,
output_metadata_file=None,
parent_folder=parent_folder) is False:
self.logger.error("ERROR Archiving attachments")
raise ValueError("ERROR: Archiving attachments failed!")
# Create temp tar file in accessible directory
msg = MIMEMultipart('mixed')
with open(target_file_name, 'rb') as f:
part = MIMEApplication(f.read())
part.add_header('Content-Disposition', 'attachment', filename=target_file_name)
msg.attach(part)
parent_folder = self.execution_dir
target_name = os.path.basename(parent_folder)
tar_file_name = f"{target_name}" + '.tar.bz2'

if output_metadata_file:
message += self.create_script_summary_message(output_metadata_file=output_metadata_file)
temp_attachment = self.create_email_attachment(output_metadata_file=output_metadata_file)
if self.execution_dir :
if not self.create_tarball_archive(tar_file_name=tar_file_name, output_metadata_file=None, parent_folder=parent_folder):
raise ValueError("ERROR: Archiving attachments failed!")
else:
self.logger.error("Execution directory is empty !")

msg = MIMEMultipart('mixed')
with open(target_file_name, 'rb') as f:
part = MIMEApplication(f.read())
part.add_header('Content-Disposition', 'attachment', filename=target_file_name)
msg.attach(part)

if failed_result and len(failed_result) and self.send_failed_objects_as_attachment:
message += '<br> <ul>' + '\n'
message += '<h3> DETAILS ABOUT THE FAILED OBJECTS CAN BE FOUND IN THE ATTACHMENTS </h3>' + '\n'
message += '</ul> <br>' + '\n'


info_result = self.create_info_gathering_action_result()
if info_result:
message += info_result
self.create_info_legos_output_file()

if self.execution_dir :
if not self.create_tarball_archive(tar_file_name=tar_file_name, output_metadata_file=None, parent_folder=parent_folder):
raise ValueError("ERROR: Archiving attachments failed!")
else:
self.logger.error("Execution directory is empty !")

msg = MIMEMultipart('mixed')
with open(target_file_name, 'rb') as f:
part = MIMEApplication(f.read())
part.add_header('Content-Disposition', 'attachment', filename=target_file_name)
msg.attach(part)


message += "</body> </html>"
attachment.attach(MIMEText(message, 'html'))
Expand All @@ -444,7 +494,8 @@ def prepare_combined_email(self,
elif msg:
attachment.attach(msg)

return attachment
return attachment


# Sendgrid specific implementation
class SendgridNotification(EmailNotification):
Expand Down Expand Up @@ -509,27 +560,14 @@ def send_sendgrid_notification(self,
failed_result=failed_result)
if failed_result and len(failed_result) and self.send_failed_objects_as_attachment:
self.create_temp_files_of_failed_check_results(failed_result=failed_result)
if output_metadata_file:
html_message += self.create_script_summary_message(output_metadata_file=output_metadata_file)
with open(output_metadata_file, 'r') as f:
metadata = json.loads(f.read())
if metadata and metadata.get('output_file'):
target_file_name = os.path.basename(metadata.get('output_file'))
parent_folder = os.path.dirname(output_metadata_file)
target_name = os.path.basename(parent_folder)
tar_file_name = f"{target_name}" + '.tar.bz2'
if metadata and metadata.get('compress') is True:
output_metadata_file = output_metadata_file.split('/')[-1]
if self.create_tarball_archive(tar_file_name=tar_file_name,
output_metadata_file=output_metadata_file,
parent_folder=parent_folder) is False:
self.create_info_legos_output_file()

# Check conditions for creating tarball
if self.execution_dir :
if not self.create_tarball_archive(tar_file_name=target_file_name, output_metadata_file=None, parent_folder=parent_folder):
raise ValueError("ERROR: Archiving attachments failed!")
else:
if len(failed_result) and self.send_failed_objects_as_attachment:
if self.create_tarball_archive(tar_file_name=tar_file_name,
output_metadata_file=None,
parent_folder=parent_folder) is False:
raise ValueError("ERROR: Archiving attachments failed!")
self.logger.error("Execution directory is empty !")
info_result = self.create_info_gathering_action_result()
if info_result:
html_message += info_result
Expand All @@ -540,7 +578,7 @@ def send_sendgrid_notification(self,
subject=email_subject,
html_content=html_message
)
if target_file_name:
if os.path.exists(target_file_name) and os.path.getsize(target_file_name) > 0:
email_message = self.sendgrid_add_email_attachment(email_message=email_message,
file_to_attach=target_file_name,
compress=True)
Expand Down

0 comments on commit 2068f85

Please sign in to comment.