ssh-wrapper: perf optimizations

- make key timestamp update pure sql so we don't generate model import overhead
- code cleanups
This commit is contained in:
RhodeCode Admin 2023-03-08 14:57:45 +01:00
parent 7486eea956
commit c3da01c179
2 changed files with 52 additions and 20 deletions

View file

@ -23,8 +23,9 @@ import re
import logging
import datetime
import configparser
from sqlalchemy import Table
from rhodecode.model.db import Session, User, UserSshKeys
from rhodecode.lib.utils2 import AttributeDict
from rhodecode.model.scm import ScmModel
from .hg import MercurialServer
@ -39,11 +40,11 @@ class SshWrapper(object):
svn_cmd_pat = re.compile(r'^svnserve -t')
def __init__(self, command, connection_info, mode,
user, user_id, key_id, shell, ini_path, env):
user, user_id, key_id: int, shell, ini_path: str, env):
self.command = command
self.connection_info = connection_info
self.mode = mode
self.user = user
self.username = user
self.user_id = user_id
self.key_id = key_id
self.shell = shell
@ -59,14 +60,38 @@ class SshWrapper(object):
return parser
def update_key_access_time(self, key_id):
key = UserSshKeys().query().filter(
UserSshKeys.ssh_key_id == key_id).scalar()
if key:
key.accessed_on = datetime.datetime.utcnow()
Session().add(key)
Session().commit()
from rhodecode.model.meta import raw_query_executor, Base
table = Table('user_ssh_keys', Base.metadata, autoload=False)
stmt = (
table.update()
.where(table.c.ssh_key_id == key_id)
.values(accessed_on=datetime.datetime.utcnow())
.returning(table.c.accessed_on, table.c.ssh_key_fingerprint)
)
scalar_res = None
with raw_query_executor() as session:
result = session.execute(stmt)
if result.rowcount:
scalar_res = result.first()
if scalar_res:
atime, ssh_key_fingerprint = scalar_res
log.debug('Update key id:`%s` fingerprint:`%s` access time',
key_id, key.ssh_key_fingerprint)
key_id, ssh_key_fingerprint)
def get_user(self, user_id):
user = AttributeDict()
# lazy load db imports
from rhodecode.model.db import User
dbuser = User.get(user_id)
if not dbuser:
return None
user.user_id = dbuser.user_id
user.username = dbuser.username
user.auth_user = dbuser.AuthUser()
return user
def get_connection_info(self):
"""
@ -186,7 +211,7 @@ class SshWrapper(object):
def wrap(self):
mode = self.mode
user = self.user
username = self.username
user_id = self.user_id
key_id = self.key_id
shell = self.shell
@ -194,29 +219,30 @@ class SshWrapper(object):
scm_detected, scm_repo, scm_mode = self.get_repo_details(mode)
log.debug(
'Mode: `%s` User: `%s:%s` Shell: `%s` SSH Command: `\"%s\"` '
'Mode: `%s` User: `name:%s : id:%s` Shell: `%s` SSH Command: `\"%s\"` '
'SCM_DETECTED: `%s` SCM Mode: `%s` SCM Repo: `%s`',
mode, user, user_id, shell, self.command,
mode, username, user_id, shell, self.command,
scm_detected, scm_mode, scm_repo)
# update last access time for this key
self.update_key_access_time(key_id)
log.debug('SSH Connection info %s', self.get_connection_info())
# update last access time for this key
if key_id:
self.update_key_access_time(key_id)
if shell and self.command is None:
log.info('Dropping to shell, no command given and shell is allowed')
os.execl('/bin/bash', '-l')
exit_code = 1
elif scm_detected:
user = User.get(user_id)
user = self.get_user(user_id)
if not user:
log.warning('User with id %s not found', user_id)
exit_code = -1
return exit_code
auth_user = user.AuthUser()
auth_user = user.auth_user
permissions = auth_user.permissions['repositories']
repo_branch_permissions = auth_user.get_branch_permissions(scm_repo)
try:

View file

@ -24,10 +24,10 @@ SQLAlchemy Metadata and Session object
from sqlalchemy.orm import declarative_base
from sqlalchemy.orm import scoped_session, sessionmaker
from sqlalchemy.orm import Session as SASession
from rhodecode.lib import caching_query
__all__ = ['Base', 'Session']
__all__ = ['Base', 'Session', 'raw_query_executor']
# scoped_session. Apply our custom CachingQuery class to it,
# using a callable that will associate the dictionary
@ -43,3 +43,9 @@ Session = scoped_session(
# The declarative Base
Base = declarative_base()
def raw_query_executor():
engine = Base.metadata.bind
session = SASession(engine)
return session