def delete(self, req, tenant_id, instance_id, id): LOG.info("Delete 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, 'user:delete', instance_id) id = correct_id_with_req(id, req) username, host = unquote_user_host(id) user = None context.notification = notification.DBaaSUserDelete(context, request=req) with StartNotification(context, instance_id=instance_id, username=username): try: user = guest_models.MySQLUser(name=username, host=host) found_user = models.User.load(context, instance_id, username, host) if not found_user: user = None except (ValueError, AttributeError) as e: raise exception.BadRequest(_("User delete error: %(e)s") % {'e': e}) if not user: raise exception.UserNotFound(uuid=id) models.User.delete(context, instance_id, user.serialize()) return wsgi.Result(None, 202)
def _create_replication_user(self): replication_user = None replication_password = utils.generate_random_password(16) mysql_user = None # cache the model as we just want name validation retry_count = 0 while replication_user is None: try: name = 'slave_' + str(uuid.uuid4())[:8] if mysql_user: mysql_user.name = name else: mysql_user = models.MySQLUser( name=name, password=replication_password ) mysql_user.check_create() MySqlAdmin().create_user([mysql_user.serialize()]) LOG.debug("Trying to create replication user " + mysql_user.name) replication_user = { 'name': mysql_user.name, 'password': replication_password } except Exception: retry_count += 1 if retry_count > 5: LOG.error("Replication user retry count exceeded") raise return replication_user
def _get_user(self, username, hostname): """Return a single user matching the criteria.""" user = None try: # Could possibly throw a ValueError here. user = models.MySQLUser(name=username) user.check_reserved() except ValueError as ve: LOG.exception(_("Error Getting user information")) err_msg = encodeutils.exception_to_unicode(ve) raise exception.BadRequest( _("Username %(user)s is not valid" ": %(reason)s") % { 'user': username, 'reason': err_msg }) with self.local_sql_client(self.mysql_app.get_engine()) as client: q = sql_query.Query() q.columns = ['User', 'Host'] q.tables = ['mysql.user'] q.where = [ "Host != 'localhost'", "User = '******'" % username, "Host = '%s'" % hostname ] q.order = ['User', 'Host'] t = text(str(q)) result = client.execute(t).fetchall() LOG.debug("Getting user information %s.", result) if len(result) != 1: return None found_user = result[0] user.host = found_user['Host'] self._associate_dbs(user) return user
def update_attributes(cls, context, instance_id, username, hostname, user_attrs): load_and_verify(context, instance_id) client = create_guest_client(context, instance_id) user_changed = user_attrs.get('name') host_changed = user_attrs.get('host') user = user_changed or username host = host_changed or hostname validate = guest_models.MySQLUser(name=user, host=host) validate.check_reserved() userhost = "%s@%s" % (user, host) if user_changed or host_changed: existing_users, _nadda = Users.load_with_client( client, limit=1, marker=userhost, include_marker=True) if (len(existing_users) > 0 and existing_users[0].name == user and existing_users[0].host == host): raise exception.UserAlreadyExists(name=user, host=host) client.update_attributes(username, hostname, user_attrs)
def load(cls, context, instance_id, username, hostname, root_user=False): load_and_verify(context, instance_id) validate = guest_models.MySQLUser(name=username, host=hostname) if root_user: validate.make_root() validate.check_reserved() client = create_guest_client(context, instance_id) found_user = client.get_user(username=username, hostname=hostname) if not found_user: return None database_names = [{ 'name': db['_name'] } for db in found_user['_databases']] return cls(found_user['_name'], found_user['_host'], found_user['_password'], database_names)
def update_all(self, req, body, tenant_id, instance_id): """Change the password of one or more users.""" LOG.info( _("Updating user password for instance '%(id)s'\n" "req : '%(req)s'\n\n") % { "id": instance_id, "req": strutils.mask_password(req) }) context = req.environ[wsgi.CONTEXT_KEY] self.authorize_target_action(context, 'user:update_all', instance_id) context.notification = notification.DBaaSUserChangePassword( context, request=req) users = body['users'] model_users = [] with StartNotification(context, instance_id=instance_id, username="******".join( [user['name'] for user in users])): for user in users: try: mu = guest_models.MySQLUser(name=user['name'], host=user.get('host'), password=user['password']) found_user = models.User.load(context, instance_id, mu.name, mu.host) if not found_user: user_and_host = mu.name if mu.host: user_and_host += '@' + mu.host raise exception.UserNotFound(uuid=user_and_host) model_users.append(mu) except (ValueError, AttributeError) as e: raise exception.BadRequest( _("Error loading user: %(e)s") % {'e': e}) try: models.User.change_password(context, instance_id, model_users) except (ValueError, AttributeError) as e: raise exception.BadRequest( _("User password update error: " "%(e)s") % {'e': e}) return wsgi.Result(None, 202)
def populate_users(users, initial_databases=None): """Create a serializable request containing users.""" users_data = [] unique_identities = set() for user in users: u = guest_models.MySQLUser(name=user.get('name', ''), host=user.get('host', '%')) u.check_reserved() user_identity = (u.name, u.host) if user_identity in unique_identities: raise exception.DatabaseInitialUserDuplicateError() unique_identities.add(user_identity) u.password = user.get('password', '') user_dbs = user.get('databases', '') # user_db_names guaranteed unique and non-empty by apischema user_db_names = [user_db.get('name', '') for user_db in user_dbs] for user_db_name in user_db_names: if (initial_databases is not None and user_db_name not in initial_databases): raise exception.DatabaseForUserNotInDatabaseListError( user=u.name, database=user_db_name) u.databases = user_db_name users_data.append(u.serialize()) return users_data
def list_users(self, limit=None, marker=None, include_marker=False): """List users that have access to the database.""" ''' SELECT User, Host, Marker FROM (SELECT User, Host, CONCAT(User, '@', Host) as Marker FROM mysql.user ORDER BY 1, 2) as innerquery WHERE Marker > :marker ORDER BY Marker LIMIT :limit; ''' LOG.debug("---Listing Users---") ignored_user_names = "'%s'" % "', '".join(cfg.get_ignored_users()) LOG.debug( "The following user names are on ignore list and will " "be omitted from the listing: %s", ignored_user_names) users = [] with self.local_sql_client(self.mysql_app.get_engine()) as client: iq = sql_query.Query() # Inner query. iq.columns = ['User', 'Host', "CONCAT(User, '@', Host) as Marker"] iq.tables = ['mysql.user'] iq.order = ['User', 'Host'] innerquery = str(iq).rstrip(';') oq = sql_query.Query() # Outer query. oq.columns = ['User', 'Host', 'Marker'] oq.tables = ['(%s) as innerquery' % innerquery] oq.where = [ "Host != 'localhost'", "User NOT IN (" + ignored_user_names + ")" ] oq.order = ['Marker'] if marker: oq.where.append( "Marker %s '%s'" % (INCLUDE_MARKER_OPERATORS[include_marker], marker)) if limit: oq.limit = limit + 1 t = text(str(oq)) result = client.execute(t) next_marker = None LOG.debug("result = %s", str(result)) for count, row in enumerate(result): if limit is not None and count >= limit: break LOG.debug("user = %s", str(row)) mysql_user = models.MySQLUser(name=row['User'], host=row['Host']) mysql_user.check_reserved() self._associate_dbs(mysql_user) next_marker = row['Marker'] users.append(mysql_user.serialize()) if limit is not None and result.rowcount <= limit: next_marker = None LOG.debug("users = %s", str(users)) return users, next_marker
def _empty_user(self): return models.MySQLUser(deserializing=True)