Example #1
0
    def __init__(self, checker, port):
        """ Initialize the RoboEarth Cloud Engine realm.

            @param checker:     Login checker which authenticates the User when
                                an initial request is received.
            @type  checker:     twisted.cred.checkers.ICredentialsChecker

            @param port:        Port where the robot process is listening for
                                connections from other endpoints.
            @type  port:        int
        """
        self._checker = checker
        self._port = port

        self._network = Network()
        self._balancer = LoadBalancer()
        self._distributor = Distributor()

        self._users = {}
        self._pendingContainer = {}
Example #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, IMasterRealm)

    def __init__(self, checker, port):
        """ Initialize the RoboEarth Cloud Engine realm.

            @param checker:     Login checker which authenticates the User when
                                an initial request is received.
            @type  checker:     twisted.cred.checkers.ICredentialsChecker

            @param port:        Port where the robot process is listening for
                                connections from other endpoints.
            @type  port:        int
        """
        self._checker = checker
        self._port = port

        self._network = Network()
        self._balancer = LoadBalancer()
        self._distributor = Distributor()

        self._users = {}
        self._pendingContainer = {}

    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 = MachineAvatar(machine, self._balancer)
            detach = lambda: avatar.logout()
            print('Connection to Container process established.')
        elif avatarId == 'robot':
            endpoint = RobotEndpoint(self._network, self._distributor,
                                     self._port)
            endpoint.callback(mind)
            avatar = RobotEndpointAvatar(self, endpoint)
            detach = lambda: avatar.logout()
            print('Connection to Robot process established.')
        elif avatarId == 'environment':
            endpoint = self._pendingContainer.pop(mind[1])
            endpoint.callback(mind[0])
            avatar = EnvironmentEndpointAvatar(self, endpoint)
            detach = lambda: avatar.logout()
            print('Connection to Environment process established.')
        else:
            raise InternalError('Invalid avatar ID received.')

        return IPerspective, avatar, detach

    def getUser(self, userID):
        """ Get the user object matching the given user ID.

            @param userID:      user ID of the user which should be retrieved.
            @type  userID:      str

            @return:            User object matching the user ID.
            @rtype:             rce.core.user.User
        """
        if userID not in self._users:
            self._users[userID] = User(self, userID)

        return self._users[userID]

    def requestURL(self, userID):
        """ Callback for Robot resource to retrieve the location of the Robot
            process to which a WebSocket connection should be established.

            @param userID:      User ID under which the robot will login.
                                (Can be used to do optimizations in distributing
                                the load.)
            @type  userID:      str

            @return:            The IP address of Robot process to which a
                                WebSocket connection should be established.
                                (type: str)
            @rtype:             twisted.internet.defer.Deferred
        """
        try:
            location = self._distributor.getNextLocation()
        except RobotProcessError:
            # TODO: What should we do here?
            raise InternalError('Robot can not be created.')

        return location.getWebsocketAddress()

    def createContainer(self, userID, data):
        """ Callback for User instance to create a new Container object in a
            container process.

            @param userID:      UserID of the user who created the container.
            @type  userID:      str

            @param data:        Extra data which is used to configure the
                                container.
            @param data:        dict

            @return:            New Namespace and Container instance.
            @rtype:             (rce.core.environment.Environment,
                                 rce.core.container.Container)
                                 (subclasses of rce.core.base.Proxy)
        """
        while 1:
            uid = uuid4().hex

            if uid not in self._pendingContainer:
                break

        try:
            container = self._balancer.createContainer(uid, userID, data)
        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 checkUIDValidity(self, uid):
        """Method to check if incoming environment ID is valid.

            @param uid:         UID to be tested.
            @type  uid:         str
        """
        if uid not in self._pendingContainer:
            raise CredentialError('Invalid environment ID.')

    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.core.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()