#!/usr/bin/env python
#-*-*- encoding: utf-8 -*-*-
#
# Copyright (C) 2005 onwards University of Deusto
# All rights reserved.
#
# This software is licensed as described in the file COPYING, which
# you should have received as part of this distribution.
#
# This software consists of contributions made by many individuals,
# listed below:
#
# Author: <NAME> <<EMAIL>>
#
from __future__ import print_function, unicode_literals

try:
    import redis
except ImportError:
    REDIS_AVAILABLE = False
else:
    REDIS_AVAILABLE = True

from voodoo.typechecker import typecheck, ITERATION
from voodoo.log import logged
import voodoo.log as log

from weblab.data.experiments import ExperimentId

import weblab.core.coordinator.redis.resource_manager as ResourcesManager
import weblab.core.coordinator.redis.reservations_manager as ReservationsManager
import weblab.core.coordinator.redis.post_reservation as PostReservationDataManager

from weblab.core.coordinator.redis.meta_scheduler import IndependentSchedulerAggregator
from weblab.core.coordinator.redis.no_scheduler import NoScheduler
from weblab.core.coordinator.redis.priority_queue_scheduler import PriorityQueueScheduler
from weblab.core.coordinator.redis.externals.weblabdeusto_scheduler import ExternalWebLabDeustoScheduler
from weblab.core.coordinator.redis.externals.ilab_batch_scheduler import ILabBatchScheduler
from weblab.core.coordinator.resource import Resource

from weblab.core.coordinator.coordinator import AbstractCoordinator
from weblab.core.coordinator.coordinator import  NO_SCHEDULER, PRIORITY_QUEUE, EXTERNAL_WEBLAB_DEUSTO, ILAB_BATCH_QUEUE

COORDINATOR_REDIS_DB       = 'coordinator_redis_db'
COORDINATOR_REDIS_PASSWORD = '<PASSWORD>'
COORDINATOR_REDIS_PORT     = 'coordinator_redis_port'
COORDINATOR_REDIS_HOST     = 'coordinator_redis_host'

class Coordinator(AbstractCoordinator):

    SCHEDULING_SYSTEMS = {
        NO_SCHEDULER           : NoScheduler,
        PRIORITY_QUEUE         : PriorityQueueScheduler,
        EXTERNAL_WEBLAB_DEUSTO : ExternalWebLabDeustoScheduler,
        ILAB_BATCH_QUEUE       : ILabBatchScheduler,
    }

    AGGREGATOR = IndependentSchedulerAggregator

    def __init__(self, locator, cfg_manager, ConfirmerClass = None):
        connection_kwargs = {}
        db       = cfg_manager.get_value(COORDINATOR_REDIS_DB,       None)
        password = cfg_manager.get_value(COORDINATOR_REDIS_PASSWORD, None)
        port     = cfg_manager.get_value(COORDINATOR_REDIS_PORT,     None)
        host     = cfg_manager.get_value(COORDINATOR_REDIS_HOST,     None)
        if db is not None: 
            connection_kwargs['db']       = db
        if password is not None:
            connection_kwargs['password'] = password
        if port is not None:
            connection_kwargs['port']     = port
        if host is not None:
            connection_kwargs['host']     = host
        self.pool = redis.ConnectionPool(**connection_kwargs)
        self._redis_maker = lambda : redis.Redis(connection_pool = self.pool)

        super(Coordinator, self).__init__(self._redis_maker, locator, cfg_manager, ConfirmerClass)

    def stop(self):
        super(Coordinator, self).stop()

        self.pool.disconnect()

    def _initial_clean(self, coordination_configuration_parser):
        external_servers_config = coordination_configuration_parser.parse_external_servers()
        for external_server_str in external_servers_config:
            for resource_type_name in external_servers_config[external_server_str]:
                self.resources_manager.add_experiment_id(ExperimentId.parse(external_server_str), resource_type_name)

    def _initialize_managers(self):
        self.reservations_manager          = ReservationsManager.ReservationsManager(self._redis_maker)
        self.resources_manager             = ResourcesManager.ResourcesManager(self._redis_maker)
        self.post_reservation_data_manager = PostReservationDataManager.PostReservationDataManager(self._redis_maker, self.time_provider)

    @typecheck(Resource, ITERATION(basestring))
    @logged()
    def mark_resource_as_broken(self, resource_instance, messages = []):
        scheduler = self._get_scheduler_per_resource(resource_instance)

        anything_changed = False
        client = self._redis_maker()
        changed = scheduler.removing_current_resource_slot(client, resource_instance)
        anything_changed = anything_changed or changed

        changed = self.resources_manager.mark_resource_as_broken(resource_instance, messages)
        anything_changed = anything_changed or changed

        if anything_changed:
            log.log( Coordinator, log.level.Warning,
                    "Resource %s marked as broken: %r" % (resource_instance, messages) )

            if self.notifications_enabled:
                return self._notify_experiment_status('broken', resource_instance, messages)
        return {}

    def _release_resource_instance(self, experiment_instance_id):
        resource_instance = self.resources_manager.get_resource_instance_by_experiment_instance_id(experiment_instance_id)
        self.resources_manager.release_resource_instance(resource_instance)

    def _delete_reservation(self, reservation_id):
        self.reservations_manager.delete(reservation_id)

    def _clean(self):
        for scheduler in self.schedulers.values():
            scheduler._clean()

        self.reservations_manager._clean()
        self.resources_manager._clean()
        self.post_reservation_data_manager._clean()


#!/usr/bin/env python
#-*-*- encoding: utf-8 -*-*-
#
# Copyright (C) 2005 onwards University of Deusto
# All rights reserved.
#
# This software is licensed as described in the file COPYING, which
# you should have received as part of this distribution.
#
# This software consists of contributions made by many individuals,
# listed below:
#
# Author: <NAME> <<EMAIL>>
#
from __future__ import print_function, unicode_literals

try:
    import redis
except ImportError:
    REDIS_AVAILABLE = False
else:
    REDIS_AVAILABLE = True

from voodoo.typechecker import typecheck, ITERATION
from voodoo.log import logged
import voodoo.log as log

from weblab.data.experiments import ExperimentId

import weblab.core.coordinator.redis.resource_manager as ResourcesManager
import weblab.core.coordinator.redis.reservations_manager as ReservationsManager
import weblab.core.coordinator.redis.post_reservation as PostReservationDataManager

from weblab.core.coordinator.redis.meta_scheduler import IndependentSchedulerAggregator
from weblab.core.coordinator.redis.no_scheduler import NoScheduler
from weblab.core.coordinator.redis.priority_queue_scheduler import PriorityQueueScheduler
from weblab.core.coordinator.redis.externals.weblabdeusto_scheduler import ExternalWebLabDeustoScheduler
from weblab.core.coordinator.redis.externals.ilab_batch_scheduler import ILabBatchScheduler
from weblab.core.coordinator.resource import Resource

from weblab.core.coordinator.coordinator import AbstractCoordinator
from weblab.core.coordinator.coordinator import  NO_SCHEDULER, PRIORITY_QUEUE, EXTERNAL_WEBLAB_DEUSTO, ILAB_BATCH_QUEUE

COORDINATOR_REDIS_DB       = 'coordinator_redis_db'
COORDINATOR_REDIS_PASSWORD = '<PASSWORD>'
COORDINATOR_REDIS_PORT     = 'coordinator_redis_port'
COORDINATOR_REDIS_HOST     = 'coordinator_redis_host'

class Coordinator(AbstractCoordinator):

    SCHEDULING_SYSTEMS = {
        NO_SCHEDULER           : NoScheduler,
        PRIORITY_QUEUE         : PriorityQueueScheduler,
        EXTERNAL_WEBLAB_DEUSTO : ExternalWebLabDeustoScheduler,
        ILAB_BATCH_QUEUE       : ILabBatchScheduler,
    }

    AGGREGATOR = IndependentSchedulerAggregator

    def __init__(self, locator, cfg_manager, ConfirmerClass = None):
        connection_kwargs = {}
        db       = cfg_manager.get_value(COORDINATOR_REDIS_DB,       None)
        password = cfg_manager.get_value(COORDINATOR_REDIS_PASSWORD, None)
        port     = cfg_manager.get_value(COORDINATOR_REDIS_PORT,     None)
        host     = cfg_manager.get_value(COORDINATOR_REDIS_HOST,     None)
        if db is not None: 
            connection_kwargs['db']       = db
        if password is not None:
            connection_kwargs['password'] = password
        if port is not None:
            connection_kwargs['port']     = port
        if host is not None:
            connection_kwargs['host']     = host
        self.pool = redis.ConnectionPool(**connection_kwargs)
        self._redis_maker = lambda : redis.Redis(connection_pool = self.pool)

        super(Coordinator, self).__init__(self._redis_maker, locator, cfg_manager, ConfirmerClass)

    def stop(self):
        super(Coordinator, self).stop()

        self.pool.disconnect()

    def _initial_clean(self, coordination_configuration_parser):
        external_servers_config = coordination_configuration_parser.parse_external_servers()
        for external_server_str in external_servers_config:
            for resource_type_name in external_servers_config[external_server_str]:
                self.resources_manager.add_experiment_id(ExperimentId.parse(external_server_str), resource_type_name)

    def _initialize_managers(self):
        self.reservations_manager          = ReservationsManager.ReservationsManager(self._redis_maker)
        self.resources_manager             = ResourcesManager.ResourcesManager(self._redis_maker)
        self.post_reservation_data_manager = PostReservationDataManager.PostReservationDataManager(self._redis_maker, self.time_provider)

    @typecheck(Resource, ITERATION(basestring))
    @logged()
    def mark_resource_as_broken(self, resource_instance, messages = []):
        scheduler = self._get_scheduler_per_resource(resource_instance)

        anything_changed = False
        client = self._redis_maker()
        changed = scheduler.removing_current_resource_slot(client, resource_instance)
        anything_changed = anything_changed or changed

        changed = self.resources_manager.mark_resource_as_broken(resource_instance, messages)
        anything_changed = anything_changed or changed

        if anything_changed:
            log.log( Coordinator, log.level.Warning,
                    "Resource %s marked as broken: %r" % (resource_instance, messages) )

            if self.notifications_enabled:
                return self._notify_experiment_status('broken', resource_instance, messages)
        return {}

    def _release_resource_instance(self, experiment_instance_id):
        resource_instance = self.resources_manager.get_resource_instance_by_experiment_instance_id(experiment_instance_id)
        self.resources_manager.release_resource_instance(resource_instance)

    def _delete_reservation(self, reservation_id):
        self.reservations_manager.delete(reservation_id)

    def _clean(self):
        for scheduler in self.schedulers.values():
            scheduler._clean()

        self.reservations_manager._clean()
        self.resources_manager._clean()
        self.post_reservation_data_manager._clean()


#!/usr/bin/env python #-*-*- encoding: utf-8 -*-*- # # Copyright (C) 2005 onwards University of Deusto # All rights reserved. # # This software is licensed as described in the file COPYING, which # you should have received as part of this distribution. # # This software consists of contributions made by many individuals, # listed below: # # Author: <NAME> <<EMAIL>> #