sensu-plugins-mongodb-mrtrotl 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (181) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +1 -0
  3. data/LICENSE +22 -0
  4. data/README.md +27 -0
  5. data/bin/check-mongodb-metric.rb +144 -0
  6. data/bin/check-mongodb-query-count.rb +267 -0
  7. data/bin/check-mongodb.py +1644 -0
  8. data/bin/check-mongodb.rb +5 -0
  9. data/bin/metrics-mongodb-replication.rb +254 -0
  10. data/bin/metrics-mongodb.rb +133 -0
  11. data/lib/bson/__init__.py +1347 -0
  12. data/lib/bson/__pycache__/__init__.cpython-310.pyc +0 -0
  13. data/lib/bson/__pycache__/_helpers.cpython-310.pyc +0 -0
  14. data/lib/bson/__pycache__/binary.cpython-310.pyc +0 -0
  15. data/lib/bson/__pycache__/code.cpython-310.pyc +0 -0
  16. data/lib/bson/__pycache__/codec_options.cpython-310.pyc +0 -0
  17. data/lib/bson/__pycache__/dbref.cpython-310.pyc +0 -0
  18. data/lib/bson/__pycache__/decimal128.cpython-310.pyc +0 -0
  19. data/lib/bson/__pycache__/errors.cpython-310.pyc +0 -0
  20. data/lib/bson/__pycache__/int64.cpython-310.pyc +0 -0
  21. data/lib/bson/__pycache__/json_util.cpython-310.pyc +0 -0
  22. data/lib/bson/__pycache__/max_key.cpython-310.pyc +0 -0
  23. data/lib/bson/__pycache__/min_key.cpython-310.pyc +0 -0
  24. data/lib/bson/__pycache__/objectid.cpython-310.pyc +0 -0
  25. data/lib/bson/__pycache__/raw_bson.cpython-310.pyc +0 -0
  26. data/lib/bson/__pycache__/regex.cpython-310.pyc +0 -0
  27. data/lib/bson/__pycache__/son.cpython-310.pyc +0 -0
  28. data/lib/bson/__pycache__/timestamp.cpython-310.pyc +0 -0
  29. data/lib/bson/__pycache__/tz_util.cpython-310.pyc +0 -0
  30. data/lib/bson/_cbson.cpython-310-x86_64-linux-gnu.so +0 -0
  31. data/lib/bson/_helpers.py +41 -0
  32. data/lib/bson/binary.py +364 -0
  33. data/lib/bson/code.py +101 -0
  34. data/lib/bson/codec_options.py +414 -0
  35. data/lib/bson/codec_options.pyi +100 -0
  36. data/lib/bson/dbref.py +133 -0
  37. data/lib/bson/decimal128.py +314 -0
  38. data/lib/bson/errors.py +35 -0
  39. data/lib/bson/int64.py +39 -0
  40. data/lib/bson/json_util.py +874 -0
  41. data/lib/bson/max_key.py +55 -0
  42. data/lib/bson/min_key.py +55 -0
  43. data/lib/bson/objectid.py +286 -0
  44. data/lib/bson/py.typed +2 -0
  45. data/lib/bson/raw_bson.py +175 -0
  46. data/lib/bson/regex.py +135 -0
  47. data/lib/bson/son.py +208 -0
  48. data/lib/bson/timestamp.py +124 -0
  49. data/lib/bson/tz_util.py +52 -0
  50. data/lib/gridfs/__init__.py +1015 -0
  51. data/lib/gridfs/__pycache__/__init__.cpython-310.pyc +0 -0
  52. data/lib/gridfs/__pycache__/errors.cpython-310.pyc +0 -0
  53. data/lib/gridfs/__pycache__/grid_file.cpython-310.pyc +0 -0
  54. data/lib/gridfs/errors.py +33 -0
  55. data/lib/gridfs/grid_file.py +907 -0
  56. data/lib/gridfs/py.typed +2 -0
  57. data/lib/pymongo/__init__.py +185 -0
  58. data/lib/pymongo/__pycache__/__init__.cpython-310.pyc +0 -0
  59. data/lib/pymongo/__pycache__/_csot.cpython-310.pyc +0 -0
  60. data/lib/pymongo/__pycache__/aggregation.cpython-310.pyc +0 -0
  61. data/lib/pymongo/__pycache__/auth.cpython-310.pyc +0 -0
  62. data/lib/pymongo/__pycache__/auth_aws.cpython-310.pyc +0 -0
  63. data/lib/pymongo/__pycache__/bulk.cpython-310.pyc +0 -0
  64. data/lib/pymongo/__pycache__/change_stream.cpython-310.pyc +0 -0
  65. data/lib/pymongo/__pycache__/client_options.cpython-310.pyc +0 -0
  66. data/lib/pymongo/__pycache__/client_session.cpython-310.pyc +0 -0
  67. data/lib/pymongo/__pycache__/collation.cpython-310.pyc +0 -0
  68. data/lib/pymongo/__pycache__/collection.cpython-310.pyc +0 -0
  69. data/lib/pymongo/__pycache__/command_cursor.cpython-310.pyc +0 -0
  70. data/lib/pymongo/__pycache__/common.cpython-310.pyc +0 -0
  71. data/lib/pymongo/__pycache__/compression_support.cpython-310.pyc +0 -0
  72. data/lib/pymongo/__pycache__/cursor.cpython-310.pyc +0 -0
  73. data/lib/pymongo/__pycache__/daemon.cpython-310.pyc +0 -0
  74. data/lib/pymongo/__pycache__/database.cpython-310.pyc +0 -0
  75. data/lib/pymongo/__pycache__/driver_info.cpython-310.pyc +0 -0
  76. data/lib/pymongo/__pycache__/encryption.cpython-310.pyc +0 -0
  77. data/lib/pymongo/__pycache__/encryption_options.cpython-310.pyc +0 -0
  78. data/lib/pymongo/__pycache__/errors.cpython-310.pyc +0 -0
  79. data/lib/pymongo/__pycache__/event_loggers.cpython-310.pyc +0 -0
  80. data/lib/pymongo/__pycache__/hello.cpython-310.pyc +0 -0
  81. data/lib/pymongo/__pycache__/helpers.cpython-310.pyc +0 -0
  82. data/lib/pymongo/__pycache__/max_staleness_selectors.cpython-310.pyc +0 -0
  83. data/lib/pymongo/__pycache__/message.cpython-310.pyc +0 -0
  84. data/lib/pymongo/__pycache__/mongo_client.cpython-310.pyc +0 -0
  85. data/lib/pymongo/__pycache__/monitor.cpython-310.pyc +0 -0
  86. data/lib/pymongo/__pycache__/monitoring.cpython-310.pyc +0 -0
  87. data/lib/pymongo/__pycache__/network.cpython-310.pyc +0 -0
  88. data/lib/pymongo/__pycache__/ocsp_cache.cpython-310.pyc +0 -0
  89. data/lib/pymongo/__pycache__/ocsp_support.cpython-310.pyc +0 -0
  90. data/lib/pymongo/__pycache__/operations.cpython-310.pyc +0 -0
  91. data/lib/pymongo/__pycache__/periodic_executor.cpython-310.pyc +0 -0
  92. data/lib/pymongo/__pycache__/pool.cpython-310.pyc +0 -0
  93. data/lib/pymongo/__pycache__/pyopenssl_context.cpython-310.pyc +0 -0
  94. data/lib/pymongo/__pycache__/read_concern.cpython-310.pyc +0 -0
  95. data/lib/pymongo/__pycache__/read_preferences.cpython-310.pyc +0 -0
  96. data/lib/pymongo/__pycache__/response.cpython-310.pyc +0 -0
  97. data/lib/pymongo/__pycache__/results.cpython-310.pyc +0 -0
  98. data/lib/pymongo/__pycache__/saslprep.cpython-310.pyc +0 -0
  99. data/lib/pymongo/__pycache__/server.cpython-310.pyc +0 -0
  100. data/lib/pymongo/__pycache__/server_api.cpython-310.pyc +0 -0
  101. data/lib/pymongo/__pycache__/server_description.cpython-310.pyc +0 -0
  102. data/lib/pymongo/__pycache__/server_selectors.cpython-310.pyc +0 -0
  103. data/lib/pymongo/__pycache__/server_type.cpython-310.pyc +0 -0
  104. data/lib/pymongo/__pycache__/settings.cpython-310.pyc +0 -0
  105. data/lib/pymongo/__pycache__/socket_checker.cpython-310.pyc +0 -0
  106. data/lib/pymongo/__pycache__/srv_resolver.cpython-310.pyc +0 -0
  107. data/lib/pymongo/__pycache__/ssl_context.cpython-310.pyc +0 -0
  108. data/lib/pymongo/__pycache__/ssl_support.cpython-310.pyc +0 -0
  109. data/lib/pymongo/__pycache__/topology.cpython-310.pyc +0 -0
  110. data/lib/pymongo/__pycache__/topology_description.cpython-310.pyc +0 -0
  111. data/lib/pymongo/__pycache__/typings.cpython-310.pyc +0 -0
  112. data/lib/pymongo/__pycache__/uri_parser.cpython-310.pyc +0 -0
  113. data/lib/pymongo/__pycache__/write_concern.cpython-310.pyc +0 -0
  114. data/lib/pymongo/_cmessage.cpython-310-x86_64-linux-gnu.so +0 -0
  115. data/lib/pymongo/_csot.py +118 -0
  116. data/lib/pymongo/aggregation.py +229 -0
  117. data/lib/pymongo/auth.py +549 -0
  118. data/lib/pymongo/auth_aws.py +94 -0
  119. data/lib/pymongo/bulk.py +513 -0
  120. data/lib/pymongo/change_stream.py +457 -0
  121. data/lib/pymongo/client_options.py +302 -0
  122. data/lib/pymongo/client_session.py +1112 -0
  123. data/lib/pymongo/collation.py +224 -0
  124. data/lib/pymongo/collection.py +3204 -0
  125. data/lib/pymongo/command_cursor.py +353 -0
  126. data/lib/pymongo/common.py +984 -0
  127. data/lib/pymongo/compression_support.py +149 -0
  128. data/lib/pymongo/cursor.py +1345 -0
  129. data/lib/pymongo/daemon.py +141 -0
  130. data/lib/pymongo/database.py +1202 -0
  131. data/lib/pymongo/driver_info.py +42 -0
  132. data/lib/pymongo/encryption.py +884 -0
  133. data/lib/pymongo/encryption_options.py +221 -0
  134. data/lib/pymongo/errors.py +365 -0
  135. data/lib/pymongo/event_loggers.py +221 -0
  136. data/lib/pymongo/hello.py +219 -0
  137. data/lib/pymongo/helpers.py +259 -0
  138. data/lib/pymongo/max_staleness_selectors.py +114 -0
  139. data/lib/pymongo/message.py +1440 -0
  140. data/lib/pymongo/mongo_client.py +2144 -0
  141. data/lib/pymongo/monitor.py +440 -0
  142. data/lib/pymongo/monitoring.py +1801 -0
  143. data/lib/pymongo/network.py +311 -0
  144. data/lib/pymongo/ocsp_cache.py +87 -0
  145. data/lib/pymongo/ocsp_support.py +372 -0
  146. data/lib/pymongo/operations.py +507 -0
  147. data/lib/pymongo/periodic_executor.py +183 -0
  148. data/lib/pymongo/pool.py +1660 -0
  149. data/lib/pymongo/py.typed +2 -0
  150. data/lib/pymongo/pyopenssl_context.py +383 -0
  151. data/lib/pymongo/read_concern.py +75 -0
  152. data/lib/pymongo/read_preferences.py +609 -0
  153. data/lib/pymongo/response.py +109 -0
  154. data/lib/pymongo/results.py +217 -0
  155. data/lib/pymongo/saslprep.py +113 -0
  156. data/lib/pymongo/server.py +247 -0
  157. data/lib/pymongo/server_api.py +170 -0
  158. data/lib/pymongo/server_description.py +285 -0
  159. data/lib/pymongo/server_selectors.py +153 -0
  160. data/lib/pymongo/server_type.py +32 -0
  161. data/lib/pymongo/settings.py +159 -0
  162. data/lib/pymongo/socket_checker.py +104 -0
  163. data/lib/pymongo/srv_resolver.py +126 -0
  164. data/lib/pymongo/ssl_context.py +39 -0
  165. data/lib/pymongo/ssl_support.py +99 -0
  166. data/lib/pymongo/topology.py +890 -0
  167. data/lib/pymongo/topology_description.py +639 -0
  168. data/lib/pymongo/typings.py +39 -0
  169. data/lib/pymongo/uri_parser.py +624 -0
  170. data/lib/pymongo/write_concern.py +129 -0
  171. data/lib/pymongo-4.2.0.dist-info/INSTALLER +1 -0
  172. data/lib/pymongo-4.2.0.dist-info/LICENSE +201 -0
  173. data/lib/pymongo-4.2.0.dist-info/METADATA +250 -0
  174. data/lib/pymongo-4.2.0.dist-info/RECORD +167 -0
  175. data/lib/pymongo-4.2.0.dist-info/REQUESTED +0 -0
  176. data/lib/pymongo-4.2.0.dist-info/WHEEL +6 -0
  177. data/lib/pymongo-4.2.0.dist-info/top_level.txt +3 -0
  178. data/lib/sensu-plugins-mongodb/metrics.rb +391 -0
  179. data/lib/sensu-plugins-mongodb/version.rb +9 -0
  180. data/lib/sensu-plugins-mongodb.rb +1 -0
  181. metadata +407 -0
@@ -0,0 +1,109 @@
1
+ # Copyright 2014-present MongoDB, Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ """Represent a response from the server."""
16
+
17
+
18
+ class Response(object):
19
+ __slots__ = ("_data", "_address", "_request_id", "_duration", "_from_command", "_docs")
20
+
21
+ def __init__(self, data, address, request_id, duration, from_command, docs):
22
+ """Represent a response from the server.
23
+
24
+ :Parameters:
25
+ - `data`: A network response message.
26
+ - `address`: (host, port) of the source server.
27
+ - `request_id`: The request id of this operation.
28
+ - `duration`: The duration of the operation.
29
+ - `from_command`: if the response is the result of a db command.
30
+ """
31
+ self._data = data
32
+ self._address = address
33
+ self._request_id = request_id
34
+ self._duration = duration
35
+ self._from_command = from_command
36
+ self._docs = docs
37
+
38
+ @property
39
+ def data(self):
40
+ """Server response's raw BSON bytes."""
41
+ return self._data
42
+
43
+ @property
44
+ def address(self):
45
+ """(host, port) of the source server."""
46
+ return self._address
47
+
48
+ @property
49
+ def request_id(self):
50
+ """The request id of this operation."""
51
+ return self._request_id
52
+
53
+ @property
54
+ def duration(self):
55
+ """The duration of the operation."""
56
+ return self._duration
57
+
58
+ @property
59
+ def from_command(self):
60
+ """If the response is a result from a db command."""
61
+ return self._from_command
62
+
63
+ @property
64
+ def docs(self):
65
+ """The decoded document(s)."""
66
+ return self._docs
67
+
68
+
69
+ class PinnedResponse(Response):
70
+ __slots__ = ("_socket_info", "_more_to_come")
71
+
72
+ def __init__(
73
+ self, data, address, socket_info, request_id, duration, from_command, docs, more_to_come
74
+ ):
75
+ """Represent a response to an exhaust cursor's initial query.
76
+
77
+ :Parameters:
78
+ - `data`: A network response message.
79
+ - `address`: (host, port) of the source server.
80
+ - `socket_info`: The SocketInfo used for the initial query.
81
+ - `pool`: The Pool from which the SocketInfo came.
82
+ - `request_id`: The request id of this operation.
83
+ - `duration`: The duration of the operation.
84
+ - `from_command`: If the response is the result of a db command.
85
+ - `docs`: List of documents.
86
+ - `more_to_come`: Bool indicating whether cursor is ready to be
87
+ exhausted.
88
+ """
89
+ super(PinnedResponse, self).__init__(
90
+ data, address, request_id, duration, from_command, docs
91
+ )
92
+ self._socket_info = socket_info
93
+ self._more_to_come = more_to_come
94
+
95
+ @property
96
+ def socket_info(self):
97
+ """The SocketInfo used for the initial query.
98
+
99
+ The server will send batches on this socket, without waiting for
100
+ getMores from the client, until the result set is exhausted or there
101
+ is an error.
102
+ """
103
+ return self._socket_info
104
+
105
+ @property
106
+ def more_to_come(self):
107
+ """If true, server is ready to send batches on the socket until the
108
+ result set is exhausted or there is an error."""
109
+ return self._more_to_come
@@ -0,0 +1,217 @@
1
+ # Copyright 2015-present MongoDB, Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ """Result class definitions."""
16
+ from typing import Any, Dict, List, Optional, cast
17
+
18
+ from pymongo.errors import InvalidOperation
19
+
20
+
21
+ class _WriteResult(object):
22
+ """Base class for write result classes."""
23
+
24
+ __slots__ = ("__acknowledged",)
25
+
26
+ def __init__(self, acknowledged: bool) -> None:
27
+ self.__acknowledged = acknowledged
28
+
29
+ def _raise_if_unacknowledged(self, property_name):
30
+ """Raise an exception on property access if unacknowledged."""
31
+ if not self.__acknowledged:
32
+ raise InvalidOperation(
33
+ "A value for %s is not available when "
34
+ "the write is unacknowledged. Check the "
35
+ "acknowledged attribute to avoid this "
36
+ "error." % (property_name,)
37
+ )
38
+
39
+ @property
40
+ def acknowledged(self) -> bool:
41
+ """Is this the result of an acknowledged write operation?
42
+
43
+ The :attr:`acknowledged` attribute will be ``False`` when using
44
+ ``WriteConcern(w=0)``, otherwise ``True``.
45
+
46
+ .. note::
47
+ If the :attr:`acknowledged` attribute is ``False`` all other
48
+ attibutes of this class will raise
49
+ :class:`~pymongo.errors.InvalidOperation` when accessed. Values for
50
+ other attributes cannot be determined if the write operation was
51
+ unacknowledged.
52
+
53
+ .. seealso::
54
+ :class:`~pymongo.write_concern.WriteConcern`
55
+ """
56
+ return self.__acknowledged
57
+
58
+
59
+ class InsertOneResult(_WriteResult):
60
+ """The return type for :meth:`~pymongo.collection.Collection.insert_one`."""
61
+
62
+ __slots__ = ("__inserted_id",)
63
+
64
+ def __init__(self, inserted_id: Any, acknowledged: bool) -> None:
65
+ self.__inserted_id = inserted_id
66
+ super(InsertOneResult, self).__init__(acknowledged)
67
+
68
+ @property
69
+ def inserted_id(self) -> Any:
70
+ """The inserted document's _id."""
71
+ return self.__inserted_id
72
+
73
+
74
+ class InsertManyResult(_WriteResult):
75
+ """The return type for :meth:`~pymongo.collection.Collection.insert_many`."""
76
+
77
+ __slots__ = ("__inserted_ids",)
78
+
79
+ def __init__(self, inserted_ids: List[Any], acknowledged: bool) -> None:
80
+ self.__inserted_ids = inserted_ids
81
+ super(InsertManyResult, self).__init__(acknowledged)
82
+
83
+ @property
84
+ def inserted_ids(self) -> List:
85
+ """A list of _ids of the inserted documents, in the order provided.
86
+
87
+ .. note:: If ``False`` is passed for the `ordered` parameter to
88
+ :meth:`~pymongo.collection.Collection.insert_many` the server
89
+ may have inserted the documents in a different order than what
90
+ is presented here.
91
+ """
92
+ return self.__inserted_ids
93
+
94
+
95
+ class UpdateResult(_WriteResult):
96
+ """The return type for :meth:`~pymongo.collection.Collection.update_one`,
97
+ :meth:`~pymongo.collection.Collection.update_many`, and
98
+ :meth:`~pymongo.collection.Collection.replace_one`.
99
+ """
100
+
101
+ __slots__ = ("__raw_result",)
102
+
103
+ def __init__(self, raw_result: Dict[str, Any], acknowledged: bool) -> None:
104
+ self.__raw_result = raw_result
105
+ super(UpdateResult, self).__init__(acknowledged)
106
+
107
+ @property
108
+ def raw_result(self) -> Dict[str, Any]:
109
+ """The raw result document returned by the server."""
110
+ return self.__raw_result
111
+
112
+ @property
113
+ def matched_count(self) -> int:
114
+ """The number of documents matched for this update."""
115
+ self._raise_if_unacknowledged("matched_count")
116
+ if self.upserted_id is not None:
117
+ return 0
118
+ return self.__raw_result.get("n", 0)
119
+
120
+ @property
121
+ def modified_count(self) -> int:
122
+ """The number of documents modified."""
123
+ self._raise_if_unacknowledged("modified_count")
124
+ return cast(int, self.__raw_result.get("nModified"))
125
+
126
+ @property
127
+ def upserted_id(self) -> Any:
128
+ """The _id of the inserted document if an upsert took place. Otherwise
129
+ ``None``.
130
+ """
131
+ self._raise_if_unacknowledged("upserted_id")
132
+ return self.__raw_result.get("upserted")
133
+
134
+
135
+ class DeleteResult(_WriteResult):
136
+ """The return type for :meth:`~pymongo.collection.Collection.delete_one`
137
+ and :meth:`~pymongo.collection.Collection.delete_many`"""
138
+
139
+ __slots__ = ("__raw_result",)
140
+
141
+ def __init__(self, raw_result: Dict[str, Any], acknowledged: bool) -> None:
142
+ self.__raw_result = raw_result
143
+ super(DeleteResult, self).__init__(acknowledged)
144
+
145
+ @property
146
+ def raw_result(self) -> Dict[str, Any]:
147
+ """The raw result document returned by the server."""
148
+ return self.__raw_result
149
+
150
+ @property
151
+ def deleted_count(self) -> int:
152
+ """The number of documents deleted."""
153
+ self._raise_if_unacknowledged("deleted_count")
154
+ return self.__raw_result.get("n", 0)
155
+
156
+
157
+ class BulkWriteResult(_WriteResult):
158
+ """An object wrapper for bulk API write results."""
159
+
160
+ __slots__ = ("__bulk_api_result",)
161
+
162
+ def __init__(self, bulk_api_result: Dict[str, Any], acknowledged: bool) -> None:
163
+ """Create a BulkWriteResult instance.
164
+
165
+ :Parameters:
166
+ - `bulk_api_result`: A result dict from the bulk API
167
+ - `acknowledged`: Was this write result acknowledged? If ``False``
168
+ then all properties of this object will raise
169
+ :exc:`~pymongo.errors.InvalidOperation`.
170
+ """
171
+ self.__bulk_api_result = bulk_api_result
172
+ super(BulkWriteResult, self).__init__(acknowledged)
173
+
174
+ @property
175
+ def bulk_api_result(self) -> Dict[str, Any]:
176
+ """The raw bulk API result."""
177
+ return self.__bulk_api_result
178
+
179
+ @property
180
+ def inserted_count(self) -> int:
181
+ """The number of documents inserted."""
182
+ self._raise_if_unacknowledged("inserted_count")
183
+ return cast(int, self.__bulk_api_result.get("nInserted"))
184
+
185
+ @property
186
+ def matched_count(self) -> int:
187
+ """The number of documents matched for an update."""
188
+ self._raise_if_unacknowledged("matched_count")
189
+ return cast(int, self.__bulk_api_result.get("nMatched"))
190
+
191
+ @property
192
+ def modified_count(self) -> int:
193
+ """The number of documents modified."""
194
+ self._raise_if_unacknowledged("modified_count")
195
+ return cast(int, self.__bulk_api_result.get("nModified"))
196
+
197
+ @property
198
+ def deleted_count(self) -> int:
199
+ """The number of documents deleted."""
200
+ self._raise_if_unacknowledged("deleted_count")
201
+ return cast(int, self.__bulk_api_result.get("nRemoved"))
202
+
203
+ @property
204
+ def upserted_count(self) -> int:
205
+ """The number of documents upserted."""
206
+ self._raise_if_unacknowledged("upserted_count")
207
+ return cast(int, self.__bulk_api_result.get("nUpserted"))
208
+
209
+ @property
210
+ def upserted_ids(self) -> Optional[Dict[int, Any]]:
211
+ """A map of operation index to the _id of the upserted document."""
212
+ self._raise_if_unacknowledged("upserted_ids")
213
+ if self.__bulk_api_result:
214
+ return dict(
215
+ (upsert["index"], upsert["_id"]) for upsert in self.bulk_api_result["upserted"]
216
+ )
217
+ return None
@@ -0,0 +1,113 @@
1
+ # Copyright 2016-present MongoDB, Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ """An implementation of RFC4013 SASLprep."""
16
+ from typing import Any, Optional
17
+
18
+ try:
19
+ import stringprep
20
+ except ImportError:
21
+ HAVE_STRINGPREP = False
22
+
23
+ def saslprep(data: Any, prohibit_unassigned_code_points: Optional[bool] = True) -> str:
24
+ """SASLprep dummy"""
25
+ if isinstance(data, str):
26
+ raise TypeError(
27
+ "The stringprep module is not available. Usernames and "
28
+ "passwords must be instances of bytes."
29
+ )
30
+ return data
31
+
32
+ else:
33
+ HAVE_STRINGPREP = True
34
+ import unicodedata
35
+
36
+ # RFC4013 section 2.3 prohibited output.
37
+ _PROHIBITED = (
38
+ # A strict reading of RFC 4013 requires table c12 here, but
39
+ # characters from it are mapped to SPACE in the Map step. Can
40
+ # normalization reintroduce them somehow?
41
+ stringprep.in_table_c12,
42
+ stringprep.in_table_c21_c22,
43
+ stringprep.in_table_c3,
44
+ stringprep.in_table_c4,
45
+ stringprep.in_table_c5,
46
+ stringprep.in_table_c6,
47
+ stringprep.in_table_c7,
48
+ stringprep.in_table_c8,
49
+ stringprep.in_table_c9,
50
+ )
51
+
52
+ def saslprep(data: Any, prohibit_unassigned_code_points: Optional[bool] = True) -> str:
53
+ """An implementation of RFC4013 SASLprep.
54
+
55
+ :Parameters:
56
+ - `data`: The string to SASLprep. Unicode strings
57
+ (:class:`str`) are supported. Byte strings
58
+ (:class:`bytes`) are ignored.
59
+ - `prohibit_unassigned_code_points`: True / False. RFC 3454
60
+ and RFCs for various SASL mechanisms distinguish between
61
+ `queries` (unassigned code points allowed) and
62
+ `stored strings` (unassigned code points prohibited). Defaults
63
+ to ``True`` (unassigned code points are prohibited).
64
+
65
+ :Returns:
66
+ The SASLprep'ed version of `data`.
67
+ """
68
+ prohibited: Any
69
+
70
+ if not isinstance(data, str):
71
+ return data
72
+
73
+ if prohibit_unassigned_code_points:
74
+ prohibited = _PROHIBITED + (stringprep.in_table_a1,)
75
+ else:
76
+ prohibited = _PROHIBITED
77
+
78
+ # RFC3454 section 2, step 1 - Map
79
+ # RFC4013 section 2.1 mappings
80
+ # Map Non-ASCII space characters to SPACE (U+0020). Map
81
+ # commonly mapped to nothing characters to, well, nothing.
82
+ in_table_c12 = stringprep.in_table_c12
83
+ in_table_b1 = stringprep.in_table_b1
84
+ data = "".join(
85
+ ["\u0020" if in_table_c12(elt) else elt for elt in data if not in_table_b1(elt)]
86
+ )
87
+
88
+ # RFC3454 section 2, step 2 - Normalize
89
+ # RFC4013 section 2.2 normalization
90
+ data = unicodedata.ucd_3_2_0.normalize("NFKC", data)
91
+
92
+ in_table_d1 = stringprep.in_table_d1
93
+ if in_table_d1(data[0]):
94
+ if not in_table_d1(data[-1]):
95
+ # RFC3454, Section 6, #3. If a string contains any
96
+ # RandALCat character, the first and last characters
97
+ # MUST be RandALCat characters.
98
+ raise ValueError("SASLprep: failed bidirectional check")
99
+ # RFC3454, Section 6, #2. If a string contains any RandALCat
100
+ # character, it MUST NOT contain any LCat character.
101
+ prohibited = prohibited + (stringprep.in_table_d2,)
102
+ else:
103
+ # RFC3454, Section 6, #3. Following the logic of #3, if
104
+ # the first character is not a RandALCat, no other character
105
+ # can be either.
106
+ prohibited = prohibited + (in_table_d1,)
107
+
108
+ # RFC3454 section 2, step 3 and 4 - Prohibit and check bidi
109
+ for char in data:
110
+ if any(in_table(char) for in_table in prohibited):
111
+ raise ValueError("SASLprep: failed prohibited character check")
112
+
113
+ return data
@@ -0,0 +1,247 @@
1
+ # Copyright 2014-present MongoDB, Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License"); you
4
+ # may not use this file except in compliance with the License. You
5
+ # may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
12
+ # implied. See the License for the specific language governing
13
+ # permissions and limitations under the License.
14
+
15
+ """Communicate with one MongoDB server in a topology."""
16
+
17
+ from datetime import datetime
18
+
19
+ from bson import _decode_all_selective
20
+ from pymongo.errors import NotPrimaryError, OperationFailure
21
+ from pymongo.helpers import _check_command_response
22
+ from pymongo.message import _convert_exception, _OpMsg
23
+ from pymongo.response import PinnedResponse, Response
24
+
25
+ _CURSOR_DOC_FIELDS = {"cursor": {"firstBatch": 1, "nextBatch": 1}}
26
+
27
+
28
+ class Server(object):
29
+ def __init__(
30
+ self, server_description, pool, monitor, topology_id=None, listeners=None, events=None
31
+ ):
32
+ """Represent one MongoDB server."""
33
+ self._description = server_description
34
+ self._pool = pool
35
+ self._monitor = monitor
36
+ self._topology_id = topology_id
37
+ self._publish = listeners is not None and listeners.enabled_for_server
38
+ self._listener = listeners
39
+ self._events = None
40
+ if self._publish:
41
+ self._events = events()
42
+
43
+ def open(self):
44
+ """Start monitoring, or restart after a fork.
45
+
46
+ Multiple calls have no effect.
47
+ """
48
+ if not self._pool.opts.load_balanced:
49
+ self._monitor.open()
50
+
51
+ def reset(self, service_id=None):
52
+ """Clear the connection pool."""
53
+ self.pool.reset(service_id)
54
+
55
+ def close(self):
56
+ """Clear the connection pool and stop the monitor.
57
+
58
+ Reconnect with open().
59
+ """
60
+ if self._publish:
61
+ assert self._listener is not None
62
+ assert self._events is not None
63
+ self._events.put(
64
+ (
65
+ self._listener.publish_server_closed,
66
+ (self._description.address, self._topology_id),
67
+ )
68
+ )
69
+ self._monitor.close()
70
+ self._pool.reset_without_pause()
71
+
72
+ def request_check(self):
73
+ """Check the server's state soon."""
74
+ self._monitor.request_check()
75
+
76
+ def run_operation(self, sock_info, operation, read_preference, listeners, unpack_res):
77
+ """Run a _Query or _GetMore operation and return a Response object.
78
+
79
+ This method is used only to run _Query/_GetMore operations from
80
+ cursors.
81
+ Can raise ConnectionFailure, OperationFailure, etc.
82
+
83
+ :Parameters:
84
+ - `sock_info`: A SocketInfo instance.
85
+ - `operation`: A _Query or _GetMore object.
86
+ - `set_secondary_okay`: Pass to operation.get_message.
87
+ - `listeners`: Instance of _EventListeners or None.
88
+ - `unpack_res`: A callable that decodes the wire protocol response.
89
+ """
90
+ duration = None
91
+ publish = listeners.enabled_for_commands
92
+ if publish:
93
+ start = datetime.now()
94
+
95
+ use_cmd = operation.use_command(sock_info)
96
+ more_to_come = operation.sock_mgr and operation.sock_mgr.more_to_come
97
+ if more_to_come:
98
+ request_id = 0
99
+ else:
100
+ message = operation.get_message(read_preference, sock_info, use_cmd)
101
+ request_id, data, max_doc_size = self._split_message(message)
102
+
103
+ if publish:
104
+ cmd, dbn = operation.as_command(sock_info)
105
+ listeners.publish_command_start(
106
+ cmd, dbn, request_id, sock_info.address, service_id=sock_info.service_id
107
+ )
108
+ start = datetime.now()
109
+
110
+ try:
111
+ if more_to_come:
112
+ reply = sock_info.receive_message(None)
113
+ else:
114
+ sock_info.send_message(data, max_doc_size)
115
+ reply = sock_info.receive_message(request_id)
116
+
117
+ # Unpack and check for command errors.
118
+ if use_cmd:
119
+ user_fields = _CURSOR_DOC_FIELDS
120
+ legacy_response = False
121
+ else:
122
+ user_fields = None
123
+ legacy_response = True
124
+ docs = unpack_res(
125
+ reply,
126
+ operation.cursor_id,
127
+ operation.codec_options,
128
+ legacy_response=legacy_response,
129
+ user_fields=user_fields,
130
+ )
131
+ if use_cmd:
132
+ first = docs[0]
133
+ operation.client._process_response(first, operation.session)
134
+ _check_command_response(first, sock_info.max_wire_version)
135
+ except Exception as exc:
136
+ if publish:
137
+ duration = datetime.now() - start
138
+ if isinstance(exc, (NotPrimaryError, OperationFailure)):
139
+ failure = exc.details
140
+ else:
141
+ failure = _convert_exception(exc)
142
+ listeners.publish_command_failure(
143
+ duration,
144
+ failure,
145
+ operation.name,
146
+ request_id,
147
+ sock_info.address,
148
+ service_id=sock_info.service_id,
149
+ )
150
+ raise
151
+
152
+ if publish:
153
+ duration = datetime.now() - start
154
+ # Must publish in find / getMore / explain command response
155
+ # format.
156
+ if use_cmd:
157
+ res = docs[0]
158
+ elif operation.name == "explain":
159
+ res = docs[0] if docs else {}
160
+ else:
161
+ res = {"cursor": {"id": reply.cursor_id, "ns": operation.namespace()}, "ok": 1}
162
+ if operation.name == "find":
163
+ res["cursor"]["firstBatch"] = docs
164
+ else:
165
+ res["cursor"]["nextBatch"] = docs
166
+ listeners.publish_command_success(
167
+ duration,
168
+ res,
169
+ operation.name,
170
+ request_id,
171
+ sock_info.address,
172
+ service_id=sock_info.service_id,
173
+ )
174
+
175
+ # Decrypt response.
176
+ client = operation.client
177
+ if client and client._encrypter:
178
+ if use_cmd:
179
+ decrypted = client._encrypter.decrypt(reply.raw_command_response())
180
+ docs = _decode_all_selective(decrypted, operation.codec_options, user_fields)
181
+
182
+ response: Response
183
+
184
+ if client._should_pin_cursor(operation.session) or operation.exhaust:
185
+ sock_info.pin_cursor()
186
+ if isinstance(reply, _OpMsg):
187
+ # In OP_MSG, the server keeps sending only if the
188
+ # more_to_come flag is set.
189
+ more_to_come = reply.more_to_come
190
+ else:
191
+ # In OP_REPLY, the server keeps sending until cursor_id is 0.
192
+ more_to_come = bool(operation.exhaust and reply.cursor_id)
193
+ if operation.sock_mgr:
194
+ operation.sock_mgr.update_exhaust(more_to_come)
195
+ response = PinnedResponse(
196
+ data=reply,
197
+ address=self._description.address,
198
+ socket_info=sock_info,
199
+ duration=duration,
200
+ request_id=request_id,
201
+ from_command=use_cmd,
202
+ docs=docs,
203
+ more_to_come=more_to_come,
204
+ )
205
+ else:
206
+ response = Response(
207
+ data=reply,
208
+ address=self._description.address,
209
+ duration=duration,
210
+ request_id=request_id,
211
+ from_command=use_cmd,
212
+ docs=docs,
213
+ )
214
+
215
+ return response
216
+
217
+ def get_socket(self, handler=None):
218
+ return self.pool.get_socket(handler)
219
+
220
+ @property
221
+ def description(self):
222
+ return self._description
223
+
224
+ @description.setter
225
+ def description(self, server_description):
226
+ assert server_description.address == self._description.address
227
+ self._description = server_description
228
+
229
+ @property
230
+ def pool(self):
231
+ return self._pool
232
+
233
+ def _split_message(self, message):
234
+ """Return request_id, data, max_doc_size.
235
+
236
+ :Parameters:
237
+ - `message`: (request_id, data, max_doc_size) or (request_id, data)
238
+ """
239
+ if len(message) == 3:
240
+ return message
241
+ else:
242
+ # get_more and kill_cursors messages don't include BSON documents.
243
+ request_id, data = message
244
+ return request_id, data, 0
245
+
246
+ def __repr__(self):
247
+ return "<%s %r>" % (self.__class__.__name__, self._description)