Exemple #1
0
    def process(self, response=None, error=None):
        if error:
            logging.debug("Error during authentication: %r", error)
            self._error(AuthenticationError(error))
            return

        if self._state == "start":
            self._state = "nonce"
            logging.debug("Sending nonce")
            msg = message.query(0, "%s.$cmd" % self.pool._dbname, 0, 1,
                                SON({'getnonce': 1}), SON({}))
            self.connection._send_message(msg, self.process)
        elif self._state == "nonce":
            # this is the nonce response
            self._state = "finish"
            try:
                nonce = response['data'][0]['nonce']
                logging.debug("Nonce received: %r", nonce)
                key = helpers._auth_key(nonce, self.dbuser, self.dbpass)
            except Exception, e:
                self._error(AuthenticationError(e))
                return

            msg = message.query(
                0, "%s.$cmd" % self.pool._dbname, 0, 1,
                SON([('authenticate', 1), ('user', self.dbuser),
                     ('nonce', nonce), ('key', key)]), SON({}))
            self.connection._send_message(msg, self.process)
Exemple #2
0
    def _refresh(self):
        """Refreshes the cursor with more data from Mongo.

        Returns the length of self.__data after refresh. Will exit early if
        self.__data is already non-empty. Raises OperationFailure when the
        cursor cannot be refreshed due to an error on the query.
        """
        if len(self.__data) or self.__killed:
            return len(self.__data)

        if self.__id is None:
            # Query
            self.__send_message(
                message.query(self.__query_options(),
                              self.__collection.full_name(), self.__skip,
                              self.__limit, self.__query_spec(),
                              self.__fields))
            if not self.__id:
                self.__killed = True
        elif self.__id:
            # Get More
            limit = 0
            if self.__limit:
                if self.__limit > self.__retrieved:
                    limit = self.__limit - self.__retrieved
                else:
                    self.__killed = True
                    return 0

            self.__send_message(
                message.get_more(self.__collection.full_name(), limit,
                                 self.__id))

        return len(self.__data)
Exemple #3
0
    def _refresh(self):
        """Refreshes the cursor with more data from Mongo.

        Returns the length of self.__data after refresh. Will exit early if
        self.__data is already non-empty. Raises OperationFailure when the
        cursor cannot be refreshed due to an error on the query.
        """
        if len(self.__data) or self.__killed:
            return len(self.__data)

        if self.__id is None:
            # Query
            self.__send_message(
                message.query(self.__query_options(),
                              self.__collection.full_name(),
                              self.__skip, self.__limit,
                              self.__query_spec(), self.__fields))
            if not self.__id:
                self.__killed = True
        elif self.__id:
            # Get More
            limit = 0
            if self.__limit:
                if self.__limit > self.__retrieved:
                    limit = self.__limit - self.__retrieved
                else:
                    self.__killed = True
                    return 0

            self.__send_message(
                message.get_more(self.__collection.full_name(),
                                 limit, self.__id))

        return len(self.__data)
Exemple #4
0
    def process(self, response=None, error=None):
        if error:
            logging.debug(error)
            logging.debug(response)
            raise AuthenticationError(error)

        if self._state == "start":
            self._state = "nonce"
            logging.debug("Sending nonce")
            msg = message.query(
                0,
                "%s.$cmd" % self.pool._dbname,
                0,
                1,
                SON({'getnonce': 1}),
                SON({})
            )
            self.connection._send_message(msg, self.process)
        elif self._state == "nonce":
            # this is the nonce response
            self._state = "finish"
            nonce = response['data'][0]['nonce']
            logging.debug("Nonce received: %r", nonce)
            key = helpers._auth_key(nonce, self.dbuser, self.dbpass)

            msg = message.query(
                0,
                "%s.$cmd" % self.pool._dbname,
                0,
                1,
                SON([('authenticate', 1),
                     ('user', self.dbuser),
                     ('nonce', nonce),
                     ('key', key)]),
                SON({})
            )
            self.connection._send_message(msg, self.process)
        elif self._state == "finish":
            self._state = "done"
            assert response['number_returned'] == 1
            response = response['data'][0]
            if response['ok'] != 1:
                logging.debug('Failed authentication %s' % response['errmsg'])
                raise AuthenticationError(response['errmsg'])
            self.connection._next_job()
        else:
            raise ValueError("Unexpected state: %s" % self._state)
 def _get_nonce(self, callback):
     assert self.__callback is None
     self.__callback = callback
     self._send_message(
             message.query(0,
                           "%s.$cmd" % self.__pool._dbname, 
                           0,
                           1,
                           SON({'getnonce' : 1}),
                           SON({})
                 ))
Exemple #6
0
    def process(self, response=None, error=None):
        if error:
            logging.debug("Error during authentication: %r", error)
            self._error(AuthenticationError(error))
            return

        if self._state == "start":
            self._state = "nonce"
            logging.debug("Sending nonce")
            msg = message.query(
                0,
                "%s.$cmd" % self.pool._dbname,
                0,
                1,
                SON({'getnonce': 1}),
                SON({})
            )
            self.connection._send_message(msg, self.process)
        elif self._state == "nonce":
            # this is the nonce response
            self._state = "finish"
            try:
                nonce = response['data'][0]['nonce']
                logging.debug("Nonce received: %r", nonce)
                key = helpers._auth_key(nonce, self.dbuser, self.dbpass)
            except Exception, e:
                self._error(AuthenticationError(e))
                return

            msg = message.query(
                0,
                "%s.$cmd" % self.pool._dbname,
                0,
                1,
                SON([('authenticate', 1),
                     ('user', self.dbuser),
                     ('nonce', nonce),
                     ('key', key)]),
                SON({})
            )
            self.connection._send_message(msg, self.process)
Exemple #7
0
    def process(self, response=None, error=None):
        if error:
            logging.debug("Problem connecting: %s", error)

            if self._state == "ismaster":
                self._state = "seed"

        if self._state == "seed":
            if self._sec_only and self._primary:
                # Add primary host to blacklisted to avoid connecting to it
                self._blacklisted.add(self._primary)

            fresh = self.known_hosts ^ self._blacklisted
            logging.debug("Working through the rest of the host list: %r",
                          fresh)

            while fresh:
                if self._primary and self._primary not in self._blacklisted:
                    # Try primary first
                    h = self._primary
                else:
                    h = random.choice(list(fresh))

                if h in fresh:
                    fresh.remove(h)

                # Add tried host to blacklisted
                self._blacklisted.add(h)

                logging.debug("Connecting to %s:%s", *h)
                self.connection._host, self.connection._port = h
                try:
                    self.connection._socket_connect()
                    logging.debug("Connected to %s", h)
                except InterfaceError, e:
                    logging.error("Failed to connect to the host: %s", e)
                else:
                    break

            else:
                self._error(
                    RSConnectionError("No more hosts to try, tried: %s" %
                                      self.known_hosts))
                return

            self._state = "ismaster"
            msg = message.query(options=0,
                                collection_name="admin.$cmd",
                                num_to_skip=0,
                                num_to_return=-1,
                                query=SON([("ismaster", 1)]))
            self.connection._send_message(msg, self.process)
Exemple #8
0
    def process(self, response=None, error=None):
        if error:
            logging.debug("Problem connecting: %s", error)

            if self._state == "ismaster":
                self._state = "seed"

        if self._state == "seed":
            if self._sec_only and self._primary:
                # Add primary host to blacklisted to avoid connecting to it
                self._blacklisted.add(self._primary)

            fresh = self.known_hosts ^ self._blacklisted
            logging.debug("Working through the rest of the host list: %r", fresh)

            while fresh:
                if self._primary and self._primary not in self._blacklisted:
                    # Try primary first
                    h = self._primary
                else:
                    h = random.choice(list(fresh))

                if h in fresh:
                    fresh.remove(h)

                # Add tried host to blacklisted
                self._blacklisted.add(h)

                logging.debug("Connecting to %s:%s", *h)
                self.connection._host, self.connection._port = h
                try:
                    self.connection._socket_connect()
                    logging.debug("Connected to %s", h)
                except InterfaceError, e:
                    logging.error("Failed to connect to the host: %s", e)
                else:
                    break

            else:
                self._error(RSConnectionError("No more hosts to try, tried: %s" % self.known_hosts))
                return

            self._state = "ismaster"
            msg = message.query(
                options=0,
                collection_name="admin.$cmd",
                num_to_skip=0,
                num_to_return=-1,
                query=SON([("ismaster", 1)])
            )
            self.connection._send_message(msg, self.process)
Exemple #9
0
 def _handle_conn(connection):
     try:
         connection.send_message(
             message.query(self.__query_options(),
                           self.full_collection_name,
                           self.__skip,
                           ntoreturn,
                           self.__query_spec(),
                           self.__fields),
             callback=functools.partial(self._handle_response, orig_callback=callback))
     except Exception, e:
         logging.error('Error sending query %s' % e)
         connection.close()
         raise
Exemple #10
0
    def process(self, response=None, error=None):
        if error:
            logging.debug(error)
            logging.debug(response)
            raise AuthenticationError(error)

        if self._state == "start":
            self._state = "nonce"
            logging.debug("Sending nonce")
            msg = message.query(0, "%s.$cmd" % self.pool._dbname, 0, 1, SON({"getnonce": 1}), SON({}))
            self.connection._send_message(msg, self.process)
        elif self._state == "nonce":
            # this is the nonce response
            self._state = "finish"
            nonce = response["data"][0]["nonce"]
            logging.debug("Nonce received: %r", nonce)
            key = helpers._auth_key(nonce, self.dbuser, self.dbpass)

            msg = message.query(
                0,
                "%s.$cmd" % self.pool._dbname,
                0,
                1,
                SON([("authenticate", 1), ("user", self.dbuser), ("nonce", nonce), ("key", key)]),
                SON({}),
            )
            self.connection._send_message(msg, self.process)
        elif self._state == "finish":
            self._state = "done"
            assert response["number_returned"] == 1
            response = response["data"][0]
            if response["ok"] != 1:
                logging.debug("Failed authentication %s" % response["errmsg"])
                raise AuthenticationError(response["errmsg"])
            self.connection._next_job()
        else:
            raise ValueError("Unexpected state: %s" % self._state)
Exemple #11
0
    def _on_get_nonce(self, response, error=None):
        if error:
            raise AuthenticationError(error)
        nonce = response['data'][0]['nonce']
        key = hashlib.md5(nonce + self._dbuser + hashlib.md5(self._dbuser + ":mongo:" + self._dbpass).hexdigest()).hexdigest()

        command = SON([('authenticate', 1)])
        command.update({'user' : self._dbuser, 'nonce' : nonce, 'key' : key})
        self.conn.send_message(
                message.query(0,
                              "%s.$cmd" % self._dbname,
                              0,
                              1,
                              command,
                              SON({})),callback=self._on_authenticate)
Exemple #12
0
    def _start_authentication(self, response, error=None):
        # this is the nonce response
        if error:
            logging.error(error)
            logging.error(response)
            raise AuthenticationError(error)
        nonce = response['data'][0]['nonce']
        key = helpers._auth_key(nonce, self.__dbuser, self.__dbpass)

        self.__callback = self._finish_authentication
        self._send_message(
            message.query(
                0, "%s.$cmd" % self.__pool._dbname, 0, 1,
                SON([('authenticate', 1), ('user', self.__dbuser),
                     ('nonce', nonce), ('key', key)]), SON({})))
Exemple #13
0
        def _handle_connection(connection):
            try:
                if self.__debug:
                    logging.debug('QUERY_SPEC: %r' % self.__query_spec())

                connection.send_message(
                    message.query(self.__query_options(),
                                  self.full_collection_name,
                                  self.__skip,
                                  self.__limit,
                                  self.__query_spec(),
                                  self.__fields),
                    callback=functools.partial(self._handle_response, orig_callback=callback))
            except Exception, e:
                logging.error('Error sending query %s' % e)
                connection.close()
                raise
    def _start_authentication(self, response, error=None):
        # this is the nonce response
        if error:
            logging.error(error)
            logging.error(response)
            raise AuthenticationError(error)
        nonce = response['data'][0]['nonce']
        key = helpers._auth_key(nonce, self.__dbuser, self.__dbpass)

        self.__callback = self._finish_authentication
        self._send_message(
                message.query(0,
                              "%s.$cmd" % self.__pool._dbname,
                              0,
                              1,
                              SON([('authenticate', 1), ('user' , self.__dbuser), ('nonce' , nonce), ('key' , key)]),
                              SON({})))
Exemple #15
0
    def process(self, response=None, error=None):
        if error:
            logging.debug("Problem connecting: %s", error)

            if self._state == "ismaster":
                self._state = "seed"

        if self._state == "seed":
            fresh = self.known_hosts ^ self._tried_hosts
            logging.debug("Working through the rest of the host list: %r", fresh)

            while fresh:
                if self._primary and self._primary not in self._tried_hosts:
                    # Try primary first
                    h = self._primary
                else:
                    h = fresh.pop()

                self._tried_hosts.add(h)

                logging.debug("Connecting to %s:%s", *h)
                self.connection._host, self.connection._port = h
                try:
                    self.connection._socket_connect()
                    logging.debug("Connected to %s", h)
                except InterfaceError, e:
                    logging.error("Failed to connect to the host: %s", e)
                else:
                    break

            else:
                raise RSConnectionError("No more hosts to try, tried: %s" % self.known_hosts)

            self._state = "ismaster"
            msg = message.query(
                options=0, collection_name="admin.$cmd", num_to_skip=0, num_to_return=-1, query=SON([("ismaster", 1)])
            )
            self.connection._send_message(msg, self.process)
Exemple #16
0
    def __try_node(self, node):
        """Try to connect to this node and see if it works
        for our connection type.

        :Parameters:
         - `node`: The (host, port) pair to try.

        Based on pymongo.Connection.__try_node
        """
        if self.__alive:
            # Close socket connection, but do not return to the connection object to the pool
            self._close()
        self.__host, self.__port = node
        self.__socket_connect()

        command = message.query(
                options=0,
                collection_name='admin.$cmd',
                num_to_skip=0,
                num_to_return=-1,
                query=SON([('ismaster', 1)]))
        self.send_message(command,
            callback=functools.partial(self.__handle_ismaster, node=node), checking_master=True)
Exemple #17
0
    def new_connection(self):
        kwargs = self._kwargs
        kwargs['pool'] = self
        self.conn =  Connection(*self._args, **kwargs)

        # Authenticate if user and pass are set
        if self._dbuser and self._dbpass:
            c = copy.copy(self)
            try:
                self.conn.send_message(
                        message.query(0,
                                      "%s.$cmd" % self._dbname,
                                      0,
                                      1,
                                      SON({'getnonce' : 1}),
                                      SON({})
                            ), callback=c._on_get_nonce)
            except Exception as e:
                # logging.error(str(e))
                raise 
            return c.conn
        else:
            return self.conn
Exemple #18
0
 def find(self, spec=None, fields=None, skip=0, limit=0,
              timeout=True, snapshot=False, tailable=False, sort=None,
              max_scan=None,
              _must_use_master=False, _is_command=False,
              callback=None):
     """Query the database.
     
     The `spec` argument is a prototype document that all results
     must match. For example:
     
     >>> db.test.find({"hello": "world"}, callback=...)
     
     only matches documents that have a key "hello" with value
     "world".  Matches can have other keys *in addition* to
     "hello". The `fields` argument is used to specify a subset of
     fields that should be included in the result documents. By
     limiting results to a certain subset of fields you can cut
     down on network traffic and decoding time.
     
     Raises :class:`TypeError` if any of the arguments are of
     improper type.
     
     :Parameters:
       - `spec` (optional): a SON object specifying elements which
         must be present for a document to be included in the
         result set
       - `fields` (optional): a list of field names that should be
         returned in the result set ("_id" will always be
         included), or a dict specifying the fields to return
       - `skip` (optional): the number of documents to omit (from
         the start of the result set) when returning the results
       - `limit` (optional): the maximum number of results to
         return
       - `timeout` (optional): if True, any returned cursor will be
         subject to the normal timeout behavior of the mongod
         process. Otherwise, the returned cursor will never timeout
         at the server. Care should be taken to ensure that cursors
         with timeout turned off are properly closed.
       - `snapshot` (optional): if True, snapshot mode will be used
         for this query. Snapshot mode assures no duplicates are
         returned, or objects missed, which were present at both
         the start and end of the query's execution. For details,
         see the `snapshot documentation
         <http://dochub.mongodb.org/core/snapshot>`_.
       - `tailable` (optional): the result of this find call will
         be a tailable cursor - tailable cursors aren't closed when
         the last data is retrieved but are kept open and the
         cursors location marks the final document's position. if
         more data is received iteration of the cursor will
         continue from the last document received. For details, see
         the `tailable cursor documentation
         <http://www.mongodb.org/display/DOCS/Tailable+Cursors>`_.
       - `sort` (optional): a list of (key, direction) pairs
         specifying the sort order for this query. See
         :meth:`~pymongo.cursor.Cursor.sort` for details.
       - `max_scan` (optional): limit the number of documents
         examined when performing the query
     
     .. mongodoc:: find
     """
     
     if spec is None:
         spec = {}
     
     if not isinstance(spec, dict):
         raise TypeError("spec must be an instance of dict")
     if not isinstance(skip, int):
         raise TypeError("skip must be an instance of int")
     if not isinstance(limit, int):
         raise TypeError("limit must be an instance of int")
     if not isinstance(timeout, bool):
         raise TypeError("timeout must be an instance of bool")
     if not isinstance(snapshot, bool):
         raise TypeError("snapshot must be an instance of bool")
     if not isinstance(tailable, bool):
         raise TypeError("tailable must be an instance of bool")
     if not callable(callback):
         raise TypeError("callback must be callable")
     
     if fields is not None:
         if not fields:
             fields = {"_id": 1}
         if not isinstance(fields, dict):
             fields = helpers._fields_list_to_dict(fields)
     
     self.__spec = spec
     self.__fields = fields
     self.__skip = skip
     self.__limit = limit
     self.__batch_size = 0
     
     self.__timeout = timeout
     self.__tailable = tailable
     self.__snapshot = snapshot
     self.__ordering = sort and helpers._index_document(sort) or None
     self.__max_scan = max_scan
     self.__explain = False
     self.__hint = None
     # self.__as_class = as_class
     self.__tz_aware = False #collection.database.connection.tz_aware
     self.__must_use_master = _must_use_master
     self.__is_command = _is_command
     
     connection = self.__pool.connection()
     try:
         connection.send_message(
             message.query(self.__query_options(),
                           self.full_collection_name,
                           self.__skip, 
                           self.__limit,
                           self.__query_spec(),
                           self.__fields), 
             callback=functools.partial(self._handle_response, orig_callback=callback))
     except Exception as e:
         connection.close()
Exemple #19
0
 def find(self, spec=None, fields=None, skip=0, limit=0,
              timeout=True, snapshot=False, tailable=False, sort=None,
              max_scan=None, slave_okay=False,
              _must_use_master=False, _is_command=False,
              callback=None):
     """Query the database.
     
     The `spec` argument is a prototype document that all results
     must match. For example:
     
     >>> db.test.find({"hello": "world"}, callback=...)
     
     only matches documents that have a key "hello" with value
     "world".  Matches can have other keys *in addition* to
     "hello". The `fields` argument is used to specify a subset of
     fields that should be included in the result documents. By
     limiting results to a certain subset of fields you can cut
     down on network traffic and decoding time.
     
     Raises :class:`TypeError` if any of the arguments are of
     improper type.
     
     :Parameters:
       - `spec` (optional): a SON object specifying elements which
         must be present for a document to be included in the
         result set
       - `fields` (optional): a list of field names that should be
         returned in the result set ("_id" will always be
         included), or a dict specifying the fields to return
       - `skip` (optional): the number of documents to omit (from
         the start of the result set) when returning the results
       - `limit` (optional): the maximum number of results to
         return
       - `timeout` (optional): if True, any returned cursor will be
         subject to the normal timeout behavior of the mongod
         process. Otherwise, the returned cursor will never timeout
         at the server. Care should be taken to ensure that cursors
         with timeout turned off are properly closed.
       - `snapshot` (optional): if True, snapshot mode will be used
         for this query. Snapshot mode assures no duplicates are
         returned, or objects missed, which were present at both
         the start and end of the query's execution. For details,
         see the `snapshot documentation
         <http://dochub.mongodb.org/core/snapshot>`_.
       - `tailable` (optional): the result of this find call will
         be a tailable cursor - tailable cursors aren't closed when
         the last data is retrieved but are kept open and the
         cursors location marks the final document's position. if
         more data is received iteration of the cursor will
         continue from the last document received. For details, see
         the `tailable cursor documentation
         <http://www.mongodb.org/display/DOCS/Tailable+Cursors>`_.
       - `sort` (optional): a list of (key, direction) pairs
         specifying the sort order for this query. See
         :meth:`~pymongo.cursor.Cursor.sort` for details.
       - `max_scan` (optional): limit the number of documents
         examined when performing the query
       - `slave_okay` (optional): is it okay to connect directly
         to and perform queries on a slave instance
     
     .. mongodoc:: find
     """
     
     if spec is None:
         spec = {}
     
     if not isinstance(spec, dict):
         raise TypeError("spec must be an instance of dict")
     if not isinstance(skip, int):
         raise TypeError("skip must be an instance of int")
     if not isinstance(limit, int):
         raise TypeError("limit must be an instance of int")
     if not isinstance(timeout, bool):
         raise TypeError("timeout must be an instance of bool")
     if not isinstance(snapshot, bool):
         raise TypeError("snapshot must be an instance of bool")
     if not isinstance(tailable, bool):
         raise TypeError("tailable must be an instance of bool")
     if not callable(callback):
         raise TypeError("callback must be callable")
     
     if fields is not None:
         if not fields:
             fields = {"_id": 1}
         if not isinstance(fields, dict):
             fields = helpers._fields_list_to_dict(fields)
     
     self.__spec = spec
     self.__fields = fields
     self.__skip = skip
     self.__limit = limit
     self.__batch_size = 0
     
     self.__timeout = timeout
     self.__tailable = tailable
     self.__snapshot = snapshot
     self.__ordering = sort and helpers._index_document(sort) or None
     self.__max_scan = max_scan
     self.__slave_okay = slave_okay
     self.__explain = False
     self.__hint = None
     # self.__as_class = as_class
     self.__tz_aware = False #collection.database.connection.tz_aware
     self.__must_use_master = _must_use_master
     self.__is_command = _is_command
     
     connection = self.__pool.connection()
     try:
         connection.send_message(
             message.query(self.__query_options(),
                           self.full_collection_name,
                           self.__skip, 
                           self.__limit,
                           self.__query_spec(),
                           self.__fields), 
             callback=functools.partial(self._handle_response, orig_callback=callback))
     except Exception, e:
         logging.error('Error sending query %s' % e)
         connection.close()
         raise
Exemple #20
0
 def _get_nonce(self, callback):
     assert self.__callback is None
     self.__callback = callback
     self._send_message(
         message.query(0, "%s.$cmd" % self.__pool._dbname, 0, 1,
                       SON({'getnonce': 1}), SON({})))