def grant_access(self, username, hostname, databases): """Grant a user permission to use a given database.""" user = self._get_user(username, hostname) mydb = None # cache the model as we just want name validation with mysql_util.SqlClient(self.mysql_app.get_engine(), use_flush=True) as client: for database in databases: try: if mydb: mydb.name = database else: mydb = models.MySQLSchema(name=database) mydb.check_reserved() except ValueError: LOG.exception("Error granting access") raise exception.BadRequest( _("Grant access to %s is not allowed") % database) g = sql_query.Grant(permissions='ALL', database=mydb.name, user=user.name, host=user.host, hashed=user.password) t = text(str(g)) client.execute(t)
def list_databases(self, limit=None, marker=None, include_marker=False): """List databases the user created on this mysql instance.""" LOG.debug("---Listing Databases---") ignored_database_names = "'%s'" % "', '".join(cfg.get_ignored_dbs()) LOG.debug( "The following database names are on ignore list and will " "be omitted from the listing: %s", ignored_database_names) databases = [] with self.local_sql_client(self.mysql_app.get_engine()) as client: # If you have an external volume mounted at /var/lib/mysql # the lost+found directory will show up in mysql as a database # which will create errors if you try to do any database ops # on it. So we remove it here if it exists. q = sql_query.Query() q.columns = [ 'schema_name as name', 'default_character_set_name as charset', 'default_collation_name as collation', ] q.tables = ['information_schema.schemata'] q.where = ["schema_name NOT IN (" + ignored_database_names + ")"] q.order = ['schema_name ASC'] if limit: q.limit = limit + 1 if marker: q.where.append( "schema_name %s '%s'" % (INCLUDE_MARKER_OPERATORS[include_marker], marker)) t = text(str(q)) database_names = client.execute(t) next_marker = None LOG.debug("database_names = %r.", database_names) for count, database in enumerate(database_names): if limit is not None and count >= limit: break LOG.debug("database = %s.", str(database)) mysql_db = models.MySQLSchema(name=database[0], character_set=database[1], collate=database[2]) next_marker = mysql_db.name databases.append(mysql_db.serialize()) LOG.debug("databases = %s", str(databases)) if limit is not None and database_names.rowcount <= limit: next_marker = None return databases, next_marker
def delete(self, req, tenant_id, instance_id, id): LOG.info("Deleting schema for instance '%(id)s'\n" "req : '%(req)s'\n\n", {"id": instance_id, "req": req}) context = req.environ[wsgi.CONTEXT_KEY] self.authorize_target_action( context, 'database:delete', instance_id) context.notification = notification.DBaaSDatabaseDelete( context, request=req) with StartNotification(context, instance_id=instance_id, dbname=id): try: schema = guest_models.MySQLSchema(name=id) schema.check_delete() if not models.Schemas.find(context, instance_id, id): raise exception.DatabaseNotFound(uuid=id) models.Schema.delete(context, instance_id, schema.serialize()) except (ValueError, AttributeError) as e: raise exception.BadRequest(_("Database delete error: %(e)s") % {'e': e}) return wsgi.Result(None, 202)
def populate_validated_databases(dbs): """ Create a serializable request with user provided data for creating new databases. """ try: databases = [] unique_identities = set() for database in dbs: mydb = guest_models.MySQLSchema(name=database.get('name', '')) mydb.check_reserved() if mydb.name in unique_identities: raise exception.DatabaseInitialDatabaseDuplicateError() unique_identities.add(mydb.name) mydb.character_set = database.get('character_set', '') mydb.collate = database.get('collate', '') databases.append(mydb.serialize()) return databases except ValueError as ve: # str(ve) contains user input and may include '%' which can cause a # format str vulnerability. Escape the '%' to avoid this. This is # okay to do since we're not using dict args here in any case. safe_string = str(ve).replace('%', '%%') raise exception.BadRequest(safe_string)