class ELK_to_Slack: def __init__(self): self.api_issues = API_Issues() self.attachments = API_Slack_Attachment() self.default_max = 20 def set_default_max(self, value): self.default_max = value ; return self def get_search_mappings(self): return { 'assign' : 'Assignee:', 'summary' : 'Summary:', #'asset' : 'Issue\\ Type:"IT Asset" AND Summary:', #'entity' : 'Issue\\ Type:"Business Entity" AND Summary:', #'epic' : 'Issue\\ Type:"Epic" AND Summary:', #'incident' : 'Issue\\ Type:"Incident" AND Summary:', #'meeting' : 'Issue\\ Type:Meeting AND Summary:', 'person' : 'Issue\ Type:Person AND Summary:', #'project' : 'Issue\\ Type:"GS-Project" AND Summary:', #'programme': 'Issue\\ Type:"Programme" AND Summary:', #'risk' : 'Issue\\ Type:Risk AND Summary:', #'sc' : 'Issue\\ Type:"Security Controls AND Summary:', #'service' : 'Issue\\ Type:"GS Service" AND Summary:', #'vuln' : 'Issue\\ Type:Vulnerability AND Summary:', #'supplier': 'Project:"Supplier\\ Log" AND Summary:', 'task' : 'Issue\ Type:"Task" AND Summary:', 'squad' : 'Issue\ Type:Squad AND Summary:', 'outcomes' : 'Issue\ Type:Outcome AND Summary:', 'keyresult' : 'Issue\ Type:Key Result AND Summary:', 'sow' : 'Issue\ Type:Sow AND Summary:', 'label' : 'Labels:', 'high' : 'Rating:High AND Summary:', 'low' : 'Rating:Low AND Summary:', 'medium' : 'Rating:Medium AND Summary:', } def get_search_query(self,params): search_type = Lists.first(params,strip=True) if search_type: query = self.get_search_mappings().get(search_type) if query: return query + ' '.join(params[1:]) #if index_name.lower() in ['people']: return 'Issue\ Type:People AND Summary ' +' '.join[1:] return ' '.join(params) def get_text_with_issues_key_and_summary(self, results): issues_list = "" keys = [] for issue in results[0:self.default_max]: key = issue['Key'] summary = issue['Summary'] jira_link = "https://glasswall.atlassian.net/browse/{0}".format(key) issues_list += "<{0}|{1}> {2} \n".format(jira_link, key, summary) keys.append(key) return issues_list def save_issues_as_new_graph(self, issues): all_keys = [] for issue in issues: all_keys.append(issue['Key']) graph = GS_Graph() # save results in graph graph.add_nodes(all_keys) return Lambda_Graph().save_gs_graph(graph, graph_type='graph-search') def get_slack_message(self, issues, graph_name): text = ":point_right: Elk search had `{0}` matches (results saved to graph `{1}` ) \n" \ .format(len(issues), graph_name) if len(issues) > self.default_max: text += ":point_right: showing first `{0}`".format(self.default_max) return text def cmd_search(self, params, user=None, team_id=None, channel=None): if Lists.empty(params): text = ':red_circle: for the `search` command, please provide the type of search you want to do. \nHere are the the options:' for name in sorted(list(set(self.get_search_mappings()))): text += '\n\t\t • `{0}` '.format(name) text += '\n\n:point_right: the syntax is: `jira search {type} {what to search}` (note search is done on the Summary field)' return slack_message(text, [], channel, team_id) query = self.get_search_query(params) issues = self.api_issues.search_using_lucene(query) if channel: if len(issues) > 0: issues_text = self.get_text_with_issues_key_and_summary(issues) graph_name = self.save_issues_as_new_graph(issues) text = self.get_slack_message(issues, graph_name) self.attachments.set_text(issues_text) self.attachments.set_callback_id("search-results") return slack_message(text, self.attachments.render(), channel, team_id) else: text = ":red_circle: Elk search for `{0}` had `{1}` matches".format(query, len(issues)) return slack_message(text, self.attachments.render(), channel, team_id) else: return issues # def cmd_search_graph(self, params, user, team_id, channel): # results = self.api_issues.search_using_lucene(' '.join(params)) # keys = [issue.get('Key') for issue in results] # if len(keys) == 0: # text = ':black_circle: ELK search returned 0 results' # else: # text = 'ELK search resulted in `{0}` keys'.format(len(keys)) # # slack_cmd = 'links {0} all 1'.format(','.join(keys)) # params = slack_cmd.split(' ') # result = Lambda('gs.elastic_jira').invoke({"params": params, "user": user, "channel": channel}) # #slack_message(result.get('text'), result.get('attachments'), channel) # self.attachments.set_text(result.get('text')) # # slack_message(text, self.attachments.render(), channel, team_id) def handle_lambda_event(self, event): channel = event.get('channel' ) params = event.get("params" ) user = event.get('user' ) team_id = event.get('team_id') log_to_elk('[Elk_to_Slack.handle_lambda_event]: {0}'.format(event)) try: if params: command = params.pop(0) if command == 'search' : return self.cmd_search (params, user, team_id, channel) #if command == 'search-graph': return self.cmd_search_graph(params, user, team_id, channel) #return slack_message(":point_right: in handle_lambda_event with params: {0}".format(event), [], channel) slack_message(":red_circle: in ELK_to_Slack, un-supported command :`{0}`. Data received was: {1}".format(command,event), [], channel) except Exception as error: message = ":red_circle: error in ELK_to_Slack:`{0}`. Data received was: {1}".format(error,event) log_to_elk(message, level = 'error') slack_message(message , [], channel) # def save_search_in_elk(self, message): # index = 'slack_interaction' # item = { 'data': message, # 'date': datetime.datetime.utcnow() } # elastic = Log_To_Elk().setup(index) # return elastic.add(item)
class Jp_Graph_Data: def __init__(self): self.lambda_graph = Lambda('osbot_jira.lambdas.graph') self.api_issues = API_Issues() self.gs_bot_jira = GS_Bot_Jira() self.graph_commands = Lambda_Graph_Commands() self.elk_to_slack = ELK_to_Slack() def lambda_invoke(self, params): result = self.lambda_graph.invoke({'params': params, 'data': {}}) return json_loads(result) def issue(self, issue_id): return self.api_issues.issue(issue_id) def issues(self, issue_id): return self.api_issues.issues(issue_id) def jira_links(self, source, depth=1): params = ['links', source, depth] return self.gs_bot_jira.cmd_links(params, save_graph=False) def jira_search(self, query): params = query.split(' ') query = self.elk_to_slack.get_search_query(params) return self.api_issues.search_using_lucene(query) def graph_expand(self, source, depth, link_types): params = [source, depth, link_types] return self.graph_commands.expand(params=params, save_graph=False) #data = json..invoke(params)) #nodes = data.get('nodes') #edges = data.get('edges') def draw_graph(self, graph): nodes = graph.nodes edges = graph.edges import networkx as nx import matplotlib.pyplot as plt size = 40 plt.figure(figsize=(size, size)) G = nx.DiGraph() for node in nodes: G.add_node(node) for edge in edges: G.add_edge(edge[0], edge[2], label=edge[1]) edge_labels = nx.get_edge_attributes(G, 'label') # pos = nx.spring_layout(G) # pos=nx.nx_pydot.graphviz_layout(G,prog='dot') pos = nx.nx_pydot.graphviz_layout(G) nx.draw_networkx_nodes(G, pos, node_shape='', node_size=100) nx.draw_networkx_labels(G, pos, font_size=16) nx.draw_networkx_edges(G, pos) nx.draw_networkx_edge_labels(G, pos=pos, edge_labels=edge_labels, font_size=10)
class Test_API_Issues(unittest.TestCase): def setUp(self): self.key = 'RISK-1515' self.api = API_Issues() def test_epic_issues(self): results = self.api.epic_issues('SEC-2024') assert len(list(results)) > 10 def test_issue(self): issue = self.api.issue(self.key) assert issue.get('Key') == self.key @unittest.skip('todo: fix: error on "if item[\'found\'] is False:" line') def test_issues(self): keys = ['RISK-1499', 'RISK-1496', 'AAA'] #result = self.api.elastic.es.mget(index='jira', # doc_type='item', # body={'ids': keys}) results = self.api.elastic().get_many(keys) #Dev.pprint(results) def test_issues_all(self): assert len(self.api.issues_all('jira')) > 2000 def test_issues_created_in_last(self): result = self.api.issues_created_in_last("3d") assert len(result) > 10 def test_issues_updated_in_last(self): result = self.api.issues_updated_in_last("3d") assert len(result) > 10 def test_issues_created_in_last_nnn(self): assert len(self.api.issues_created_in_last_seconds( 1 * 24 * 60 * 60)) > 0 assert len(self.api.issues_created_in_last_minutes(1 * 24 * 60)) > 0 assert len(self.api.issues_created_in_last_hours(1 * 24)) > 0 assert len(self.api.issues_created_in_last_days(1)) > 0 assert len(self.api.issues_created_in_last_weeks(1)) > 0 assert len(self.api.issues_created_in_last_months(1)) > 0 @unittest.skip('fails in CodeBuild') def test_create_issue_table(self): table = self.api.create_issue_table('RISK-424') table.save_tmp() #Dev.print(table.puml) def test_labels(self): result = self.api.labels() assert 'VULN-2160' in result['AWSrisk'] assert len(result) > 650 def test_link_types(self): result = self.api.link_types() assert len(result) > 100 def test_keys(self): keys = self.api.keys() assert 'VULN-10' in keys assert len(keys) > 15000 def test_search(self): assert len(self.api.search("aw", "Summary", 100)) > 0 assert len(self.api.search("R1", "Labels", 10)) > 0 assert self.api.search("GSP-95", "Key", 10).pop().get('Key') == "GSP-95" def test_search_using_lucene(self): query = 'Project:RISK AND Status:"Fixed"' results = self.api.search_using_lucene(query) assert len(results) > 200 # def test_stakeholders(self): # result = self.api.stakeholders() # #Dev.pprint(result) # #Dev.pprint(len(set(result))) ### move these to separate analysis file @unittest.skip('Fails in CodeBuild') def test_graph_issue_links_plant_uml(self): puml = self.api.graph_issue_links_plant_uml(self.key) puml.save_tmp() puml._dev_send_to_slack()