<commit_before>"""
Copyright 2015 <NAME>

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
"""

import inspect
import os.path
import subprocess

from MaxiNet.Frontend import maxinet
from tinyrpc.dispatch import public

import configuration
from publisher import Publisher
from rpc_server import RPCServer
import topology
from transmission import Transmission
import transport_api

class NetworkSimulator(object):
    """Implementation of the network simulators public interface.

    This class implements the public interface made available through the RPC
    server.
    This class is singleton. The instance is accessable throught get_instance().

    Attributes:
        publisher: ZeroMQ publisher to publish results asynchronously.
        rpc_server: RPCServer providing this interface.
        __cluster: MaxiNet cluster.
        __experiment: Currently running MaxiNet experiment.
        topology: Topology used by current MaxiNet experiment.
    """

    # Singleton instance
    _INSTANCE = None

    def __init__(self):
        self.publisher = Publisher()
        self.rpc_server = RPCServer(self)

        self.__cluster = maxinet.Cluster()
        self.__experiment = None

        self.topology = None

    def start(self):
        """Start the network simulator."""
        self.__cluster.start()
        # start serving rpc calls forever
        self.rpc_server.serve_forever()

    @public
    def start_simulation(self, topo):
        """RPC: Start a new simulation.

        Starts a new MaxiNet experiment with the given topology. If there is
        an experiment running MaxiNet is reset first.

        Args:
            topo: A dict representing the topology description. A topology
                description has a type, which must correspond to a class in the
                topology module and arguments. The arguments may vary for the
                different topology classes. However, there must always be a list
                of racks. For example:

                {
                    "type" : "FatTree",
                    "arguments" : {
                        "racks" : [ ... ]
                        }
                }

        Returns:
            True on success, False otherwise.
        """
        # Copy transport api executables onto workers
        for worker in self.__cluster.worker:
            dest_dir = transport_api.TransportAPI.REMOTE_TRANSPORT_BIN_PATH
            rm_cmd = "ssh %s rm -rf %s" % (worker.hn(), dest_dir)
            mkdir_cmd = "ssh %s mkdir -p %s" % (worker.hn(), \
                    os.path.dirname(dest_dir))
            copy_cmd = "scp -r ./transport_bin %s:%s" % (worker.hn(), dest_dir)
            subprocess.check_output(rm_cmd.split())
            subprocess.check_output(mkdir_cmd.split())
            subprocess.check_output(copy_cmd.split())

        # Create topology object
        topology_class = None
        for key, value in inspect.getmembers(topology, inspect.isclass):
            if key == topo["type"]:
                topology_class = value
                break
        if not topology_class:
            print("ERROR: topology class \"%s\" not found." % topo["type"])
            return False

        self.topology = topology_class(**topo["arguments"])

        # Reset & start experiment
        if self.__experiment:
            self.__experiment.stop()
        self.__experiment = maxinet.Experiment(self.__cluster, self.topology)
        self.__experiment.setup()


        #start traffGen on all emulated Hosts!

        hostsPerRack = "20"
        flowFile = "~/traffGen/flows.csv"
        scaleFactorSize = "1"
        scaleFactorTime = "150"
        participatory = "false"
        participatorySleep = "0"
        loop = "true"
        config = "/tmp/traffGen.config"
        ipBase = "10.0"

        for host in self.__experiment.hosts:
            ip = host.IP()
            ipAr = ip.split(".")
            hostId = hostsPerRack * (ipAr[2]-1) + ipAr[3]

            host.cmd("~/traffGen/trafficGenerator/trafficGenerator/traffGen --hostsPerRack %s \
            --ipBase %s --hostId %s --flowFile %s --scaleFactorSize %s --scaleFactorTime %s \
            --participatory %s --participatorySleep %s --loop %s --config %s &" % (hostsPerRack, ipBase, hostId,flowFile,scaleFactorSize,scaleFactorTime,participatory,participatorySleep,loop,config ))

        #send start command to all traffGen processes.
        for w in self.__cluster.workers:
            w.run_cmd("killall -s USR2 traffGen &")




        result = {
                "type" : "SIMULATION_STARTED",
                "data" : {}
                }
        self.publisher.publish("DEFAULT", result)

        return True

    @public
    def register_coflow(self, coflow_description):
        """RPC: Register a new coflow.

        Register a new coflow using the current transport API.

        Args:
            coflow_description: Coflow description for the new coflow. This
                conforms to the Varys CoflowDescription and is a json string of
                the following form:
                
                {
                    "name" : "CoflowX",
                    "coflowType" : "DEFAULT",
                    "maxFlows" : 42,<commit_msg>Int vs String vs Philip<commit_after>"""
Copyright 2015 <NAME>

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
"""

import inspect
import os.path
import subprocess

from MaxiNet.Frontend import maxinet
from tinyrpc.dispatch import public

import configuration
from publisher import Publisher
from rpc_server import RPCServer
import topology
from transmission import Transmission
import transport_api

import traceback

class NetworkSimulator(object):
    """Implementation of the network simulators public interface.

    This class implements the public interface made available through the RPC
    server.
    This class is singleton. The instance is accessable throught get_instance().

    Attributes:
        publisher: ZeroMQ publisher to publish results asynchronously.
        rpc_server: RPCServer providing this interface.
        __cluster: MaxiNet cluster.
        __experiment: Currently running MaxiNet experiment.
        topology: Topology used by current MaxiNet experiment.
    """

    # Singleton instance
    _INSTANCE = None

    def __init__(self):
        self.publisher = Publisher()
        self.rpc_server = RPCServer(self)

        self.__cluster = maxinet.Cluster()
        self.__experiment = None

        self.topology = None

    def start(self):
        """Start the network simulator."""
        self.__cluster.start()
        # start serving rpc calls forever
        self.rpc_server.serve_forever()

    @public
    def start_simulation(self, topo):
      try:
        """RPC: Start a new simulation.

        Starts a new MaxiNet experiment with the given topology. If there is
        an experiment running MaxiNet is reset first.

        Args:
            topo: A dict representing the topology description. A topology
                description has a type, which must correspond to a class in the
                topology module and arguments. The arguments may vary for the
                different topology classes. However, there must always be a list
                of racks. For example:

                {
                    "type" : "FatTree",
                    "arguments" : {
                        "racks" : [ ... ]
                        }
                }

        Returns:
            True on success, False otherwise.
        """
        # Copy transport api executables onto workers
        for worker in self.__cluster.worker:
            dest_dir = transport_api.TransportAPI.REMOTE_TRANSPORT_BIN_PATH
            rm_cmd = "ssh %s rm -rf %s" % (worker.hn(), dest_dir)
            mkdir_cmd = "ssh %s mkdir -p %s" % (worker.hn(), \
                    os.path.dirname(dest_dir))
            copy_cmd = "scp -r ./transport_bin %s:%s" % (worker.hn(), dest_dir)
            subprocess.check_output(rm_cmd.split())
            subprocess.check_output(mkdir_cmd.split())
            subprocess.check_output(copy_cmd.split())

        # Create topology object
        topology_class = None
        for key, value in inspect.getmembers(topology, inspect.isclass):
            if key == topo["type"]:
                topology_class = value
                break
        if not topology_class:
            print("ERROR: topology class \"%s\" not found." % topo["type"])
            return False

        self.topology = topology_class(**topo["arguments"])

        # Reset & start experiment
        if self.__experiment:
            self.__experiment.stop()
        self.__experiment = maxinet.Experiment(self.__cluster, self.topology)
        self.__experiment.setup()


        #start traffGen on all emulated Hosts!

        hostsPerRack = 20
        flowFile = "~/traffGen/flows.csv"
        scaleFactorSize = "1"
        scaleFactorTime = "150"
        participatory = "false"
        participatorySleep = "0"
        loop = "true"
        config = "/tmp/traffGen.config"
        ipBase = "10.0"

        for host in self.__experiment.hosts:
            ip = host.IP()
            ipAr = ip.split(".")
            hostId = hostsPerRack * (int(ipAr[2])-1) + int(ipAr[3])

            host.cmd("~/traffGen/trafficGenerator/trafficGenerator/traffGen --hostsPerRack %d \
            --ipBase %s --hostId %s --flowFile %s --scaleFactorSize %s --scaleFactorTime %s \
            --participatory %s --participatorySleep %s --loop %s --config %s &" % (hostsPerRack, ipBase, hostId,flowFile,scaleFactorSize,scaleFactorTime,participatory,participatorySleep,loop,config ))

        #send start command to all traffGen processes.
        for w in self.__cluster.workers:
            w.run_cmd("killall -s USR2 traffGen &")




        result = {
                "type" : "SIMULATION_STARTED",
                "data" : {}
                }
        self.publisher.publish("DEFAULT", result)

        return True
      except:
        traceback.print_exc()

    @public
    def register_coflow(self, coflow_description):
        """RPC: Register a new coflow.

        Register a new coflow using the current transport API.

        Args:
            coflow_description: Coflow description for the new coflow. This
                conforms to the Varys CoflowDescription and is a json string of
                the following form:
                
                {
                    "name" : "CoflowX",
                    "coflowType" : "DEFAULT",
                    "maxFlows" : 42,
{'fraction_non_alphanumeric': 0.08211219977455995, 'fraction_numerical': 0.004161969999132923, 'mean_word_length': 2.090568060021436, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6704537', 'n_tokens_mistral': 3164, 'n_tokens_neox': 2961, 'n_words': 998}