From 36192adcef9a1c2c796437fee2d1881ef1437e84 Mon Sep 17 00:00:00 2001 From: Marco Bardelli <bardelli.marco@gmail.com> Date: Mon, 27 Jul 2015 10:48:29 +0200 Subject: [PATCH 1/4] allow SSL with pymongo >= 3.0 --- mongodbtools/collection_stats.py | 33 ++++++++++++++++++++++++---- mongodbtools/index_stats.py | 36 ++++++++++++++++++++++++++----- mongodbtools/redundant_indexes.py | 32 +++++++++++++++++++++++---- requirements.txt | 2 +- 4 files changed, 89 insertions(+), 14 deletions(-) diff --git a/mongodbtools/collection_stats.py b/mongodbtools/collection_stats.py index 4e03464..bf85651 100755 --- a/mongodbtools/collection_stats.py +++ b/mongodbtools/collection_stats.py @@ -7,9 +7,17 @@ from prettytable import PrettyTable import psutil -from pymongo import Connection from pymongo import ReadPreference from optparse import OptionParser +from distutils.version import StrictVersion +import pymongo + +HAS_PYMONGO3 = bool(StrictVersion(pymongo.version) >= StrictVersion('3.0')) + +if HAS_PYMONGO3: + from pymongo import MongoClient +else: + from pymongo import Connection as MongoClient def compute_signature(index): signature = index["ns"] @@ -50,18 +58,34 @@ def get_cli_options(): default="", metavar="PASSWORD", help="Admin password if authentication is enabled") + parser.add_option("--ssl-cert", + dest="ssl_certfile", + default=None, + metavar="CERTIFICATE", + help="SSL Certificate to use is SSL is enabled (only with pymongo >= 3)") + parser.add_option("--ssl-ca-certs", + dest="ssl_ca_certs", + default=None, + metavar="CA", + help="SSL Certificate of CA for certificate validation if SSL is enabled (only with pymongo >= 3)") (options, args) = parser.parse_args() return options -def get_connection(host, port, username, password): +def get_connection(host, port, username, password, ssl_certfile=None, ssl_ca_certs=None): userPass = "" if username and password: userPass = username + ":" + password + "@" mongoURI = "mongodb://" + userPass + host + ":" + str(port) - return Connection(host=mongoURI, read_preference=ReadPreference.SECONDARY) + + conn_kwargs = dict(host=mongoURI, read_preference=ReadPreference.SECONDARY) + + if HAS_PYMONGO3: + conn_kwargs.update(dict(ssl_certfile=ssl_certfile, ssl_ca_certs=ssl_ca_certs)) + + return MongoClient(**conn_kwargs) # From http://www.5dollarwhitebox.org/drupal/node/84 def convert_bytes(bytes): @@ -92,7 +116,8 @@ def main(options): } all_stats = [] - connection = get_connection(options.host, options.port, options.user, options.password) + connection = get_connection(options.host, options.port, options.user, options.password, + options.ssl_certfile, options.ssl_ca_certs) all_db_stats = {} diff --git a/mongodbtools/index_stats.py b/mongodbtools/index_stats.py index fd1313d..6a73a2e 100755 --- a/mongodbtools/index_stats.py +++ b/mongodbtools/index_stats.py @@ -7,9 +7,18 @@ from prettytable import PrettyTable import psutil -from pymongo import Connection +from socket import getfqdn from pymongo import ReadPreference from optparse import OptionParser +from distutils.version import StrictVersion +import pymongo + +HAS_PYMONGO3 = bool(StrictVersion(pymongo.version) >= StrictVersion('3.0')) + +if HAS_PYMONGO3: + from pymongo import MongoClient +else: + from pymongo import Connection as MongoClient def compute_signature(index): signature = index["ns"] @@ -70,18 +79,34 @@ def get_cli_options(): default="", metavar="PASSWORD", help="Admin password if authentication is enabled") + parser.add_option("--ssl-cert", + dest="ssl_certfile", + default=None, + metavar="CERTIFICATE", + help="SSL Certificate to use is SSL is enabled") + parser.add_option("--ssl-ca-certs", + dest="ssl_ca_certs", + default=None, + metavar="CA", + help="SSL Certificate of CA for certificate validation if SSL is enabled") (options, args) = parser.parse_args() return options -def get_connection(host, port, username, password): +def get_connection(host, port, username, password, ssl_certfile=None, ssl_ca_certs=None): userPass = "" if username and password: userPass = username + ":" + password + "@" mongoURI = "mongodb://" + userPass + host + ":" + str(port) - return Connection(host=mongoURI, read_preference=ReadPreference.SECONDARY) + + conn_kwargs = dict(host=mongoURI, read_preference=ReadPreference.SECONDARY) + + if HAS_PYMONGO3: + conn_kwargs.update(dict(ssl_certfile=ssl_certfile, ssl_ca_certs=ssl_ca_certs)) + + return MongoClient(**conn_kwargs) def main(options): summary_stats = { @@ -91,7 +116,8 @@ def main(options): } all_stats = [] - connection = get_connection(options.host, options.port, options.user, options.password) + connection = get_connection(options.host, options.port, options.user, options.password, + options.ssl_certfile, options.ssl_ca_certs) all_db_stats = {} @@ -164,7 +190,7 @@ def main(options): print "Total Index Size:", convert_bytes(summary_stats["indexSize"]) # this is only meaningful if we're running the script on localhost - if options.host == "localhost": + if options.host == "localhost" or options.host == getfqdn(): ram_headroom = psutil.phymem_usage()[0] - summary_stats["indexSize"] print "RAM Headroom:", convert_bytes(ram_headroom) print "RAM Used: %s (%s%%)" % (convert_bytes(psutil.phymem_usage()[1]), psutil.phymem_usage()[3]) diff --git a/mongodbtools/redundant_indexes.py b/mongodbtools/redundant_indexes.py index 12b202e..6cd8807 100755 --- a/mongodbtools/redundant_indexes.py +++ b/mongodbtools/redundant_indexes.py @@ -6,10 +6,17 @@ with just fields {field1:1}, the latter index is not needed since the first index already indexes the necessary fields. """ -from pymongo import Connection from pymongo import ReadPreference from optparse import OptionParser +from distutils.version import StrictVersion +import pymongo +HAS_PYMONGO3 = bool(StrictVersion(pymongo.version) >= StrictVersion('3.0')) + +if HAS_PYMONGO3: + from pymongo import MongoClient +else: + from pymongo import Connection as MongoClient def get_cli_options(): parser = OptionParser(usage="usage: python %prog [options]", @@ -40,21 +47,38 @@ def get_cli_options(): default="", metavar="PASSWORD", help="Admin password if authentication is enabled") + parser.add_option("--ssl-cert", + dest="ssl_certfile", + default=None, + metavar="CERTIFICATE", + help="SSL Certificate to use is SSL is enabled (only with pymongo >= 3)") + parser.add_option("--ssl-ca-certs", + dest="ssl_ca_certs", + default=None, + metavar="CA", + help="SSL Certificate of CA for certificate validation if SSL is enabled (only with pymongo >= 3)") (options, args) = parser.parse_args() return options -def get_connection(host, port, username, password): +def get_connection(host, port, username, password, ssl_certfile=None, ssl_ca_certs=None): userPass = "" if username and password: userPass = username + ":" + password + "@" mongoURI = "mongodb://" + userPass + host + ":" + str(port) - return Connection(host=mongoURI, read_preference=ReadPreference.SECONDARY) + + conn_kwargs = dict(host=mongoURI, read_preference=ReadPreference.SECONDARY) + + if HAS_PYMONGO3: + conn_kwargs.update(dict(ssl_certfile=ssl_certfile, ssl_ca_certs=ssl_ca_certs)) + + return MongoClient(**conn_kwargs) def main(options): - connection = get_connection(options.host, options.port, options.user, options.password) + connection = get_connection(options.host, options.port, options.user, options.password, + options.ssl_certfile, options.ssl_ca_certs) def compute_signature(index): signature = index["ns"] diff --git a/requirements.txt b/requirements.txt index c880503..237758a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -pymongo==2.1 +pymongo>=2.1 PrettyTable==0.7.1 psutil==0.3.0 mongoengine==0.5.0 From f885307d50d308b3a1a91ace5d7e9e3e91eed67d Mon Sep 17 00:00:00 2001 From: Marco Bardelli <bardelli.marco@gmail.com> Date: Mon, 27 Jul 2015 11:09:56 +0200 Subject: [PATCH 2/4] use print as function looking forward to py3 --- mongodbtools/collection_stats.py | 20 ++++++++++---------- mongodbtools/index_stats.py | 24 ++++++++++++------------ mongodbtools/redundant_indexes.py | 8 ++++---- 3 files changed, 26 insertions(+), 26 deletions(-) diff --git a/mongodbtools/collection_stats.py b/mongodbtools/collection_stats.py index bf85651..de41de7 100755 --- a/mongodbtools/collection_stats.py +++ b/mongodbtools/collection_stats.py @@ -17,7 +17,7 @@ if HAS_PYMONGO3: from pymongo import MongoClient else: - from pymongo import Connection as MongoClient + from pymongo import Connection as MongoClient # pylint: disable=E0611 def compute_signature(index): signature = index["ns"] @@ -26,7 +26,7 @@ def compute_signature(index): return signature def get_collection_stats(database, collection): - print "Checking DB: %s" % collection.full_name + print("Checking DB: %s" % collection.full_name) return database.command("collstats", collection.name) def get_cli_options(): @@ -170,18 +170,18 @@ def main(options): ]) print - print x.get_string(sortby="% Size") - print "Total Documents:", summary_stats["count"] - print "Total Data Size:", convert_bytes(summary_stats["size"]) - print "Total Index Size:", convert_bytes(summary_stats["indexSize"]) - print "Total Storage Size:", convert_bytes(summary_stats["storageSize"]) + print(x.get_string(sortby="% Size")) + print("Total Documents:", summary_stats["count"]) + print("Total Data Size:", convert_bytes(summary_stats["size"])) + print("Total Index Size:", convert_bytes(summary_stats["indexSize"])) + print("Total Storage Size:", convert_bytes(summary_stats["storageSize"])) # this is only meaningful if we're running the script on localhost if options.host == "localhost": ram_headroom = psutil.phymem_usage()[0] - summary_stats["indexSize"] - print "RAM Headroom:", convert_bytes(ram_headroom) - print "RAM Used: %s (%s%%)" % (convert_bytes(psutil.phymem_usage()[1]), psutil.phymem_usage()[3]) - print "Available RAM Headroom:", convert_bytes((100 - psutil.phymem_usage()[3]) / 100 * ram_headroom) + print("RAM Headroom:", convert_bytes(ram_headroom)) + print("RAM Used: %s (%s%%)" % (convert_bytes(psutil.phymem_usage()[1]), psutil.phymem_usage()[3])) + print("Available RAM Headroom:", convert_bytes((100 - psutil.phymem_usage()[3]) / 100 * ram_headroom)) if __name__ == "__main__": options = get_cli_options() diff --git a/mongodbtools/index_stats.py b/mongodbtools/index_stats.py index 6a73a2e..c3f9daa 100755 --- a/mongodbtools/index_stats.py +++ b/mongodbtools/index_stats.py @@ -18,7 +18,7 @@ if HAS_PYMONGO3: from pymongo import MongoClient else: - from pymongo import Connection as MongoClient + from pymongo import Connection as MongoClient # pylint: disable=E0611 def compute_signature(index): signature = index["ns"] @@ -27,7 +27,7 @@ def compute_signature(index): return signature def get_collection_stats(database, collection): - print "Checking DB: %s" % collection.full_name + print("Checking DB: %s" % collection.full_name) return database.command("collstats", collection.name) # From http://www.5dollarwhitebox.org/drupal/node/84 @@ -167,11 +167,11 @@ def main(options): x.add_row(row) - print "Index Overview" - print x.get_string(sortby="Collection") + print("Index Overview") + print(x.get_string(sortby="Collection")) print - print "Top 5 Largest Indexes" + print("Top 5 Largest Indexes") x = PrettyTable(["Collection", "Index","% Size", "Index Size"]) x.align["Collection"] = "l" x.align["Index"] = "l" @@ -182,19 +182,19 @@ def main(options): top_five_indexes = sorted(index_size_mapping.keys(), reverse=True)[0:5] for size in top_five_indexes: x.add_row(index_size_mapping.get(size)) - print x + print(x) print - print "Total Documents:", summary_stats["count"] - print "Total Data Size:", convert_bytes(summary_stats["size"]) - print "Total Index Size:", convert_bytes(summary_stats["indexSize"]) + print("Total Documents:", summary_stats["count"]) + print("Total Data Size:", convert_bytes(summary_stats["size"])) + print("Total Index Size:", convert_bytes(summary_stats["indexSize"])) # this is only meaningful if we're running the script on localhost if options.host == "localhost" or options.host == getfqdn(): ram_headroom = psutil.phymem_usage()[0] - summary_stats["indexSize"] - print "RAM Headroom:", convert_bytes(ram_headroom) - print "RAM Used: %s (%s%%)" % (convert_bytes(psutil.phymem_usage()[1]), psutil.phymem_usage()[3]) - print "Available RAM Headroom:", convert_bytes((100 - psutil.phymem_usage()[3]) / 100 * ram_headroom) + print("RAM Headroom:", convert_bytes(ram_headroom)) + print("RAM Used: %s (%s%%)" % (convert_bytes(psutil.phymem_usage()[1]), psutil.phymem_usage()[3])) + print("Available RAM Headroom:", convert_bytes((100 - psutil.phymem_usage()[3]) / 100 * ram_headroom)) if __name__ == "__main__": options = get_cli_options() diff --git a/mongodbtools/redundant_indexes.py b/mongodbtools/redundant_indexes.py index 6cd8807..64c843d 100755 --- a/mongodbtools/redundant_indexes.py +++ b/mongodbtools/redundant_indexes.py @@ -16,7 +16,7 @@ if HAS_PYMONGO3: from pymongo import MongoClient else: - from pymongo import Connection as MongoClient + from pymongo import Connection as MongoClient # pylint: disable=E0611 def get_cli_options(): parser = OptionParser(usage="usage: python %prog [options]", @@ -90,7 +90,7 @@ def compute_signature(index): return signature def report_redundant_indexes(current_db): - print "Checking DB: %s" % current_db.name + print("Checking DB: %s" % current_db.name) indexes = current_db.system.indexes.find() index_map = {} for index in indexes: @@ -102,11 +102,11 @@ def report_redundant_indexes(current_db): if signature == other_sig: continue if other_sig.startswith(signature): - print "Index %s[%s] may be redundant with %s[%s]" % ( + print ("Index %s[%s] may be redundant with %s[%s]" % ( index_map[signature]["ns"], index_map[signature]["name"], index_map[other_sig]["ns"], - index_map[other_sig]["name"]) + index_map[other_sig]["name"])) databases= [] if options.database: From 0fdb38f81264db054fcd1122dd0d2a7b055cbfbd Mon Sep 17 00:00:00 2001 From: Marco Bardelli <bardelli.marco@gmail.com> Date: Mon, 27 Jul 2015 13:25:03 +0200 Subject: [PATCH 3/4] better format for print --- mongodbtools/collection_stats.py | 15 ++++++++------- mongodbtools/index_stats.py | 10 +++++----- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/mongodbtools/collection_stats.py b/mongodbtools/collection_stats.py index de41de7..943a08e 100755 --- a/mongodbtools/collection_stats.py +++ b/mongodbtools/collection_stats.py @@ -7,6 +7,7 @@ from prettytable import PrettyTable import psutil +from socket import getfqdn from pymongo import ReadPreference from optparse import OptionParser from distutils.version import StrictVersion @@ -171,17 +172,17 @@ def main(options): print print(x.get_string(sortby="% Size")) - print("Total Documents:", summary_stats["count"]) - print("Total Data Size:", convert_bytes(summary_stats["size"])) - print("Total Index Size:", convert_bytes(summary_stats["indexSize"])) - print("Total Storage Size:", convert_bytes(summary_stats["storageSize"])) + print("Total Documents: %s" % summary_stats["count"]) + print("Total Data Size: %s" % convert_bytes(summary_stats["size"])) + print("Total Index Size: %s" % convert_bytes(summary_stats["indexSize"])) + print("Total Storage Size: %s" % convert_bytes(summary_stats["storageSize"])) # this is only meaningful if we're running the script on localhost - if options.host == "localhost": + if options.host == "localhost" or options.host == getfqdn(): ram_headroom = psutil.phymem_usage()[0] - summary_stats["indexSize"] - print("RAM Headroom:", convert_bytes(ram_headroom)) + print("RAM Headroom: %s" % convert_bytes(ram_headroom)) print("RAM Used: %s (%s%%)" % (convert_bytes(psutil.phymem_usage()[1]), psutil.phymem_usage()[3])) - print("Available RAM Headroom:", convert_bytes((100 - psutil.phymem_usage()[3]) / 100 * ram_headroom)) + print("Available RAM Headroom: %s" % convert_bytes((100 - psutil.phymem_usage()[3]) / 100 * ram_headroom)) if __name__ == "__main__": options = get_cli_options() diff --git a/mongodbtools/index_stats.py b/mongodbtools/index_stats.py index c3f9daa..0bccb21 100755 --- a/mongodbtools/index_stats.py +++ b/mongodbtools/index_stats.py @@ -185,16 +185,16 @@ def main(options): print(x) print - print("Total Documents:", summary_stats["count"]) - print("Total Data Size:", convert_bytes(summary_stats["size"])) - print("Total Index Size:", convert_bytes(summary_stats["indexSize"])) + print("Total Documents: %s" % summary_stats["count"]) + print("Total Data Size: %s" % convert_bytes(summary_stats["size"])) + print("Total Index Size: %s" % convert_bytes(summary_stats["indexSize"])) # this is only meaningful if we're running the script on localhost if options.host == "localhost" or options.host == getfqdn(): ram_headroom = psutil.phymem_usage()[0] - summary_stats["indexSize"] - print("RAM Headroom:", convert_bytes(ram_headroom)) + print("RAM Headroom: %s" % convert_bytes(ram_headroom)) print("RAM Used: %s (%s%%)" % (convert_bytes(psutil.phymem_usage()[1]), psutil.phymem_usage()[3])) - print("Available RAM Headroom:", convert_bytes((100 - psutil.phymem_usage()[3]) / 100 * ram_headroom)) + print("Available RAM Headroom: %s" % convert_bytes((100 - psutil.phymem_usage()[3]) / 100 * ram_headroom)) if __name__ == "__main__": options = get_cli_options() From 16a3afe90050e88c34b91f32ca52bf622492f672 Mon Sep 17 00:00:00 2001 From: Marco Bardelli <bardelli.marco@gmail.com> Date: Mon, 27 Jul 2015 13:25:38 +0200 Subject: [PATCH 4/4] allow console scripts main invocation w/o param --- mongodbtools/collection_stats.py | 5 ++++- mongodbtools/index_stats.py | 5 ++++- mongodbtools/redundant_indexes.py | 5 ++++- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/mongodbtools/collection_stats.py b/mongodbtools/collection_stats.py index 943a08e..8bade4b 100755 --- a/mongodbtools/collection_stats.py +++ b/mongodbtools/collection_stats.py @@ -108,7 +108,10 @@ def convert_bytes(bytes): size = '%.2fb' % bytes return size -def main(options): +def main(options=None): + if options is None: + options = get_cli_options() + summary_stats = { "count" : 0, "size" : 0, diff --git a/mongodbtools/index_stats.py b/mongodbtools/index_stats.py index 0bccb21..11ccfdc 100755 --- a/mongodbtools/index_stats.py +++ b/mongodbtools/index_stats.py @@ -108,7 +108,10 @@ def get_connection(host, port, username, password, ssl_certfile=None, ssl_ca_cer return MongoClient(**conn_kwargs) -def main(options): +def main(options=None): + if options is None: + options = get_cli_options() + summary_stats = { "count" : 0, "size" : 0, diff --git a/mongodbtools/redundant_indexes.py b/mongodbtools/redundant_indexes.py index 64c843d..fa5e843 100755 --- a/mongodbtools/redundant_indexes.py +++ b/mongodbtools/redundant_indexes.py @@ -76,7 +76,10 @@ def get_connection(host, port, username, password, ssl_certfile=None, ssl_ca_cer return MongoClient(**conn_kwargs) -def main(options): +def main(options=None): + if options is None: + options = get_cli_options() + connection = get_connection(options.host, options.port, options.user, options.password, options.ssl_certfile, options.ssl_ca_certs)