%PDF- %PDF-
Direktori : /proc/thread-self/root/lib/python2.7/site-packages/salt/modules/ |
Current File : //proc/thread-self/root/lib/python2.7/site-packages/salt/modules/mongodb.py |
# -*- coding: utf-8 -*- ''' Module to provide MongoDB functionality to Salt :configuration: This module uses PyMongo, and accepts configuration details as parameters as well as configuration settings:: mongodb.host: 'localhost' mongodb.port: 27017 mongodb.user: '' mongodb.password: '' This data can also be passed into pillar. Options passed into opts will overwrite options passed into pillar. ''' from __future__ import absolute_import, print_function, unicode_literals # Import python libs import logging import re # Import salt libs import salt.utils.json from salt.utils.versions import LooseVersion as _LooseVersion from salt.exceptions import get_error_message as _get_error_message # Import third party libs from salt.ext import six try: import pymongo HAS_MONGODB = True except ImportError: HAS_MONGODB = False log = logging.getLogger(__name__) def __virtual__(): ''' Only load this module if pymongo is installed ''' if HAS_MONGODB: return 'mongodb' else: return (False, 'The mongodb execution module cannot be loaded: the pymongo library is not available.') def _connect(user=None, password=None, host=None, port=None, database='admin', authdb=None): ''' Returns a tuple of (user, host, port) with config, pillar, or default values assigned to missing values. ''' if not user: user = __salt__['config.option']('mongodb.user') if not password: password = __salt__['config.option']('mongodb.password') if not host: host = __salt__['config.option']('mongodb.host') if not port: port = __salt__['config.option']('mongodb.port') if not authdb: authdb = database try: conn = pymongo.MongoClient(host=host, port=port) mdb = pymongo.database.Database(conn, database) if user and password: mdb.authenticate(user, password, source=authdb) except pymongo.errors.PyMongoError: log.error('Error connecting to database %s', database) return False return conn def _to_dict(objects): ''' Potentially interprets a string as JSON for usage with mongo ''' try: if isinstance(objects, six.string_types): objects = salt.utils.json.loads(objects) except ValueError as err: log.error("Could not parse objects: %s", err) raise err return objects def db_list(user=None, password=None, host=None, port=None, authdb=None): ''' List all MongoDB databases CLI Example: .. code-block:: bash salt '*' mongodb.db_list <user> <password> <host> <port> ''' conn = _connect(user, password, host, port, authdb=authdb) if not conn: return 'Failed to connect to mongo database' try: log.info('Listing databases') return conn.database_names() except pymongo.errors.PyMongoError as err: log.error(err) return six.text_type(err) def db_exists(name, user=None, password=None, host=None, port=None, authdb=None): ''' Checks if a database exists in MongoDB CLI Example: .. code-block:: bash salt '*' mongodb.db_exists <name> <user> <password> <host> <port> ''' dbs = db_list(user, password, host, port, authdb=authdb) if isinstance(dbs, six.string_types): return False return name in dbs def db_remove(name, user=None, password=None, host=None, port=None, authdb=None): ''' Remove a MongoDB database CLI Example: .. code-block:: bash salt '*' mongodb.db_remove <name> <user> <password> <host> <port> ''' conn = _connect(user, password, host, port, authdb=authdb) if not conn: return 'Failed to connect to mongo database' try: log.info('Removing database %s', name) conn.drop_database(name) except pymongo.errors.PyMongoError as err: log.error('Removing database %s failed with error: %s', name, err) return six.text_type(err) return True def _version(mdb): return mdb.command('buildInfo')['version'] def version(user=None, password=None, host=None, port=None, database='admin', authdb=None): ''' Get MongoDB instance version CLI Example: .. code-block:: bash salt '*' mongodb.version <user> <password> <host> <port> <database> ''' conn = _connect(user, password, host, port, authdb=authdb) if not conn: err_msg = "Failed to connect to MongoDB database {0}:{1}".format(host, port) log.error(err_msg) return (False, err_msg) try: mdb = pymongo.database.Database(conn, database) return _version(mdb) except pymongo.errors.PyMongoError as err: log.error('Listing users failed with error: %s', err) return six.text_type(err) def user_find(name, user=None, password=None, host=None, port=None, database='admin', authdb=None): ''' Get single user from MongoDB CLI Example: .. code-block:: bash salt '*' mongodb.user_find <name> <user> <password> <host> <port> <database> <authdb> ''' conn = _connect(user, password, host, port, authdb=authdb) if not conn: err_msg = "Failed to connect to MongoDB database {0}:{1}".format(host, port) log.error(err_msg) return (False, err_msg) mdb = pymongo.database.Database(conn, database) try: return mdb.command("usersInfo", name)["users"] except pymongo.errors.PyMongoError as err: log.error('Listing users failed with error: %s', err) return (False, six.text_type(err)) def user_list(user=None, password=None, host=None, port=None, database='admin', authdb=None): ''' List users of a MongoDB database CLI Example: .. code-block:: bash salt '*' mongodb.user_list <user> <password> <host> <port> <database> ''' conn = _connect(user, password, host, port, authdb=authdb) if not conn: return 'Failed to connect to mongo database' try: log.info('Listing users') mdb = pymongo.database.Database(conn, database) output = [] mongodb_version = _version(mdb) if _LooseVersion(mongodb_version) >= _LooseVersion('2.6'): for user in mdb.command('usersInfo')['users']: output.append( {'user': user['user'], 'roles': user['roles']} ) else: for user in mdb.system.users.find(): output.append( {'user': user['user'], 'readOnly': user.get('readOnly', 'None')} ) return output except pymongo.errors.PyMongoError as err: log.error('Listing users failed with error: %s', err) return six.text_type(err) def user_exists(name, user=None, password=None, host=None, port=None, database='admin', authdb=None): ''' Checks if a user exists in MongoDB CLI Example: .. code-block:: bash salt '*' mongodb.user_exists <name> <user> <password> <host> <port> <database> ''' users = user_list(user, password, host, port, database, authdb) if isinstance(users, six.string_types): return 'Failed to connect to mongo database' for user in users: if name == dict(user).get('user'): return True return False def user_create(name, passwd, user=None, password=None, host=None, port=None, database='admin', authdb=None, roles=None): ''' Create a MongoDB user CLI Example: .. code-block:: bash salt '*' mongodb.user_create <user_name> <user_password> <roles> <user> <password> <host> <port> <database> ''' conn = _connect(user, password, host, port, authdb=authdb) if not conn: return 'Failed to connect to mongo database' if not roles: roles = [] try: log.info('Creating user %s', name) mdb = pymongo.database.Database(conn, database) mdb.add_user(name, passwd, roles=roles) except pymongo.errors.PyMongoError as err: log.error('Creating database %s failed with error: %s', name, err) return six.text_type(err) return True def user_remove(name, user=None, password=None, host=None, port=None, database='admin', authdb=None): ''' Remove a MongoDB user CLI Example: .. code-block:: bash salt '*' mongodb.user_remove <name> <user> <password> <host> <port> <database> ''' conn = _connect(user, password, host, port) if not conn: return 'Failed to connect to mongo database' try: log.info('Removing user %s', name) mdb = pymongo.database.Database(conn, database) mdb.remove_user(name) except pymongo.errors.PyMongoError as err: log.error('Creating database %s failed with error: %s', name, err) return six.text_type(err) return True def user_roles_exists(name, roles, database, user=None, password=None, host=None, port=None, authdb=None): ''' Checks if a user of a MongoDB database has specified roles CLI Examples: .. code-block:: bash salt '*' mongodb.user_roles_exists johndoe '["readWrite"]' dbname admin adminpwd localhost 27017 .. code-block:: bash salt '*' mongodb.user_roles_exists johndoe '[{"role": "readWrite", "db": "dbname" }, {"role": "read", "db": "otherdb"}]' dbname admin adminpwd localhost 27017 ''' try: roles = _to_dict(roles) except Exception: return 'Roles provided in wrong format' users = user_list(user, password, host, port, database, authdb) if isinstance(users, six.string_types): return 'Failed to connect to mongo database' for user in users: if name == dict(user).get('user'): for role in roles: # if the role was provided in the shortened form, we convert it to a long form if not isinstance(role, dict): role = {'role': role, 'db': database} if role not in dict(user).get('roles', []): return False return True return False def user_grant_roles(name, roles, database, user=None, password=None, host=None, port=None, authdb=None): ''' Grant one or many roles to a MongoDB user CLI Examples: .. code-block:: bash salt '*' mongodb.user_grant_roles johndoe '["readWrite"]' dbname admin adminpwd localhost 27017 .. code-block:: bash salt '*' mongodb.user_grant_roles janedoe '[{"role": "readWrite", "db": "dbname" }, {"role": "read", "db": "otherdb"}]' dbname admin adminpwd localhost 27017 ''' conn = _connect(user, password, host, port, authdb=authdb) if not conn: return 'Failed to connect to mongo database' try: roles = _to_dict(roles) except Exception: return 'Roles provided in wrong format' try: log.info('Granting roles %s to user %s', roles, name) mdb = pymongo.database.Database(conn, database) mdb.command("grantRolesToUser", name, roles=roles) except pymongo.errors.PyMongoError as err: log.error('Granting roles %s to user %s failed with error: %s', roles, name, err) return six.text_type(err) return True def user_revoke_roles(name, roles, database, user=None, password=None, host=None, port=None, authdb=None): ''' Revoke one or many roles to a MongoDB user CLI Examples: .. code-block:: bash salt '*' mongodb.user_revoke_roles johndoe '["readWrite"]' dbname admin adminpwd localhost 27017 .. code-block:: bash salt '*' mongodb.user_revoke_roles janedoe '[{"role": "readWrite", "db": "dbname" }, {"role": "read", "db": "otherdb"}]' dbname admin adminpwd localhost 27017 ''' conn = _connect(user, password, host, port, authdb=authdb) if not conn: return 'Failed to connect to mongo database' try: roles = _to_dict(roles) except Exception: return 'Roles provided in wrong format' try: log.info('Revoking roles %s from user %s', roles, name) mdb = pymongo.database.Database(conn, database) mdb.command("revokeRolesFromUser", name, roles=roles) except pymongo.errors.PyMongoError as err: log.error('Revoking roles %s from user %s failed with error: %s', roles, name, err) return six.text_type(err) return True def insert(objects, collection, user=None, password=None, host=None, port=None, database='admin', authdb=None): ''' Insert an object or list of objects into a collection CLI Example: .. code-block:: bash salt '*' mongodb.insert '[{"foo": "FOO", "bar": "BAR"}, {"foo": "BAZ", "bar": "BAM"}]' mycollection <user> <password> <host> <port> <database> ''' conn = _connect(user, password, host, port, database, authdb) if not conn: return "Failed to connect to mongo database" try: objects = _to_dict(objects) except Exception as err: return err try: log.info("Inserting %r into %s.%s", objects, database, collection) mdb = pymongo.database.Database(conn, database) col = getattr(mdb, collection) ids = col.insert(objects) return ids except pymongo.errors.PyMongoError as err: log.error("Inserting objects %r failed with error %s", objects, err) return err def update_one(objects, collection, user=None, password=None, host=None, port=None, database='admin', authdb=None): ''' Update an object into a collection http://api.mongodb.com/python/current/api/pymongo/collection.html#pymongo.collection.Collection.update_one .. versionadded:: 2016.11.0 CLI Example: .. code-block:: bash salt '*' mongodb.update_one '{"_id": "my_minion"} {"bar": "BAR"}' mycollection <user> <password> <host> <port> <database> ''' conn = _connect(user, password, host, port, database, authdb) if not conn: return "Failed to connect to mongo database" objects = six.text_type(objects) objs = re.split(r'}\s+{', objects) if len(objs) is not 2: return "Your request does not contain a valid " + \ "'{_\"id\": \"my_id\"} {\"my_doc\": \"my_val\"}'" objs[0] = objs[0] + '}' objs[1] = '{' + objs[1] document = [] for obj in objs: try: obj = _to_dict(obj) document.append(obj) except Exception as err: return err _id_field = document[0] _update_doc = document[1] # need a string to perform the test, so using objs[0] test_f = find(collection, objs[0], user, password, host, port, database, authdb) if not isinstance(test_f, list): return 'The find result is not well formatted. An error appears; cannot update.' elif len(test_f) < 1: return 'Did not find any result. You should try an insert before.' elif len(test_f) > 1: return 'Too many results. Please try to be more specific.' else: try: log.info("Updating %r into %s.%s", _id_field, database, collection) mdb = pymongo.database.Database(conn, database) col = getattr(mdb, collection) ids = col.update_one(_id_field, {'$set': _update_doc}) nb_mod = ids.modified_count return "{0} objects updated".format(nb_mod) except pymongo.errors.PyMongoError as err: log.error('Updating object %s failed with error %s', objects, err) return err def find(collection, query=None, user=None, password=None, host=None, port=None, database='admin', authdb=None): ''' Find an object or list of objects in a collection CLI Example: .. code-block:: bash salt '*' mongodb.find mycollection '[{"foo": "FOO", "bar": "BAR"}]' <user> <password> <host> <port> <database> ''' conn = _connect(user, password, host, port, database, authdb) if not conn: return 'Failed to connect to mongo database' try: query = _to_dict(query) except Exception as err: return err try: log.info("Searching for %r in %s", query, collection) mdb = pymongo.database.Database(conn, database) col = getattr(mdb, collection) ret = col.find(query) return list(ret) except pymongo.errors.PyMongoError as err: log.error("Searching objects failed with error: %s", err) return err def remove(collection, query=None, user=None, password=None, host=None, port=None, database='admin', w=1, authdb=None): ''' Remove an object or list of objects into a collection CLI Example: .. code-block:: bash salt '*' mongodb.remove mycollection '[{"foo": "FOO", "bar": "BAR"}, {"foo": "BAZ", "bar": "BAM"}]' <user> <password> <host> <port> <database> ''' conn = _connect(user, password, host, port, database, authdb) if not conn: return 'Failed to connect to mongo database' try: query = _to_dict(query) except Exception as err: return _get_error_message(err) try: log.info("Removing %r from %s", query, collection) mdb = pymongo.database.Database(conn, database) col = getattr(mdb, collection) ret = col.remove(query, w=w) return "{0} objects removed".format(ret['n']) except pymongo.errors.PyMongoError as err: log.error("Removing objects failed with error: %s", _get_error_message(err)) return _get_error_message(err)