def setUp(self): patcher1 = patch( 'charlesbot.slack.slack_connection.SlackConnection.api_call' ) # NOQA self.addCleanup(patcher1.stop) self.mock_api_call = patcher1.start() from charlesbot.slack.slack_connection import SlackConnection self.slack_connection = SlackConnection() from charlesbot.slack.slack_user import SlackUser self.su = SlackUser()
def setUp(self): patcher2 = patch( 'charlesbot.slack.slack_connection.SlackConnection.api_call' ) # NOQA self.addCleanup(patcher2.stop) self.mock_api_call = patcher2.start() from charlesbot_jira.jira_helpers import send_jira_issue_response self.send_response = send_jira_issue_response from charlesbot.slack.slack_connection import SlackConnection self.slack_connection = SlackConnection()
def __init__(self, plugin_name): self.set_running(True) self.log = logging.getLogger(__name__) self.slack = SlackConnection() self._plugin_name = plugin_name self.log.info("Initializing the %s plugin" % plugin_name) self._q = asyncio.Queue() self.initialize_queue_consumer()
def setUp(self): patcher1 = patch('charlesbot.slack.slack_connection.SlackConnection.api_call') # NOQA self.addCleanup(patcher1.stop) self.mock_api_call = patcher1.start() from charlesbot.slack.slack_connection import SlackConnection self.slack_connection = SlackConnection() from charlesbot.slack.slack_user import SlackUser self.su = SlackUser()
class TestSendJiraIssueResponse(asynctest.TestCase): def setUp(self): patcher2 = patch( 'charlesbot.slack.slack_connection.SlackConnection.api_call' ) # NOQA self.addCleanup(patcher2.stop) self.mock_api_call = patcher2.start() from charlesbot_jira.jira_helpers import send_jira_issue_response self.send_response = send_jira_issue_response from charlesbot.slack.slack_connection import SlackConnection self.slack_connection = SlackConnection() def tearDown(self): self.slack_connection._drop() def test_send_issue(self): issue = JiraIssue(key="JIRA-9", summary="this is the problem", description="detailed description here") expected_attachment = SlackAttachment( color="#A4ADAD", fallback="JIRA-9: this is the problem", text="detailed description here", mrkdwn_in=['text'], thumb_url= "https://slack.global.ssl.fastly.net/12d4/img/services/jira_48.png", # NOQA title="JIRA-9: this is the problem", title_link="https://jira.atlassian.com/browse/JIRA-9") yield from self.send_response(self.slack_connection, "#work", "https://jira.atlassian.com", issue) expected_call = call( 'chat.postMessage', channel="#work", attachments=expected_attachment, as_user=False, username="******", icon_url= "https://avatars.slack-edge.com/2015-07-31/8502215814_6662f69db3bed43d32e6_48.jpg" # NOQA ) self.assertEqual(self.mock_api_call.mock_calls, [expected_call])
def setUp(self): self.channel_list_one = load_fixture("channel_list_one.json") self.channel_list_two = load_fixture("channel_list_two.json") self.channel_list_three = load_fixture("channel_list_three.json") self.channel_list_four = load_fixture("channel_list_four.json") from charlesbot.slack.slack_connection import SlackConnection self.slack = SlackConnection() self.slack.initialized = True self.slack.sc = MagicMock()
def __init__(self, token, url, channel, jobs): self.log = logging.getLogger(__name__) self.rundeck_token = token self.rundeck_url = url self.topic_channel = channel self.topic_channel_id = None self.slack = SlackConnection() self.locked_by_user = "" self.rundeck_jobs = [] self.rd_jobs_raw_list = jobs self.seed_job_list()
def start(self): # pragma: no cover self.set_running(True) self.slack = SlackConnection() loop = asyncio.get_event_loop() self.plugin_list = self.initialize_plugins() self.initialize_static_plugins() loop.create_task(self.produce()) loop.add_signal_handler(signal.SIGINT, functools.partial(self.exit_cleanly)) try: loop.run_forever() finally: loop.close()
class TestSlackConnectionApiCall(asynctest.TestCase): def setUp(self): self.channel_list_one = load_fixture("channel_list_one.json") self.channel_list_two = load_fixture("channel_list_two.json") self.channel_list_three = load_fixture("channel_list_three.json") self.channel_list_four = load_fixture("channel_list_four.json") from charlesbot.slack.slack_connection import SlackConnection self.slack = SlackConnection() self.slack.initialized = True self.slack.sc = MagicMock() def tearDown(self): self.slack._drop() def test_slack_rtm_api_call_ok(self): channel_list = self.channel_list_one.encode("utf8") self.slack.sc.api_call.return_value = channel_list val = yield from self.slack.api_call("fake_endpoint") self.assertEqual(json.loads(val), json.loads(channel_list.decode("utf-8"))) def test_slack_rtm_api_call_not_ok(self): channel_list = self.channel_list_two.encode("utf8") self.slack.sc.api_call.return_value = channel_list val = yield from self.slack.api_call("fake_endpoint") self.assertEqual(json.loads(val), "{}") def test_slack_rtm_api_call_not_encoded_utf8(self): channel_list = self.channel_list_three self.slack.sc.api_call.return_value = channel_list with self.assertRaises(AttributeError): yield from self.slack.api_call("fake_endpoint") def test_slack_rtm_api_call_malformed_json(self): channel_list = self.channel_list_four.encode("utf8") self.slack.sc.api_call.return_value = channel_list with self.assertRaises(ValueError): yield from self.slack.api_call("fake_endpoint")
class TestSlackUser(asynctest.TestCase): def setUp(self): patcher1 = patch( 'charlesbot.slack.slack_connection.SlackConnection.api_call' ) # NOQA self.addCleanup(patcher1.stop) self.mock_api_call = patcher1.start() from charlesbot.slack.slack_connection import SlackConnection self.slack_connection = SlackConnection() from charlesbot.slack.slack_user import SlackUser self.su = SlackUser() def tearDown(self): self.slack_connection._drop() @asynctest.ignore_loop def test_user_equality(self): from charlesbot.slack.slack_user import SlackUser user1 = SlackUser(id="SU01", name="userone", color="red") user2 = SlackUser(id="SU02", name="usertwo", color="blue") self.assertNotEqual(user1, user2) user2.id = "SU01" self.assertNotEqual(user1, user2) user2.name = "userone" self.assertNotEqual(user1, user2) user2.color = "red" self.assertEqual(user1, user2) @asynctest.ignore_loop def test_user_return_string(self): self.su.id = "SU01" self.su.name = "User One" self.su.deleted = False self.su.is_admin = False self.su.has_2fa = True user_json = json.loads(str(self.su)) self.assertEqual(user_json.get('id'), "SU01") self.assertEqual(user_json.get('name'), "User One") self.assertEqual(user_json.get('deleted'), False) self.assertEqual(user_json.get('is_admin'), False) self.assertEqual(user_json.get('has_2fa'), True) self.assertEqual(user_json.get('is_owner'), "") def test_empty_slack_response(self): self.su.name = "suser" self.mock_api_call.side_effect = ["{}"] yield from self.su.retrieve_slack_user_info(self.slack_connection, "fake123") expected_call = call("users.info", user="******") self.assertEqual(self.mock_api_call.mock_calls, [expected_call]), self.assertEqual(self.su.name, "suser") self.assertEqual(self.su.last_name, "") self.assertEqual(self.su.is_bot, "") def test_no_profile_key(self): self.su.name = "suser" user_info = {"ok": True, "user": {"id": "U023BECGF", "name": "bobby"}} self.mock_api_call.side_effect = [json.dumps(user_info)] yield from self.su.retrieve_slack_user_info(self.slack_connection, "fake123") expected_call = call("users.info", user="******") self.assertEqual(self.mock_api_call.mock_calls, [expected_call]), self.assertEqual(self.su.name, "bobby") self.assertEqual(self.su.id, "U023BECGF") self.assertEqual(self.su.last_name, "") self.assertEqual(self.su.is_bot, "") def test_with_profile_key(self): self.su.name = "suser" user_info = { "ok": True, "user": { "id": "U023BECGF", "name": "bobby", "profile": { "real_name": "Bobby Tables", "image_24": "https://www.tables.com", } } } self.mock_api_call.side_effect = [json.dumps(user_info)] yield from self.su.retrieve_slack_user_info(self.slack_connection, "fake123") expected_call = call("users.info", user="******") self.assertEqual(self.mock_api_call.mock_calls, [expected_call]), self.assertEqual(self.su.name, "bobby") self.assertEqual(self.su.id, "U023BECGF") self.assertEqual(self.su.real_name, "Bobby Tables") self.assertEqual(self.su.image_24, "https://www.tables.com") self.assertEqual(self.su.is_bot, "")
class RundeckLock(object): def __init__(self, token, url, channel, jobs): self.log = logging.getLogger(__name__) self.rundeck_token = token self.rundeck_url = url self.topic_channel = channel self.topic_channel_id = None self.slack = SlackConnection() self.locked_by_user = "" self.rundeck_jobs = [] self.rd_jobs_raw_list = jobs self.seed_job_list() @asyncio.coroutine def populate_slack_user_object(self, username): # pragma: no cover slack_user = SlackUser() yield from slack_user.retrieve_slack_user_info(self.slack, username) return slack_user @asyncio.coroutine def toggle_rundeck_lock(self, slack_message, lock_job): """ Coordinating function to toggle the Rundeck lock from open to locked, or visa versa. This is the user-triggered function. """ slack_user = yield from self.populate_slack_user_object(slack_message.user) # NOQA if not self.is_user_authorized_to_lock(slack_user): fail_msg = "Sorry <@%s>, you are not allowed to lock Rundeck executions." % slack_user.name # NOQA self.log.warning(fail_msg) yield from self.slack.send_channel_message(slack_message.channel, fail_msg) return self.locked_by_user = slack_user.name tasks = [] for job in self.rundeck_jobs: tasks.append(self.lock_or_unlock_rundeck_job(job, lock_job)) yield from asyncio.gather(*tasks) self.log.info("Rundeck jobs locked: %s" % lock_job) self.log.info("Job state toggled by @%s" % slack_user.name) full_slack_msg = self.get_execution_status_message(lock_job) yield from self.set_channel_topic(lock_job) yield from self.slack.send_channel_message(slack_message.channel, full_slack_msg) yield from self.print_lock_status(slack_message) @asyncio.coroutine def get_topic_channel_id(self): if not self.topic_channel: return None if self.topic_channel_id: return self.topic_channel_id channel_list = yield from self.slack.api_call('channels.list', exclude_archived=1) json_list = json.loads(channel_list) for channel in json_list['channels']: if channel['name'] == self.topic_channel: self.topic_channel_id = channel['id'] return self.topic_channel_id return None @asyncio.coroutine def lock_or_unlock_rundeck_job(self, rundeck_job_obj, lock_job): """ Lock the job associated with this RundeckJob object """ verb = "enable" if lock_job: verb = "disable" url = "%s/execution/%s" % (rundeck_job_obj.href, verb) headers = { "Accept": "application/json", "X-Rundeck-Auth-Token": self.rundeck_token, } response = yield from http_post_request(url, headers) if response: rundeck_job_obj.execution_enabled = lock_job @asyncio.coroutine def trigger_rundeck_executions_allowed_update(self): tasks = [] for job in self.rundeck_jobs: tasks.append(self.update_rundeck_job_execution_enabled_status(job)) yield from asyncio.gather(*tasks) @asyncio.coroutine def update_rundeck_job_execution_enabled_status(self, rundeck_job_obj): """ Update the execution_enabled flag for this RundeckJob object to reflect reality """ url = "%s" % rundeck_job_obj.href headers = { "Accept": "application/xml", # As of Rundeck 2.6.2, this endpoint # does not return json :( "X-Rundeck-Auth-Token": self.rundeck_token, } response = yield from http_get_request(url, headers, {}) xml_root = etree.fromstring(response) execution_enabled = xml_root[0].find("executionEnabled").text rundeck_job_obj.execution_enabled = False if execution_enabled == "true": rundeck_job_obj.execution_enabled = True def get_execution_status_message(self, lock_job): """ Return an appropriate user-facing message """ if lock_job: return ":lock: Rundeck executions locked by <@%s> :lock:" % self.locked_by_user # NOQA return ":white_check_mark: Rundeck executions unlocked! :white_check_mark:" # NOQA @asyncio.coroutine def set_channel_topic(self, lock_job): topic_channel_id = yield from self.get_topic_channel_id() if not topic_channel_id: return topic_message = "" if lock_job: topic_message = ":lock: Rundeck executions locked by @%s :lock:" % self.locked_by_user # NOQA yield from self.slack.api_call('channels.setTopic', channel=topic_channel_id, topic=topic_message) @asyncio.coroutine def print_lock_status(self, slack_message): """ Print the status of the Rundeck lock (whether open or locked) """ yield from self.trigger_rundeck_executions_allowed_update() out_message = [] out_message.append("*Rundeck Job Lock Report*") out_message.append("```") for job in self.rundeck_jobs: if job.execution_enabled: out_message.append("%s: unlocked" % job.friendly_name) else: out_message.append("%s: locked" % job.friendly_name) out_message.append("```") yield from self.slack.send_channel_message(slack_message.channel, "\n".join(out_message)) def is_user_authorized_to_lock(self, slack_user_obj): """ Returns True or False, depending on whether this user is authorized to lock rundeck executions. """ return slack_user_obj.is_admin def seed_job_list(self): # pragma: no cover loop = asyncio.get_event_loop() loop.create_task(self.load_rundeck_jobs()) @asyncio.coroutine def load_rundeck_jobs(self): """ Read the rd_jobs_raw_list array and load the information about all those jobs into the `rundeck_jobs` list. """ for job in self.rd_jobs_raw_list: rd_job = RundeckJob(friendly_name=job['friendly_name']) job_loaded_successfully = yield from rd_job.retrieve_rundeck_job_info( # NOQA self.rundeck_token, self.rundeck_url, job['project'], job['name'] ) if not job_loaded_successfully: self.log.warning("Could not retrieve job info for: %s" % job['friendly_name']) # NOQA continue self.log.info("Retrieved Rundeck info for job: %s" % job['friendly_name']) # NOQA self.rundeck_jobs.append(rd_job)
class TestSlackUser(asynctest.TestCase): def setUp(self): patcher1 = patch('charlesbot.slack.slack_connection.SlackConnection.api_call') # NOQA self.addCleanup(patcher1.stop) self.mock_api_call = patcher1.start() from charlesbot.slack.slack_connection import SlackConnection self.slack_connection = SlackConnection() from charlesbot.slack.slack_user import SlackUser self.su = SlackUser() def tearDown(self): self.slack_connection._drop() @asynctest.ignore_loop def test_user_equality(self): from charlesbot.slack.slack_user import SlackUser user1 = SlackUser(id="SU01", name="userone", color="red") user2 = SlackUser(id="SU02", name="usertwo", color="blue") self.assertNotEqual(user1, user2) user2.id = "SU01" self.assertNotEqual(user1, user2) user2.name = "userone" self.assertNotEqual(user1, user2) user2.color = "red" self.assertEqual(user1, user2) @asynctest.ignore_loop def test_user_return_string(self): self.su.id = "SU01" self.su.name = "User One" self.su.deleted = False self.su.is_admin = False self.su.has_2fa = True user_json = json.loads(str(self.su)) self.assertEqual(user_json.get('id'), "SU01") self.assertEqual(user_json.get('name'), "User One") self.assertEqual(user_json.get('deleted'), False) self.assertEqual(user_json.get('is_admin'), False) self.assertEqual(user_json.get('has_2fa'), True) self.assertEqual(user_json.get('is_owner'), "") def test_empty_slack_response(self): self.su.name = "suser" self.mock_api_call.side_effect = ["{}"] yield from self.su.retrieve_slack_user_info(self.slack_connection, "fake123") expected_call = call("users.info", user="******") self.assertEqual(self.mock_api_call.mock_calls, [expected_call]), self.assertEqual(self.su.name, "suser") self.assertEqual(self.su.last_name, "") self.assertEqual(self.su.is_bot, "") def test_no_profile_key(self): self.su.name = "suser" user_info = { "ok": True, "user": { "id": "U023BECGF", "name": "bobby" } } self.mock_api_call.side_effect = [json.dumps(user_info)] yield from self.su.retrieve_slack_user_info(self.slack_connection, "fake123") expected_call = call("users.info", user="******") self.assertEqual(self.mock_api_call.mock_calls, [expected_call]), self.assertEqual(self.su.name, "bobby") self.assertEqual(self.su.id, "U023BECGF") self.assertEqual(self.su.last_name, "") self.assertEqual(self.su.is_bot, "") def test_with_profile_key(self): self.su.name = "suser" user_info = { "ok": True, "user": { "id": "U023BECGF", "name": "bobby", "profile": { "real_name": "Bobby Tables", "image_24": "https://www.tables.com", } } } self.mock_api_call.side_effect = [json.dumps(user_info)] yield from self.su.retrieve_slack_user_info(self.slack_connection, "fake123") expected_call = call("users.info", user="******") self.assertEqual(self.mock_api_call.mock_calls, [expected_call]), self.assertEqual(self.su.name, "bobby") self.assertEqual(self.su.id, "U023BECGF") self.assertEqual(self.su.real_name, "Bobby Tables") self.assertEqual(self.su.image_24, "https://www.tables.com") self.assertEqual(self.su.is_bot, "")