Ejemplo n.º 1
0
 def __init__(self, reactor, checker, intIF, port):
     """ Initialize the RoboEarth Cloud Engine realm.
         
         @param reactor:     Twisted reactor used in this process.
         @type  reactor:     twisted::reactor
         
         @param checker:     Login checker which authenticates the User when
                             an initial request is received.
         @type  checker:     twisted.cred.checkers.ICredentialsChecker
         
         @param intIF:       Name of network interface used for internal
                             communication.
         @type  intIF:       str
         
         @param port:        Port where the robot process is listening for
                             connections to other endpoints.
         @type  port:        int
     """
     self._reactor = reactor
     self._checker = checker
     self._intIF = intIF
     self._port = port
     
     self._network = Network()
     self._balancer = self.LOAD_BALANCER_CLS(self)
     self._distributor = self.DISTRIBUTOR_CLS()
     
     self._users = {}
     self._pendingContainer = {}
     
     self._intIP = None
Ejemplo n.º 2
0
class RoboEarthCloudEngine(object):
    """ Realm for the twisted cred system. It is responsible for storing all
        cloud engine relevant informations by having a reference to a Network,
        Load Balancer, and Distributor instance, where each is responsible for
        part of the system. Additionally, the realm keeps a list of all User
        object.
        
        There should be only one instance running in the Master process.
    """
    implements(IRealm)
    
    # CONFIG
    MAX_ROBOTS = 10
    LOAD_BALANCER_CLS = LoadBalancer
    DISTRIBUTOR_CLS = Distributor
    
    def __init__(self, reactor, checker, intIF, port):
        """ Initialize the RoboEarth Cloud Engine realm.
            
            @param reactor:     Twisted reactor used in this process.
            @type  reactor:     twisted::reactor
            
            @param checker:     Login checker which authenticates the User when
                                an initial request is received.
            @type  checker:     twisted.cred.checkers.ICredentialsChecker
            
            @param intIF:       Name of network interface used for internal
                                communication.
            @type  intIF:       str
            
            @param port:        Port where the robot process is listening for
                                connections to other endpoints.
            @type  port:        int
        """
        self._reactor = reactor
        self._checker = checker
        self._intIF = intIF
        self._port = port
        
        self._network = Network()
        self._balancer = self.LOAD_BALANCER_CLS(self)
        self._distributor = self.DISTRIBUTOR_CLS()
        
        self._users = {}
        self._pendingContainer = {}
        
        self._intIP = None
    
    def requestAvatar(self, avatarId, mind, *interfaces):
        """ Returns Avatar for slave processes of the cloud engine.
            
            Implementation for IRealm
        """
        if IPerspective not in interfaces:
            raise NotImplementedError('RoboEarthCloudEngine only '
                                      'handles IPerspective.')
        
        # There are three possible roles (=avatarId):
        #     'container', 'robot', and 'environment'
        if avatarId == 'container':
            machine = self._balancer.createMachine(mind[0], mind[1])
            avatar = Avatar() # TODO: At the moment does nothing
            detach = lambda: self._balancer.destroyMachine(machine)
            print('Connection to Container process established.')
        elif avatarId == 'robot':
            endpoint = RobotEndpoint(self._network, self._distributor, self,
                                     self._port)
            endpoint.callback(mind)
            avatar = Avatar() # TODO: At the moment does nothing
            detach = lambda: endpoint.destroy()
            print('Connection to Robot process established.')
        elif avatarId == 'environment':
            endpoint = self._pendingContainer.pop(mind[1])
            endpoint.callback(mind[0])
            avatar = Avatar() # TODO: At the moment does nothing
            detach = lambda: endpoint.destroy()
            print('Connection to Environment process established.')
        else:
            raise InternalError('Invalid avatar ID received.')
        
        return IPerspective, avatar, detach
    
    def _getUser(self, userID):
        if userID not in self._users:
            self._users[userID] = User(self, userID)
        
        return self._users[userID]
    
    def getInternalIP(self):
        """ Get the IP address of the network interface used for the internal
            communication.
            
            @return:            IP address of the network interface.
            @rtype:             str
        """
        if self._intIP is None:
            self._intIP = getIP(self._intIF)
        
        return self._intIP
    
    def requestUser(self, userID, robotID, password):
        """ Callback for client protocol to initialize the connection by
            authenticating himself and announcing the robot's ID.
            
            @param userID:      User ID under which the robot will login.
            @type  userID:      str
            
            @param robotID:     ID of the robot which will be using the cloud
                                engine.
            @type  robotID:     str
            
            @param password:    Password matching the User ID for login.
            @type  password:    str
            
            @return:            Key which should be used to authenticate the
                                websocket connection and the IP address of
                                responsible robot process as a tuple.
            @rtype:             twisted::Deferred
        """
        # Check if the credentials are correct
        d = self._checker.requestAvatarId(UsernamePassword(userID, password))
        
        # Create the robot
        d.addCallback(lambda uID: self._getUser(uID).createRobot(robotID))
        
        return d
    
    def createRobot(self, user, robotID, uid):
        """ Callback for User instance to create a new Robot object in a
            robot process.
            
            @param user:        User instance under which the robot has logged
                                in and will run. (Owner of the robot)
            @type  user:        rce.master.user.User
                                (subclass of twisted.spread.pb.Referenceable)
            
            @param robotID:     ID of the robot which has to be created.
            @type  robotID:     str
            
            @param uid:         Key which will be used to authenticate the
                                websocket connection.
            @type  uid:         str
            
            @return:            New Robot instance.
            @rtype:             rce.master.robot.Robot
                                (subclass of rce.master.base.Proxy)
        """
        try:
            location = self._distributor.getNextLocation()
        except RobotProcessError:
            # TODO: What should we do here?
            raise InternalError('Robot can not be created.')
        
        return location.createNamespace(user, robotID, uid)
    
    def createContainer(self):
        """ Callback for User instance to create a new Container object in a
            container process.
            
            @return:            New Namespace and Container instance.
            @rtype:             (rce.master.environment.Environment,
                                 rce.master.container.Container)
                                (subclasses of rce.master.base.Proxy)
        """
        while 1:
            uid = uuid4().hex
            
            if uid not in self._pendingContainer:
                break
        
        try:
            container = self._balancer.createContainer(uid)
        except ContainerProcessError:
            # TODO: What should we do here?
            raise InternalError('Container can not be created.')
        
        endpoint = EnvironmentEndpoint(self._network, container)
        self._pendingContainer[uid] = endpoint
        return endpoint.createNamespace(), container
    
    def createConnection(self, interfaceA, interfaceB):
        """ Callback for User instance to create a new connection between two
            interfaces.
            
            @param interfaceX:  Interface which should be connected.
            @type  interfaceX:  rce.master.network.Interface
            
            @return:            New Connection instance.
            @rtype:             rce.master.network.Connection
        """
        return self._network.createConnection(interfaceA, interfaceB)
    
    def preShutdown(self):
        """ Method is executed by the twisted reactor when a shutdown event
            is triggered, before the reactor is being stopped.
        """
        for user in self._users.values():
            user.destroy()
    
    def postShutdown(self):
        """ Method is executed by the twisted reactor when a shutdown event
            is triggered, after the reactor has been stopped.
        """
        self._network.cleanUp()
        self._balancer.cleanUp()
        self._distributor.cleanUp()