Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Run post-breach phase in separate thread #758

Merged
merged 3 commits into from
Aug 11, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 11 additions & 3 deletions monkey/infection_monkey/monkey.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import subprocess
import sys
import time
from threading import Thread

import infection_monkey.tunnel as tunnel
from common.network.network_utils import get_host_from_network_location
Expand Down Expand Up @@ -138,9 +139,9 @@ def start(self):
StateTelem(is_done=False, version=get_version()).send()
TunnelTelem().send()

LOG.debug("Starting the post-breach phase.")
self.collect_system_info_if_configured()
PostBreach().execute_all_configured()
LOG.debug("Starting the post-breach phase asynchronously.")
post_breach_phase = Thread(target=self.start_post_breach_phase)
post_breach_phase.start()

LOG.debug("Starting the propagation phase.")
self.shutdown_by_max_depth_reached()
Expand Down Expand Up @@ -230,10 +231,17 @@ def start(self):
if monkey_tunnel:
monkey_tunnel.stop()
monkey_tunnel.join()

post_breach_phase.join()

except PlannedShutdownException:
LOG.info("A planned shutdown of the Monkey occurred. Logging the reason and finishing execution.")
LOG.exception("Planned shutdown, reason:")

def start_post_breach_phase(self):
self.collect_system_info_if_configured()
PostBreach().execute_all_configured()

def shutdown_by_max_depth_reached(self):
if 0 == WormConfiguration.depth:
TraceTelem(MAX_DEPTH_REACHED_MESSAGE).send()
Expand Down
16 changes: 10 additions & 6 deletions monkey/infection_monkey/post_breach/post_breach_handler.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import logging
from multiprocessing.dummy import Pool
from typing import Sequence

from infection_monkey.post_breach.pba import PBA
Expand All @@ -24,12 +25,8 @@ def execute_all_configured(self):
"""
Executes all post breach actions.
"""
for pba in self.pba_list:
try:
LOG.debug("Executing PBA: '{}'".format(pba.name))
pba.run()
except Exception as e:
LOG.error("PBA {} failed. Error info: {}".format(pba.name, e))
pool = Pool(5)
pool.map(self.run_pba, self.pba_list)
Comment on lines +28 to +29
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have you tried this with multithreading? Performance was worse? Processes take longer to spawn, but are truly "parallel". If I/O is long, maybe we don't really need parallel execution, maybe we just need to init all I/O asap?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm importing Pool from multiprocessing.dummy.

multiprocessing.dummy replicates the API of multiprocessing but is no more than a wrapper around the threading module.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahh, I see!

LOG.info("All PBAs executed. Total {} executed.".format(len(self.pba_list)))

@staticmethod
Expand All @@ -38,3 +35,10 @@ def config_to_pba_list() -> Sequence[PBA]:
:return: A list of PBA objects.
"""
return PBA.get_instances()

def run_pba(self, pba):
try:
LOG.debug("Executing PBA: '{}'".format(pba.name))
pba.run()
except Exception as e:
LOG.error("PBA {} failed. Error info: {}".format(pba.name, e))
Comment on lines +41 to +44
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Logging doesn't get messed up?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No? Just that all PBA logs are not logged together now.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What I'm concerned with is the possibility of log showing:

Executing PBA X
Output of PBA Y
Errors of PBA Y

This might be a bit misleading, but I think we'll manage.