def __init__(self, docker_factory, number_of_containers, image_id, volumes_from, ipc_port, checker_jar_path):
     self.number_of_containers = number_of_containers
     self._barriers = {
         # Barrier which ensures that the creation of all containers starts
         #(approximately) at the same moment.
         # (it is probably unuseful as container creation takes no so much time)
         'init': Barrier(number_of_containers + 1),  # Waiting thread
         # No container will start before passing it
         'before_save': Barrier(number_of_containers + 1),  # Waiting thread
         # No container will be stopped before passing it
         'end': Barrier(number_of_containers + 1),  # Response time measuring thread
         'ready': Barrier (2),  # Response time measuring thread
     };
     self.docker_factory = docker_factory
     self.allocate = self.docker_factory.create()
     self.image_id = image_id
     self._volumes_from = volumes_from
     self._ipc_port = ipc_port
     self._rmeter = ResponseTimeMeter(checker_jar_path, self._ipc_port)
     self._dmeter = DockerMeter(self.allocate)
 def __init__(self, docker_factory, number_of_containers, image_id, volumes_from, ipc_port, checker_jar_path):
     self.number_of_containers = number_of_containers
     self._barriers = {
         # Barrier which ensures that the creation of all containers starts
         # (approximately) at the same moment.
         # (it is probably unuseful as container creation takes no so much time)
         "init": Barrier(number_of_containers + 1),  # Waiting thread
         # No container will start before passing it
         "before_save": Barrier(number_of_containers + 1),  # Waiting thread
         # No container will be stopped before passing it
         "end": Barrier(number_of_containers + 1),  # Response time measuring thread
         "ready": Barrier(2),  # Response time measuring thread
     }
     self.docker_factory = docker_factory
     self.allocate = self.docker_factory.create()
     self.image_id = image_id
     self._volumes_from = volumes_from
     self._ipc_port = ipc_port
     self._rmeter = ResponseTimeMeter(checker_jar_path, self._ipc_port)
     self._dmeter = DockerMeter(self.allocate)
class TestRun(object):
    """
    It takes measures at run-level and stores them.
    This includes things that are only checked once (e.g., response time for the last created container) and
    differences between before and after a run.
    """
    def __init__(self, docker_factory, number_of_containers, image_id, volumes_from, ipc_port, checker_jar_path):
        self.number_of_containers = number_of_containers
        self._barriers = {
            # Barrier which ensures that the creation of all containers starts
            #(approximately) at the same moment.
            # (it is probably unuseful as container creation takes no so much time)
            'init': Barrier(number_of_containers + 1),  # Waiting thread
            # No container will start before passing it
            'before_save': Barrier(number_of_containers + 1),  # Waiting thread
            # No container will be stopped before passing it
            'end': Barrier(number_of_containers + 1),  # Response time measuring thread
            'ready': Barrier (2),  # Response time measuring thread
        };
        self.docker_factory = docker_factory
        self.allocate = self.docker_factory.create()
        self.image_id = image_id
        self._volumes_from = volumes_from
        self._ipc_port = ipc_port
        self._rmeter = ResponseTimeMeter(checker_jar_path, self._ipc_port)
        self._dmeter = DockerMeter(self.allocate)

    def _save_container(self, dao, container, run_id):
        session = dao.get_session()
        c = Container(docker_id=container.get('Id'), run_id=run_id)
        session.add(c)
        session.commit()
        return c

    def _start_container_and_measure(self, container_id, docker_id, docker_factory, ready_barrier):
        container = RunningContainer(container_id, docker_id, docker_factory.create(), self._dmeter.get_container_meter(docker_id))
        args = (self._barriers['before_save'], self._barriers['end'], ready_barrier)
        thread = start_daemon(target=container.run, args=args, begin_barrier=self._barriers['init'])
        return thread, container

    def _run_container(self, last_container, dao, run_id):
        # For Docker: run = create + start
        volumes_from = [] if not self._volumes_from else [v for v in self._volumes_from.split(',')]
        ports = { 39000: self._ipc_port, 5900: None } if last_container else {}
        with self.allocate() as docker:
            host_config = docker.create_host_config(port_bindings = ports, volumes_from=volumes_from)
            container = docker.create_container(image = self.image_id,
                                                ports = list(ports.keys()),
                                                host_config = host_config)
        db_cont = self._save_container(dao, container, run_id)
        logging.info('Container "%s" created.' % db_cont.docker_id)
        if container.get('Warnings'):
            logging.debug('Warnings on the creation: ' + container.get('Warnings'))
        return self._start_container_and_measure( db_cont.id, db_cont.docker_id, self.docker_factory,
                                                    self._barriers['ready'] if last_container else None )

    def run(self, dao, run_id):
        thread_containers = []  # Array of tuples (thread, container)
        self._record_init_disk_size()
        for n in range(self.number_of_containers):
            # n+1 is the last created container, we measure its response time
            # to see if it takes more time for it to give a response as the scale increases.
            last_container = n+1==self.number_of_containers
            thread_containers.append( self._run_container(last_container, dao, run_id) )

        start_daemon(self._rmeter.measure, args=(20,),
                        begin_barrier=self._barriers['ready'],
                        end_barrier=self._barriers['end'])
        # It ensures that containers run for at least 5 seconds
        start_daemon(target=wait_at_least, args=(5,),
                        begin_barrier=self._barriers['init'],
                        end_barrier=self._barriers['before_save'])

        session = dao.get_session()
        # Waits for the rest of the threads
        for thread, container in thread_containers:
            thread.join()
            if container.thrown_exception:
                container.save_error(session)
            else:
                container.save_measures(session)

        # while it is running a container consumes less disk
        self._save(session, run_id)

        for _, container in thread_containers:
            container.remove()

    def _record_init_disk_size(self):
        self._dmeter.record_init_disk_size()

    def _save_disk_size(self, session, run_id, size):
        d = DiskRequired(run_id=run_id, size=size)
        session.add(d)
        session.commit()

    def _save_response_time(self, session, run_id, response_time):
        s = ResponseTime(run_id=run_id, time=response_time)
        session.add(s)
        session.commit()

    def _save(self, session, run_id):
        self._save_disk_size(session, run_id, self._dmeter.get_disk_size_increase())
        self._save_response_time(session, run_id, self._rmeter.response_time)
class TestRun(object):
    """
    It takes measures at run-level and stores them.
    This includes things that are only checked once (e.g., response time for the last created container) and
    differences between before and after a run.
    """

    def __init__(self, docker_factory, number_of_containers, image_id, volumes_from, ipc_port, checker_jar_path):
        self.number_of_containers = number_of_containers
        self._barriers = {
            # Barrier which ensures that the creation of all containers starts
            # (approximately) at the same moment.
            # (it is probably unuseful as container creation takes no so much time)
            "init": Barrier(number_of_containers + 1),  # Waiting thread
            # No container will start before passing it
            "before_save": Barrier(number_of_containers + 1),  # Waiting thread
            # No container will be stopped before passing it
            "end": Barrier(number_of_containers + 1),  # Response time measuring thread
            "ready": Barrier(2),  # Response time measuring thread
        }
        self.docker_factory = docker_factory
        self.allocate = self.docker_factory.create()
        self.image_id = image_id
        self._volumes_from = volumes_from
        self._ipc_port = ipc_port
        self._rmeter = ResponseTimeMeter(checker_jar_path, self._ipc_port)
        self._dmeter = DockerMeter(self.allocate)

    def _save_container(self, dao, container, run_id):
        session = dao.get_session()
        c = Container(docker_id=container.get("Id"), run_id=run_id)
        session.add(c)
        session.commit()
        return c

    def _start_container_and_measure(self, container_id, docker_id, docker_factory, ready_barrier):
        container = RunningContainer(
            container_id, docker_id, docker_factory.create(), self._dmeter.get_container_meter(docker_id)
        )
        args = (self._barriers["before_save"], self._barriers["end"], ready_barrier)
        thread = start_daemon(target=container.run, args=args, begin_barrier=self._barriers["init"])
        return thread, container

    def _run_container(self, last_container, dao, run_id):
        # For Docker: run = create + start
        volumes_from = [] if not self._volumes_from else [v for v in self._volumes_from.split(",")]
        ports = {39000: self._ipc_port, 5900: None} if last_container else {}
        with self.allocate() as docker:
            host_config = docker.create_host_config(port_bindings=ports, volumes_from=volumes_from)
            container = docker.create_container(image=self.image_id, ports=list(ports.keys()), host_config=host_config)
        db_cont = self._save_container(dao, container, run_id)
        logging.info('Container "%s" created.' % db_cont.docker_id)
        if container.get("Warnings"):
            logging.debug("Warnings on the creation: " + container.get("Warnings"))
        return self._start_container_and_measure(
            db_cont.id, db_cont.docker_id, self.docker_factory, self._barriers["ready"] if last_container else None
        )

    def run(self, dao, run_id):
        thread_containers = []  # Array of tuples (thread, container)
        self._record_init_disk_size()
        for n in range(self.number_of_containers):
            # n+1 is the last created container, we measure its response time
            # to see if it takes more time for it to give a response as the scale increases.
            last_container = n + 1 == self.number_of_containers
            thread_containers.append(self._run_container(last_container, dao, run_id))

        start_daemon(
            self._rmeter.measure, args=(20,), begin_barrier=self._barriers["ready"], end_barrier=self._barriers["end"]
        )
        # It ensures that containers run for at least 5 seconds
        start_daemon(
            target=wait_at_least,
            args=(5,),
            begin_barrier=self._barriers["init"],
            end_barrier=self._barriers["before_save"],
        )

        session = dao.get_session()
        # Waits for the rest of the threads
        for thread, container in thread_containers:
            thread.join()
            if container.thrown_exception:
                container.save_error(session)
            else:
                container.save_measures(session)

        # while it is running a container consumes less disk
        self._save(session, run_id)

        for _, container in thread_containers:
            container.remove()

    def _record_init_disk_size(self):
        self._dmeter.record_init_disk_size()

    def _save_disk_size(self, session, run_id, size):
        d = DiskRequired(run_id=run_id, size=size)
        session.add(d)
        session.commit()

    def _save_response_time(self, session, run_id, response_time):
        s = ResponseTime(run_id=run_id, time=response_time)
        session.add(s)
        session.commit()

    def _save(self, session, run_id):
        self._save_disk_size(session, run_id, self._dmeter.get_disk_size_increase())
        self._save_response_time(session, run_id, self._rmeter.response_time)