Пример #1
0
    def __init__(self,
                 remote="mlcneta.cs.wpi.edu",
                 localdir="./",
                 glommadir="",
                 remotedir="",
                 rootdir="./rdir",
                 datasize="50M",
                 round="0"):
        self.cmd = CommandWrapper()
        self.remote = remote
        self.trialroot = rootdir
        self.glommadir = glommadir
        self.remotedir = remotedir
        self.localdir = localdir

        self.local_udping_path = f"{self.trialroot}/udpLog.txt"
        self.local_pcap_path = f"{self.trialroot}/local.pcap"
        self.remote_pcap_path = f"{self.trialroot}/{self.remote}.pcap"

        self.amount = datasize
        self.round = round

        # Open Log File
        try:
            ERR_FILE = self.localdir + f"/errorlog_trial.txt"
            self.errorlog = open(ERR_FILE, 'a+')
        except:
            raise ValueError("cannot open error log file for trial")
Пример #2
0
    def __init__(self, args):

        # Check singleton
        if ExperimentExecutor.__instance != None:
            raise RuntimeError(
                "Trying To Construct Extra New_Trial in Setup Phase")
        else:
            ExperimentExecutor.__instance = self

        self.args = args
        self.cmd = CommandWrapper()
        # Open Log File
        try:
            ERR_FILE = self.args[
                "EXPERIMENT_DIR_LOCAL"] + f"/errorlog_executor.txt"
            self.errorlog = open(ERR_FILE, 'w+')
        except:
            raise ValueError("cannot open error log file")

        self.cmd.executeOneSCPCommand(
            host="glomma.cs.wpi.edu",
            localFilepath="./GlommaExecutor.py",
            remoteFilepath=self.args["EXPERIMENT_DIR_GLOMMA"],
            raiseOnError=True)

        for m_p in self.args["MACHINE_PROTOCOLS"]:
            machine = m_p[0]
            self.cmd.executeOneSCPCommand(
                host=machine,
                localFilepath="./RemoteExecutor.py",
                remoteFilepath=self.args["EXPERIMENT_DIR_REMOTE"],
                raiseOnError=True)
Пример #3
0
    def __init__(self):
        """
        Init supported fields
        """

        # Check singleton
        if SetupWorker.__instance != None:
            raise RuntimeError("Trying To Construct Extra SetupWorker in Setup Phase")
        else:
            SetupWorker.__instance = self

        # Supported Protocols
        self.supportedProtocols = {"BBR", "CUBIC", "HYBLA", "PCC"}

        # Supported self.supportedMachines [including acronym dictionary for conversion]
        self.supportedMachines = {
            "MLCA": "mlcneta.cs.wpi.edu",
            "MLCB": "mlcnetb.cs.wpi.edu",
            "MLCC": "mlcnetc.cs.wpi.edu",
            "MLCD": "mlcnetd.cs.wpi.edu",
            "mlcneta.cs.wpi.edu": "mlcneta.cs.wpi.edu",
            "mlcnetb.cs.wpi.edu": "mlcnetb.cs.wpi.edu",
            "mlcnetc.cs.wpi.edu": "mlcnetc.cs.wpi.edu",
            "mlcnetd.cs.wpi.edu": "mlcnetd.cs.wpi.edu"
        }

        # Supported Proxy Modes
        self.supportedProxies = {"1", "2", "3"}

        # Default Global Parameters
        self.GLOBAL_PARAMETERS = {
            "EXPERIMENT_NAME": "EXAMPLE_EXPERIMENT",
            "EXPERIMENT_DIR_LOCAL": "./experiment/EXAMPLE_EXPERIMENT/",
            "EXPERIMENT_DIR_GLOMMA":"./experiment/EXAMPLE_EXPERIMENT/",
            "EXPERIMENT_DIR_REMOTE":"./experiment/EXAMPLE_EXPERIMENT/",
            "MACHINE_PROTOCOLS": [["mlcneta.cs.wpi.edu", "cubic"]],
            "PROXY_MODES": ["2", "3"],
            "BDP": 15000000,
            "WMEM": 60000000,
            "UDPING_FLAG": False,
            "VERBOSE": False,
            "SETUP_REPORT": True,
            "DATA_SIZE_AND_ROUNDS": [["1G", "50"]]
        }

        self.__global_parameter_setted = False
        self.__finished_sysconf_generation = False
        self.local_dir = None
        self.mlc_dir = None
        self.glomma_dir = None
        self.glomma_addr = "glomma.cs.wpi.edu"
        self.args = None
        self.cmd = CommandWrapper()
# This is the script to check glomma system configurations
# TODO: Add more checking / testings to this file

from CommandWrapper import CommandWrapper
import re, configparser, inspect

# Initialize cmd instance
cmd = CommandWrapper()


# To mark test functions
def TEST(function):
    function.__is_test__ = True
    return function


class TestFailException(Exception):
    """
    Exception raised for failing customized tests
    """
    def __init__(self, reason=""):
        self.message = reason
        super().__init__(self.message)

    def __str__(self):
        return f'Test Failed for: {self.message}'


# To execute all test methods in a class
def executeAllTestMethods(instance):
    methods = (getattr(instance, name) for name in dir(instance))
Пример #5
0
class Trial:
    def __init__(self,
                 remote="mlcneta.cs.wpi.edu",
                 localdir="./",
                 glommadir="",
                 remotedir="",
                 rootdir="./rdir",
                 datasize="50M",
                 round="0"):
        self.cmd = CommandWrapper()
        self.remote = remote
        self.trialroot = rootdir
        self.glommadir = glommadir
        self.remotedir = remotedir
        self.localdir = localdir

        self.local_udping_path = f"{self.trialroot}/udpLog.txt"
        self.local_pcap_path = f"{self.trialroot}/local.pcap"
        self.remote_pcap_path = f"{self.trialroot}/{self.remote}.pcap"

        self.amount = datasize
        self.round = round

        # Open Log File
        try:
            ERR_FILE = self.localdir + f"/errorlog_trial.txt"
            self.errorlog = open(ERR_FILE, 'a+')
        except:
            raise ValueError("cannot open error log file for trial")

    # Simple SSH Checkings here
    def command_glomma(self, command):
        glomma_executor_path = self.glommadir + "/GlommaExecutor.py"
        out, err = self.cmd.executeOneSSHCommand(
            host="glomma.cs.wpi.edu",
            command=f"python3 {glomma_executor_path} {command}",
            getOut=True,
            raiseOnError=True)

        if "ok" in out:
            return

        if err:
            self.errorlog.write(f"#{self.round} - Glomma: SSH ERROR: {err}"
                                )  # Simple Report mechanism

    def command_remote(self, command):
        remote_executor_path = self.remotedir + "/RemoteExecutor.py"
        out, err = self.cmd.executeOneSSHCommand(
            host=self.remote,
            command=f"python3 {remote_executor_path} {command}",
            getOut=True,
            raiseOnError=True)

        if "ok" in out:
            return

        if err:
            self.errorlog.write(
                f"#{self.round} - {self.remote}: SSH ERROR: {err}"
            )  # Simple Report mechanism

    def start(self):
        # self.command_glomma(command="-C CHECK_ROUTE") # Check Route
        self.command_glomma(command=f"-C CLEANUP")  # CLEANUP G
        self.command_remote(command=f"-C CLEANUP")  # CLEANUP M
        self.command_glomma(
            command=f"-C MAKEDIR -P {self.trialroot}")  # Make Trial Root at G
        self.command_remote(command=f"-C S_UDPING")  # Start UDPING at M
        self.command_glomma(
            command=f"-C S_UDPING -R {self.remote} -P {self.local_udping_path}"
        )  # Start UDPING at G
        self.command_glomma(command=f"-C S_TCPDUMP -P {self.local_pcap_path}"
                            )  # Start TCPDUMP at G
        self.command_remote(command=f"-C S_TCPDUMP")  # Start TCPDUMP at M
        self.command_remote(command=f"-C S_IPERF")  # Start IPERF at M
        self.command_glomma(
            command=f"-C S_IPERF -R {self.remote} -A {self.amount}"
        )  # Start IPERF at G
        self.command_glomma(command=f"-C CLEANUP")  # CLEANUP G
        self.command_remote(command=f"-C CLEANUP")  # CLEANUP M
        self.command_glomma(
            command=f"-C S_SCP_PCAP -R {self.remote} -P {self.remote_pcap_path}"
        )  # Start SCP at G

    def __del__(self):
        # Close The File
        try:
            self.errorlog.close()
        except:
            raise ValueError("cannot close error log for trial")
Пример #6
0
class ExperimentExecutor:

    # Simple way to define singleton in a process
    __instance = None

    @staticmethod
    def getInstance():
        """ Static access method. """
        if ExperimentExecutor.__instance == None:
            ExperimentExecutor()
        return ExperimentExecutor.__instance

    def __init__(self, args):

        # Check singleton
        if ExperimentExecutor.__instance != None:
            raise RuntimeError(
                "Trying To Construct Extra New_Trial in Setup Phase")
        else:
            ExperimentExecutor.__instance = self

        self.args = args
        self.cmd = CommandWrapper()
        # Open Log File
        try:
            ERR_FILE = self.args[
                "EXPERIMENT_DIR_LOCAL"] + f"/errorlog_executor.txt"
            self.errorlog = open(ERR_FILE, 'w+')
        except:
            raise ValueError("cannot open error log file")

        self.cmd.executeOneSCPCommand(
            host="glomma.cs.wpi.edu",
            localFilepath="./GlommaExecutor.py",
            remoteFilepath=self.args["EXPERIMENT_DIR_GLOMMA"],
            raiseOnError=True)

        for m_p in self.args["MACHINE_PROTOCOLS"]:
            machine = m_p[0]
            self.cmd.executeOneSCPCommand(
                host=machine,
                localFilepath="./RemoteExecutor.py",
                remoteFilepath=self.args["EXPERIMENT_DIR_REMOTE"],
                raiseOnError=True)

    #Wrapper For Print
    def PRINT(self, logfile, msg):
        print(msg)
        try:
            logfile.write(msg)
        except:
            print("LOG FILE ERROR")

    # Execute test on a specific machine with specific protocol once
    def executeTestOnce(self,
                        machine,
                        protocol,
                        proxyMode,
                        roundIndex,
                        logfile,
                        dataSize="50M"):
        """
        Method to execute test once on a specific machine with specific protocol once
        @params: machine, protocol: being tested machine and protocol
        @params: roundIndex: current round (most outer loop)
        """

        # Trial Constructor:
        #    def __init__(self, name='experiment', dir='.', local='glomma', remote='mlc1.cs.wpi.edu', data=None)

        # Switch Proxy Mode
        msg = "Switching Proxy Mode to %d\n" % (proxyMode)
        self.PRINT(logfile, msg)

        # SIMPLE CHECKING HERE
        out = self.cmd.executeOneSSHCommand(
            host="glomma.cs.wpi.edu",
            command=f"python3 GlommaExecutor.py -C S_PROXY -A {proxyMode}",
            getOut=True)[0]
        if "OK" not in out:
            self.errorlog.write(
                f"FAIL TO SWITCH PROXY IN ROUND {roundIndex} with {machine}_{protocol}"
            )

        # Print Round Start
        test_start_time = datetime.now()
        test_start_time_str = test_start_time.strftime("%Y-%m-%d-%H-%M-%S")
        msg = "# Round %d %s %s ProxyMode %d Started At : %s\n" % (
            roundIndex, machine, protocol, proxyMode, test_start_time_str)
        self.PRINT(logfile, msg)

        # Trial
        title = f"{self.args['EXPERIMENT_DIR_GLOMMA']}/data/{machine}_{protocol}_Proxy{proxyMode}_{dataSize}_{roundIndex}"  # Title of the trial.
        trial = Trial(localdir=self.args['EXPERIMENT_DIR_LOCAL'],
                      glommadir=self.args['EXPERIMENT_DIR_GLOMMA'],
                      remotedir=self.args['EXPERIMENT_DIR_REMOTE'],
                      rootdir=title,
                      datasize=dataSize,
                      remote=machine)
        trial.start()

        test_end_time = datetime.now()
        test_end_time_str = test_end_time.strftime("%Y-%m-%d-%H-%M-%S")
        duration = divmod((test_end_time - test_start_time).total_seconds(),
                          60)
        msg = """# Round %d %s %s ProxyMode %d Ended At : %s
        Duration: %s \n""" % (roundIndex, machine, protocol, proxyMode,
                              test_end_time_str, str(duration))
        self.PRINT(logfile, msg)

    def __start(self, numOfTests=10, dataSize="50M"):

        # Open Log File
        try:
            LOG_FILE = self.args[
                "EXPERIMENT_DIR_LOCAL"] + f"/{dataSize}_log.txt"
            logfile = open(LOG_FILE, 'w+')
        except:
            raise ValueError("cannot open logfile")
        print_msg = ""

        # Record Start time, and then End Time After Test Ends, for Analysis Purposes
        start_time = datetime.now()
        start_time_str = start_time.strftime("%Y-%m-%d-%H-%M-%S")
        print_msg = f"TEST Started At {start_time_str}\n" \
                    f"Rounds: {numOfTests}"
        self.PRINT(logfile, print_msg)

        # Main Loop For Testing
        current_time_str = ""
        for i in range(numOfTests):

            # Record The Time When A Round Starts
            current_time_str = datetime.now().strftime("%Y-%m-%d-%H-%M-%S")
            print_msg = "\n**************************************** Round %d Started At [ %s ] ****************************************\n" % (
                i, current_time_str)
            self.PRINT(logfile, print_msg)

            # Loop 2: Traverse (Machine, Protocol) groups
            for [machine, protocol] in self.args["MACHINE_PROTOCOLS"]:
                # Record The Time When A (Machine Protocol) Group Starts
                current_time_str = datetime.now().strftime("%Y-%m-%d-%H-%M-%S")
                print_msg = "\n------------------------------ Round %d %s %s Started At [ %s ] ------------------------------\n" % (
                    i, machine, protocol, current_time_str)
                self.PRINT(logfile, print_msg)

                # Loop Body 3: Run Test With Proxy 2 Once and Proxy 3 Once (Machine, Protocol)
                self.executeTestOnce(machine, protocol, 2, i, logfile,
                                     dataSize)
                self.executeTestOnce(machine, protocol, 3, i, logfile,
                                     dataSize)

                # Record The Time When A (Machine Protocol) Group Ends
                current_time_str = datetime.now().strftime("%Y-%m-%d-%H-%M-%S")
                print_msg = "\n------------------------------- Round %d %s %s Ended At [ %s ] -------------------------------\n" % (
                    i, machine, protocol, current_time_str)
                self.PRINT(logfile, print_msg)

            # Record The Time When A Round Ends
            current_time_str = datetime.now().strftime("%Y-%m-%d-%H-%M-%S")
            print_msg = "\n***************************************** Round %d Ended At [ %s ] *****************************************\n" % (
                i, current_time_str)
            self.PRINT(logfile, print_msg)
        # End of Testing Loop

        # Record Test Ending Time and Print Overall Statistics
        end_time = datetime.now()
        end_time_str = end_time.strftime("%Y-%m-%d-%H-%M-%S")
        duration = divmod((end_time - start_time).total_seconds(), 60)
        print_msg = "TEST Ended At " + end_time_str
        self.PRINT(logfile, print_msg)

        print_msg = """ \n\n
        ********** TEST ENDED **********
        Start Time: %s
        End Time: %s
        Duration: %s
        """ % (start_time_str, end_time_str, str(duration))
        self.PRINT(logfile, print_msg)
        # End of Recording

        # Close The File
        try:
            logfile.close()
        except:
            raise ValueError("cannot close logfile")

    def start(self):
        for size_and_round in self.args["DATA_SIZE_AND_ROUNDS"]:
            numoftest = int(size_and_round[1])
            datasize = size_and_round[0]
            self.__start(numOfTests=numoftest, dataSize=datasize)
Пример #7
0
class SetupWorker:

    # Simple way to define singleton in a process
    __instance = None

    @staticmethod
    def getInstance():
        """ Static access method. """
        if SetupWorker.__instance == None:
            SetupWorker()
        return SetupWorker.__instance

    def __init__(self):
        """
        Init supported fields
        """

        # Check singleton
        if SetupWorker.__instance != None:
            raise RuntimeError("Trying To Construct Extra SetupWorker in Setup Phase")
        else:
            SetupWorker.__instance = self

        # Supported Protocols
        self.supportedProtocols = {"BBR", "CUBIC", "HYBLA", "PCC"}

        # Supported self.supportedMachines [including acronym dictionary for conversion]
        self.supportedMachines = {
            "MLCA": "mlcneta.cs.wpi.edu",
            "MLCB": "mlcnetb.cs.wpi.edu",
            "MLCC": "mlcnetc.cs.wpi.edu",
            "MLCD": "mlcnetd.cs.wpi.edu",
            "mlcneta.cs.wpi.edu": "mlcneta.cs.wpi.edu",
            "mlcnetb.cs.wpi.edu": "mlcnetb.cs.wpi.edu",
            "mlcnetc.cs.wpi.edu": "mlcnetc.cs.wpi.edu",
            "mlcnetd.cs.wpi.edu": "mlcnetd.cs.wpi.edu"
        }

        # Supported Proxy Modes
        self.supportedProxies = {"1", "2", "3"}

        # Default Global Parameters
        self.GLOBAL_PARAMETERS = {
            "EXPERIMENT_NAME": "EXAMPLE_EXPERIMENT",
            "EXPERIMENT_DIR_LOCAL": "./experiment/EXAMPLE_EXPERIMENT/",
            "EXPERIMENT_DIR_GLOMMA":"./experiment/EXAMPLE_EXPERIMENT/",
            "EXPERIMENT_DIR_REMOTE":"./experiment/EXAMPLE_EXPERIMENT/",
            "MACHINE_PROTOCOLS": [["mlcneta.cs.wpi.edu", "cubic"]],
            "PROXY_MODES": ["2", "3"],
            "BDP": 15000000,
            "WMEM": 60000000,
            "UDPING_FLAG": False,
            "VERBOSE": False,
            "SETUP_REPORT": True,
            "DATA_SIZE_AND_ROUNDS": [["1G", "50"]]
        }

        self.__global_parameter_setted = False
        self.__finished_sysconf_generation = False
        self.local_dir = None
        self.mlc_dir = None
        self.glomma_dir = None
        self.glomma_addr = "glomma.cs.wpi.edu"
        self.args = None
        self.cmd = CommandWrapper()

    def __check_args__(self):
        if not self.args:
            raise RuntimeError("Setup Phase: Called Setup Global Parameters Before Reads In Arguments")

    def __setupGlobalParameters(self):
        '''
        Method to setup global parameters for trial
        '''

        self.__check_args__()

        # Read config file if specified. Else use default values.
        if self.args.CONFIG_PATH:
            if not os.path.isfile(self.args.CONFIG_PATH):
                raise FileNotFoundError("Setup Phase: Setup Global Parameters: Configuration file does not exists")

            config = configparser.ConfigParser()
            config.read(self.args.CONFIG_PATH)

            # Experiment name
            # TODO: Currently set up directory names based on experiment name, guess it should be fine
            # TODO: Else, read optional EXPERIMENT_DIR_* from set up configuration file
            self.GLOBAL_PARAMETERS["EXPERIMENT_NAME"] = config["GENERAL PARAMETERS"]["EXPERIMENT_NAME"]
            self.GLOBAL_PARAMETERS["EXPERIMENT_DIR_LOCAL"] = f"./experiment/{self.GLOBAL_PARAMETERS['EXPERIMENT_NAME']}"
            self.GLOBAL_PARAMETERS["EXPERIMENT_DIR_GLOMMA"] = f"$HOME/experiment/{self.GLOBAL_PARAMETERS['EXPERIMENT_NAME']}"
            self.GLOBAL_PARAMETERS["EXPERIMENT_DIR_REMOTE"] = f"$HOME/experiment/{self.GLOBAL_PARAMETERS['EXPERIMENT_NAME']}"

            # Process Machine Parameter in Configuration File.
            # Expected Format: MACHINE_PROTOCOLS = {MACHINE}_{PROTOCOL}, separated with comma
            MACHINE_PROTOCOLS = [x.strip() for x in config["GENERAL PARAMETERS"]["MACHINE_PROTOCOLS"].split(",")]
            MACHINE_PROTOCOLS = [x.split("_") for x in MACHINE_PROTOCOLS] # Split machine and protocol

            # Value checking for machine & protocols
            for m_p in MACHINE_PROTOCOLS:
                if m_p[0] not in self.supportedMachines:
                    raise ValueError(f"Machine {m_p[0]} is not a supported machine. Check parameters, or check supported list in TestExecutor.py")
                elif m_p[1] not in self.supportedProtocols :
                    raise ValueError(f"Protocol {m_p[1]} is not a supported protocol. Check parameters, or check supported list in TestExecutor.py")
                m_p[0] = self.supportedMachines[m_p[0]] # Convert acronyms to full remote names
            self.GLOBAL_PARAMETERS["MACHINE_PROTOCOLS"] = MACHINE_PROTOCOLS

            # Read proxy modes. Expected format: {PROXYMODE}, separated with comma
            PROXIES = [x.strip() for x in config["GENERAL PARAMETERS"]["PROXIES"].split(",")]

            for proxy in PROXIES:
                if proxy not in self.supportedProxies:
                    raise ValueError(f"Proxy mode {proxy} is not supported. Check parameters, or check supported list in TestExecutor.py")
            self.GLOBAL_PARAMETERS["PROXY_MODES"] = PROXIES

            # Other general parameters
            self.GLOBAL_PARAMETERS["BDP"] = int(config["GENERAL PARAMETERS"]["BDP"])
            self.GLOBAL_PARAMETERS["WMEM"] = int(myutil.NSP.eval(config["GENERAL PARAMETERS"]["WMEM"])) # Give up using python eval for security concerns

            # Trial related parameters
            self.GLOBAL_PARAMETERS["UDPING_FLAG"] = config["TRIAL PARAMETERS"].getboolean("UDPING")
            self.GLOBAL_PARAMETERS["VERBOSE"] = config["TRIAL PARAMETERS"].getboolean("VERBOSE")
            self.GLOBAL_PARAMETERS["SETUP_REPORT"] = config["TRIAL PARAMETERS"].getboolean("SETUP_REPORT")

            # Read proxy modes. Expected format: {DATASIZE_ROUND}, separated with comma
            DATA_SIZE_AND_ROUNDS = [x.strip() for x in config["TRIAL PARAMETERS"]["DATA_SIZE_AND_ROUNDS"].split(",")]
            for data_round in DATA_SIZE_AND_ROUNDS:
                if not myutil.DSRCHECKER.check(data_round):
                    raise ValueError(f"Datasize_round {data_round} is not supported. Check parameters.")
            DATA_SIZE_AND_ROUNDS = [x.split("_") for x in DATA_SIZE_AND_ROUNDS]  # Split datasize and rounds
            self.GLOBAL_PARAMETERS["DATA_SIZE_AND_ROUNDS"] = DATA_SIZE_AND_ROUNDS

        else:
            self.GLOBAL_PARAMETERS["EXPERIMENT_NAME"] = self.args.TESTNAME

        self.__global_parameter_setted = True
        print("Setup Phase: Global Parameters Set Up Completed")

    def getGlobalParameters(self):
        '''
        Return GLOBAL_PARAMETERS
        '''
        self.__check_args__()

        if not self.__global_parameter_setted:
            self.setupGlobalParameters()

        return self.GLOBAL_PARAMETERS

    def __setupLocalDirectory(self):
        '''
        Method to set up directory at local (where the command to start experiments is executed)
        '''
        self.__check_args__()

        if not self.__global_parameter_setted:
            self.setupGlobalParameters()

        if not os.path.exists(self.GLOBAL_PARAMETERS["EXPERIMENT_DIR_LOCAL"]):
            os.makedirs(self.GLOBAL_PARAMETERS["EXPERIMENT_DIR_LOCAL"])
            print(f"Setup Phase: Made A New Experiment Directory At {self.GLOBAL_PARAMETERS['EXPERIMENT_DIR_LOCAL']}")

        self.local_dir = self.GLOBAL_PARAMETERS["EXPERIMENT_DIR_LOCAL"]
        print("Setup Phase: Local Directory Setup Finished")

    def __setupRemoteDirectory(self):
        """
        Method to set up remote directories (in current version, MLCs + Glomma)
        """
        self.__check_args__()

        # Inner method for check and set a specific directory at host
        def __check_and_set_dir(host, dir_path, debug=False):
            # Inner worker method for check and set a specific sub path at host
            def __inner_worker(dir_path_inner):
                dir_checking_command = f"[ -d {dir_path_inner} ] && echo EXISTS || echo DNE"
                out, err = self.cmd.executeOneSSHCommand(host=host,
                                                         command=dir_checking_command,
                                                         getOut=True, raiseOnError=True)

                if "DNE" in out:
                    self.cmd.executeOneSSHCommand(host=host,
                                                  command=f"mkdir {dir_path_inner}",
                                                  raiseOnError=True)

            # Split the dir into subpaths
            dir_hierachy = dir_path.split("/")

            # Iterate over subpaths, and check_and_set them one by one
            current_dir = ""
            while len(dir_hierachy):
                subpath = dir_hierachy.pop(0) # Get current subpath
                if subpath == "$HOME": # Skip if home
                    current_dir += subpath
                    continue
                current_dir += ("/" + subpath) # Add subpath to current dir
                if debug:
                    print("Current Dir: ", current_dir)
                __inner_worker(current_dir) # Check and set the dir
        # End of Inner Method check_and_set_dir

        # Setup MLC dirs
        for m_p in self.GLOBAL_PARAMETERS["MACHINE_PROTOCOLS"]:
            machine = m_p[0]
            __check_and_set_dir(host=self.supportedMachines[machine], dir_path=self.GLOBAL_PARAMETERS['EXPERIMENT_DIR_REMOTE'])

        # Setup Glomma dir
        __check_and_set_dir(host=self.glomma_addr, dir_path=self.GLOBAL_PARAMETERS['EXPERIMENT_DIR_GLOMMA'])



        print("Setup Phase: Remote Directory Setup Finished")

    def __generateSysConfFiles(self):
        self.__check_args__()

        SCG = SysConfGenerator(self.GLOBAL_PARAMETERS)

        SCG.generateMlcSysConf()
        SCG.generateGlommaSysConf()

        self.__finished_sysconf_generation = True
        print("Setup Phase: System Configuration File Setup Finished")

    def __checkGlommaSysConf(self):
        self.__check_args__()

        if not self.__finished_sysconf_generation or not self.__global_parameter_setted:
            raise RuntimeError("Setup Phase: Called Check Glomma SysConf Before Generated It")

        glomma_sysconf_path = f'{self.GLOBAL_PARAMETERS["EXPERIMENT_DIR_LOCAL"]}/glomma.machine_config'

        # Check if can find Glomma configuration file at local
        if not os.path.isfile(glomma_sysconf_path):
            raise FileNotFoundError("Setup Phase: Check Glomma SysConf: Cannot find file. Bugs exists. "
                                    "Check Generate SysConf Command")

        # First scp over glomma system configuration file, config checker, and command wrapper which config checker needs
        self.cmd.executeOneSCPCommand(host=self.glomma_addr,
                                      localFilepath=glomma_sysconf_path,
                                      remoteFilepath=self.GLOBAL_PARAMETERS["EXPERIMENT_DIR_GLOMMA"],
                                      raiseOnError=True)
        self.cmd.executeOneSCPCommand(host=self.glomma_addr,
                                      localFilepath="./ConfigCheckerGlomma.py",
                                      remoteFilepath=self.GLOBAL_PARAMETERS["EXPERIMENT_DIR_GLOMMA"],
                                      raiseOnError=True)
        self.cmd.executeOneSCPCommand(host=self.glomma_addr,
                                      localFilepath="./CommandWrapper.py",
                                      remoteFilepath=self.GLOBAL_PARAMETERS["EXPERIMENT_DIR_GLOMMA"],
                                      raiseOnError=True)

        # Then run check file
        remote_checker_path = self.GLOBAL_PARAMETERS["EXPERIMENT_DIR_GLOMMA"] + "/ConfigCheckerGlomma.py"
        out = self.cmd.executeOneSSHCommand(host=self.glomma_addr,
                                      command=f"""python3 {remote_checker_path}""",
                                      getOut=True, raiseOnError=True)[0]

        # Process out
        if "False" in out:
            out = out.split("\n")[0]
            raise RuntimeError("Setup Phase: ConfigCheckerGlomma Failed for ", out)

        print("Setup Phase: Glomma System Configuration Checked")

    def __checkRemoteSysConf(self):
        self.__check_args__()

        if not self.__finished_sysconf_generation or not self.__global_parameter_setted:
            raise RuntimeError("Setup Phase: Called Check Remote SysConf Before Generated It")

        def __inner_checking_worker(machine):
            machine_sysconf_path = f'{self.GLOBAL_PARAMETERS["EXPERIMENT_DIR_LOCAL"]}/{machine}.machine_config'

            # Check if can find Machine configuration file at local
            if not os.path.isfile(machine_sysconf_path):
                raise FileNotFoundError(f"Setup Phase: Check {machine} SysConf: Cannot find file. Bugs exists. "
                                        "Check Generate SysConf Command")

            # First scp over machine system configuration file, config checker, and command wrapper which config checker needs
            self.cmd.executeOneSCPCommand(host=machine,
                                          localFilepath=machine_sysconf_path,
                                          remoteFilepath=self.GLOBAL_PARAMETERS["EXPERIMENT_DIR_REMOTE"],
                                          raiseOnError=True)
            self.cmd.executeOneSCPCommand(host=machine,
                                          localFilepath="./ConfigCheckerRemote.py",
                                          remoteFilepath=self.GLOBAL_PARAMETERS["EXPERIMENT_DIR_REMOTE"],
                                          raiseOnError=True)
            self.cmd.executeOneSCPCommand(host=machine,
                                          localFilepath="./CommandWrapper.py",
                                          remoteFilepath=self.GLOBAL_PARAMETERS["EXPERIMENT_DIR_REMOTE"],
                                          raiseOnError=True)

            # Then run check file
            remote_checker_path = self.GLOBAL_PARAMETERS["EXPERIMENT_DIR_REMOTE"] + "/ConfigCheckerRemote.py"
            out = self.cmd.executeOneSSHCommand(host=machine,
                                          command=f"""python3 {remote_checker_path}""",
                                          getOut=True, raiseOnError=True)[0]

            # Process out
            if "False" in out:
                out = out.split("\n")[0]
                raise RuntimeError("Setup Phase: ConfigCheckerRemote Failed for ", out)

        for m_p in self.GLOBAL_PARAMETERS["MACHINE_PROTOCOLS"]:
            machine = m_p[0]
            __inner_checking_worker(machine)
            print(f"Setup Phase: {machine} Configuration Checked")

        print("Setup Phase: All Remote System Configuration Checked")

    def setup(self, args):
        '''
        Reads in command line arguments
        '''
        # if not isinstance(args, argparse.Namespace):
        #     raise TypeError("Setup Phase: Read Arguments: Not argparse.Namespace instance.")
        self.args = args

        # Set up phase executions
        self.__setupGlobalParameters()
        self.__setupLocalDirectory()
        self.__setupRemoteDirectory()
        self.__generateSysConfFiles()
        self.__checkGlommaSysConf()
        self.__checkRemoteSysConf()

        # Report finishing
        # TODO: Add logging to setup phase
        return True