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)
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)
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({}) ))
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)
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)
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)
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
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 _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)
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({})))
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({})))
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)
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)
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
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()
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
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({})))