tillmo / two_tiered_quiz

A multiple choice quiz with justifications for the answers, written in Django
GNU Affero General Public License v3.0
0 stars 0 forks source link

Problem with deployed database #44

Closed tillmo closed 4 years ago

tillmo commented 4 years ago

Currently, the deployed backend always throws an error "attempt to write a readonly database", see below. If I manually start (on the server)

python3 manage.py runserver 0.0.0.0:8000

everything works. Also, if I make the database publicly readable, it works. It seems that the systemd script is run by a user who is not member of group webservd. The error can be reproduced with

curl -d 'username=test&password1=q76q76q76&password2=q76q76q76' http://quiz.iks.cs.ovgu.de:8000/rest-auth/registration/
OperationalError at /rest-auth/login/
attempt to write a readonly database

Request Method: POST
Request URL: http://quiz.iks.cs.ovgu.de:8000/rest-auth/login/
Django Version: 2.2.11
Python Executable: /usr/bin/python3
Python Version: 3.6.9
Python Path: ['/local/home/webadm/ttq/backend/lqserver', '/usr/lib/python36.zip', '/usr/lib/python3.6', '/usr/lib/python3.6/lib-dynload', '/local/home/webadm/ttq/python_modules/lib/python3.6/site-packages', '/usr/local/lib/python3.6/dist-packages', '/usr/lib/python3/dist-packages']
Server time: Sat, 4 Apr 2020 11:28:25 +0000
Installed Applications:
['django.contrib.admin',
 'django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.messages',
 'django.contrib.staticfiles',
 'rest_framework',
 'rest_framework.authtoken',
 'rest_auth',
 'django.contrib.sites',
 'allauth',
 'allauth.account',
 'allauth.socialaccount',
 'rest_auth.registration',
 'QuizBoard',
 'nested_admin']
Installed Middleware:
['corsheaders.middleware.CorsMiddleware',
 'django.middleware.security.SecurityMiddleware',
 'django.contrib.sessions.middleware.SessionMiddleware',
 'django.middleware.common.CommonMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.contrib.messages.middleware.MessageMiddleware',
 'django.middleware.clickjacking.XFrameOptionsMiddleware']

Traceback:

File "/local/home/webadm/ttq/python_modules/lib/python3.6/site-packages/django/db/backends/utils.py" in _execute
  84.                 return self.cursor.execute(sql, params)

File "/local/home/webadm/ttq/python_modules/lib/python3.6/site-packages/django/db/backends/sqlite3/base.py" in execute
  383.         return Database.Cursor.execute(self, query, params)

The above exception (attempt to write a readonly database) was the direct cause of the following exception:

File "/local/home/webadm/ttq/python_modules/lib/python3.6/site-packages/django/core/handlers/exception.py" in inner
  34.             response = get_response(request)

File "/local/home/webadm/ttq/python_modules/lib/python3.6/site-packages/django/core/handlers/base.py" in _get_response
  115.                 response = self.process_exception_by_middleware(e, request)

File "/local/home/webadm/ttq/python_modules/lib/python3.6/site-packages/django/core/handlers/base.py" in _get_response
  113.                 response = wrapped_callback(request, *callback_args, **callback_kwargs)

File "/local/home/webadm/ttq/python_modules/lib/python3.6/site-packages/django/views/decorators/csrf.py" in wrapped_view
  54.         return view_func(*args, **kwargs)

File "/local/home/webadm/ttq/python_modules/lib/python3.6/site-packages/django/views/generic/base.py" in view
  71.             return self.dispatch(request, *args, **kwargs)

File "/local/home/webadm/ttq/python_modules/lib/python3.6/site-packages/django/utils/decorators.py" in _wrapper
  45.         return bound_method(*args, **kwargs)

File "/local/home/webadm/ttq/python_modules/lib/python3.6/site-packages/django/views/decorators/debug.py" in sensitive_post_parameters_wrapper
  76.             return view(request, *args, **kwargs)

File "/local/home/webadm/ttq/python_modules/lib/python3.6/site-packages/rest_auth/views.py" in dispatch
  49.         return super(LoginView, self).dispatch(*args, **kwargs)

File "/local/home/webadm/ttq/python_modules/lib/python3.6/site-packages/rest_framework/views.py" in dispatch
  497.             response = self.handle_exception(exc)

File "/local/home/webadm/ttq/python_modules/lib/python3.6/site-packages/rest_framework/views.py" in handle_exception
  457.             self.raise_uncaught_exception(exc)

File "/local/home/webadm/ttq/python_modules/lib/python3.6/site-packages/rest_framework/views.py" in raise_uncaught_exception
  468.         raise exc

File "/local/home/webadm/ttq/python_modules/lib/python3.6/site-packages/rest_framework/views.py" in dispatch
  494.             response = handler(request, *args, **kwargs)

File "/local/home/webadm/ttq/python_modules/lib/python3.6/site-packages/rest_auth/views.py" in post
  105.         self.login()

File "/local/home/webadm/ttq/python_modules/lib/python3.6/site-packages/rest_auth/views.py" in login
  71.             self.process_login()

File "/local/home/webadm/ttq/python_modules/lib/python3.6/site-packages/rest_auth/views.py" in process_login
  52.         django_login(self.request, self.user)

File "/local/home/webadm/ttq/python_modules/lib/python3.6/site-packages/django/contrib/auth/__init__.py" in login
  108.         request.session.cycle_key()

File "/local/home/webadm/ttq/python_modules/lib/python3.6/site-packages/django/contrib/sessions/backends/base.py" in cycle_key
  297.         self.create()

File "/local/home/webadm/ttq/python_modules/lib/python3.6/site-packages/django/contrib/sessions/backends/db.py" in create
  55.                 self.save(must_create=True)

File "/local/home/webadm/ttq/python_modules/lib/python3.6/site-packages/django/contrib/sessions/backends/db.py" in save
  87.                 obj.save(force_insert=must_create, force_update=not must_create, using=using)

File "/local/home/webadm/ttq/python_modules/lib/python3.6/site-packages/django/db/models/base.py" in save
  741.                        force_update=force_update, update_fields=update_fields)

File "/local/home/webadm/ttq/python_modules/lib/python3.6/site-packages/django/db/models/base.py" in save_base
  779.                 force_update, using, update_fields,

File "/local/home/webadm/ttq/python_modules/lib/python3.6/site-packages/django/db/models/base.py" in _save_table
  870.             result = self._do_insert(cls._base_manager, using, fields, update_pk, raw)

File "/local/home/webadm/ttq/python_modules/lib/python3.6/site-packages/django/db/models/base.py" in _do_insert
  908.                                using=using, raw=raw)

File "/local/home/webadm/ttq/python_modules/lib/python3.6/site-packages/django/db/models/manager.py" in manager_method
  82.                 return getattr(self.get_queryset(), name)(*args, **kwargs)

File "/local/home/webadm/ttq/python_modules/lib/python3.6/site-packages/django/db/models/query.py" in _insert
  1186.         return query.get_compiler(using=using).execute_sql(return_id)

File "/local/home/webadm/ttq/python_modules/lib/python3.6/site-packages/django/db/models/sql/compiler.py" in execute_sql
  1375.                 cursor.execute(sql, params)

File "/local/home/webadm/ttq/python_modules/lib/python3.6/site-packages/django/db/backends/utils.py" in execute
  99.             return super().execute(sql, params)

File "/local/home/webadm/ttq/python_modules/lib/python3.6/site-packages/django/db/backends/utils.py" in execute
  67.         return self._execute_with_wrappers(sql, params, many=False, executor=self._execute)

File "/local/home/webadm/ttq/python_modules/lib/python3.6/site-packages/django/db/backends/utils.py" in _execute_with_wrappers
  76.         return executor(sql, params, many, context)

File "/local/home/webadm/ttq/python_modules/lib/python3.6/site-packages/django/db/backends/utils.py" in _execute
  84.                 return self.cursor.execute(sql, params)

File "/local/home/webadm/ttq/python_modules/lib/python3.6/site-packages/django/db/utils.py" in __exit__
  89.                 raise dj_exc_value.with_traceback(traceback) from exc_value

File "/local/home/webadm/ttq/python_modules/lib/python3.6/site-packages/django/db/backends/utils.py" in _execute
  84.                 return self.cursor.execute(sql, params)

File "/local/home/webadm/ttq/python_modules/lib/python3.6/site-packages/django/db/backends/sqlite3/base.py" in execute
  383.         return Database.Cursor.execute(self, query, params)

Exception Type: OperationalError at /rest-auth/login/
Exception Value: attempt to write a readonly database
Request information:
USER: AnonymousUser

GET: No GET data

POST:
username = 'till'
password = '********'

FILES: No FILES data

COOKIES: No cookie data

META:
CONTENT_LENGTH = '31'
CONTENT_TYPE = 'application/x-www-form-urlencoded'
DJANGO_SETTINGS_MODULE = 'lqserver.settings'
GATEWAY_INTERFACE = 'CGI/1.1'
HTTP_ACCEPT = '*/*'
HTTP_HOST = 'quiz.iks.cs.ovgu.de:8000'
HTTP_USER_AGENT = 'curl/7.58.0'
INVOCATION_ID = '2919e08a61924d069a23f04663817566'
JOURNAL_STREAM = '9:52979240'
LANG = 'en_US.UTF-8'
LOGNAME = 'webservd'
PATH = '/usr/sbin:/usr/bin:/sbin:/bin'
PATH_INFO = '/rest-auth/login/'
PORT = '8000'
PYTHONUSERBASE = '/local/home/webadm/ttq/python_modules'
QUERY_STRING = ''
REMOTE_ADDR = '88.69.96.32'
REMOTE_HOST = ''
REQUEST_METHOD = 'POST'
RUN_MAIN = 'true'
SCRIPT_NAME = ''
SERVER_NAME = 'quiz.iks.cs.ovgu.de'
SERVER_PORT = '8000'
SERVER_PROTOCOL = 'HTTP/1.1'
SERVER_SOFTWARE = 'WSGIServer/0.2'
TZ = 'UTC'
USER = 'webservd'
wsgi.errors = <_io.TextIOWrapper name='<stderr>' mode='w' encoding='UTF-8'>
wsgi.file_wrapper = ''
wsgi.input = <django.core.handlers.wsgi.LimitedStream object at 0x7fcca0528978>
wsgi.multiprocess = False
wsgi.multithread = True
wsgi.run_once = False
wsgi.url_scheme = 'http'
wsgi.version = '(1, 0)'

Settings:
Using settings module lqserver.settings
ABSOLUTE_URL_OVERRIDES = {}
ACCOUNT_AUTHENTICATION_METHOD = 'username'
ACCOUNT_EMAIL_REQUIRED = False
ACCOUNT_EMAIL_VERIFICATION = 'none'
ADMINS = []
ALLOWED_HOSTS = ['*']
APPEND_SLASH = True
AUTHENTICATION_BACKENDS = ['django.contrib.auth.backends.ModelBackend']
AUTH_PASSWORD_VALIDATORS = '********************'
AUTH_USER_MODEL = 'auth.User'
BASE_DIR = '/local/home/webadm/ttq/backend/lqserver'
CACHES = {'default': {'BACKEND': 'django.core.cache.backends.locmem.LocMemCache'}}
CACHE_MIDDLEWARE_ALIAS = 'default'
CACHE_MIDDLEWARE_KEY_PREFIX = '********************'
CACHE_MIDDLEWARE_SECONDS = 600
CORS_ORIGIN_ALLOW_ALL = True
CSRF_COOKIE_AGE = 31449600
CSRF_COOKIE_DOMAIN = None
CSRF_COOKIE_HTTPONLY = False
CSRF_COOKIE_NAME = 'csrftoken'
CSRF_COOKIE_PATH = '/'
CSRF_COOKIE_SAMESITE = 'Lax'
CSRF_COOKIE_SECURE = False
CSRF_FAILURE_VIEW = 'django.views.csrf.csrf_failure'
CSRF_HEADER_NAME = 'HTTP_X_CSRFTOKEN'
CSRF_TRUSTED_ORIGINS = []
CSRF_USE_SESSIONS = False
DATABASES = {'default': {'ENGINE': 'django.db.backends.sqlite3', 'NAME': '/local/home/webadm/ttq/backend/lqserver/db.sqlite3', 'ATOMIC_REQUESTS': False, 'AUTOCOMMIT': True, 'CONN_MAX_AGE': 0, 'OPTIONS': {}, 'TIME_ZONE': None, 'USER': '', 'PASSWORD': '********************', 'HOST': '', 'PORT': '', 'TEST': {'CHARSET': None, 'COLLATION': None, 'NAME': None, 'MIRROR': None}}}
DATABASE_ROUTERS = []
DATA_UPLOAD_MAX_MEMORY_SIZE = 2621440
DATA_UPLOAD_MAX_NUMBER_FIELDS = 10240
DATETIME_FORMAT = 'N j, Y, P'
DATETIME_INPUT_FORMATS = ['%Y-%m-%d %H:%M:%S', '%Y-%m-%d %H:%M:%S.%f', '%Y-%m-%d %H:%M', '%Y-%m-%d', '%m/%d/%Y %H:%M:%S', '%m/%d/%Y %H:%M:%S.%f', '%m/%d/%Y %H:%M', '%m/%d/%Y', '%m/%d/%y %H:%M:%S', '%m/%d/%y %H:%M:%S.%f', '%m/%d/%y %H:%M', '%m/%d/%y']
DATE_FORMAT = 'N j, Y'
DATE_INPUT_FORMATS = ['%Y-%m-%d', '%m/%d/%Y', '%m/%d/%y', '%b %d %Y', '%b %d, %Y', '%d %b %Y', '%d %b, %Y', '%B %d %Y', '%B %d, %Y', '%d %B %Y', '%d %B, %Y']
DEBUG = True
DEBUG_PROPAGATE_EXCEPTIONS = False
DECIMAL_SEPARATOR = '.'
DEFAULT_CHARSET = 'utf-8'
DEFAULT_CONTENT_TYPE = 'text/html'
DEFAULT_EXCEPTION_REPORTER_FILTER = 'django.views.debug.SafeExceptionReporterFilter'
DEFAULT_FILE_STORAGE = 'django.core.files.storage.FileSystemStorage'
DEFAULT_FROM_EMAIL = 'webmaster@localhost'
DEFAULT_INDEX_TABLESPACE = ''
DEFAULT_TABLESPACE = ''
DISALLOWED_USER_AGENTS = []
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'localhost'
EMAIL_HOST_PASSWORD = '********************'
EMAIL_HOST_USER = ''
EMAIL_PORT = 25
EMAIL_SSL_CERTFILE = None
EMAIL_SSL_KEYFILE = '********************'
EMAIL_SUBJECT_PREFIX = '[Django] '
EMAIL_TIMEOUT = None
EMAIL_USE_LOCALTIME = False
EMAIL_USE_SSL = False
EMAIL_USE_TLS = False
FILE_CHARSET = 'utf-8'
FILE_UPLOAD_DIRECTORY_PERMISSIONS = None
FILE_UPLOAD_HANDLERS = ['django.core.files.uploadhandler.MemoryFileUploadHandler', 'django.core.files.uploadhandler.TemporaryFileUploadHandler']
FILE_UPLOAD_MAX_MEMORY_SIZE = 2621440
FILE_UPLOAD_PERMISSIONS = None
FILE_UPLOAD_TEMP_DIR = None
FIRST_DAY_OF_WEEK = 0
FIXTURE_DIRS = []
FORCE_SCRIPT_NAME = None
FORMAT_MODULE_PATH = None
FORM_RENDERER = 'django.forms.renderers.DjangoTemplates'
IGNORABLE_404_URLS = []
INSTALLED_APPS = ['django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'rest_framework', 'rest_framework.authtoken', 'rest_auth', 'django.contrib.sites', 'allauth', 'allauth.account', 'allauth.socialaccount', 'rest_auth.registration', 'QuizBoard', 'nested_admin']
INTERNAL_IPS = []
LANGUAGES = [('af', 'Afrikaans'), ('ar', 'Arabic'), ('ast', 'Asturian'), ('az', 'Azerbaijani'), ('bg', 'Bulgarian'), ('be', 'Belarusian'), ('bn', 'Bengali'), ('br', 'Breton'), ('bs', 'Bosnian'), ('ca', 'Catalan'), ('cs', 'Czech'), ('cy', 'Welsh'), ('da', 'Danish'), ('de', 'German'), ('dsb', 'Lower Sorbian'), ('el', 'Greek'), ('en', 'English'), ('en-au', 'Australian English'), ('en-gb', 'British English'), ('eo', 'Esperanto'), ('es', 'Spanish'), ('es-ar', 'Argentinian Spanish'), ('es-co', 'Colombian Spanish'), ('es-mx', 'Mexican Spanish'), ('es-ni', 'Nicaraguan Spanish'), ('es-ve', 'Venezuelan Spanish'), ('et', 'Estonian'), ('eu', 'Basque'), ('fa', 'Persian'), ('fi', 'Finnish'), ('fr', 'French'), ('fy', 'Frisian'), ('ga', 'Irish'), ('gd', 'Scottish Gaelic'), ('gl', 'Galician'), ('he', 'Hebrew'), ('hi', 'Hindi'), ('hr', 'Croatian'), ('hsb', 'Upper Sorbian'), ('hu', 'Hungarian'), ('hy', 'Armenian'), ('ia', 'Interlingua'), ('id', 'Indonesian'), ('io', 'Ido'), ('is', 'Icelandic'), ('it', 'Italian'), ('ja', 'Japanese'), ('ka', 'Georgian'), ('kab', 'Kabyle'), ('kk', 'Kazakh'), ('km', 'Khmer'), ('kn', 'Kannada'), ('ko', 'Korean'), ('lb', 'Luxembourgish'), ('lt', 'Lithuanian'), ('lv', 'Latvian'), ('mk', 'Macedonian'), ('ml', 'Malayalam'), ('mn', 'Mongolian'), ('mr', 'Marathi'), ('my', 'Burmese'), ('nb', 'Norwegian Bokmål'), ('ne', 'Nepali'), ('nl', 'Dutch'), ('nn', 'Norwegian Nynorsk'), ('os', 'Ossetic'), ('pa', 'Punjabi'), ('pl', 'Polish'), ('pt', 'Portuguese'), ('pt-br', 'Brazilian Portuguese'), ('ro', 'Romanian'), ('ru', 'Russian'), ('sk', 'Slovak'), ('sl', 'Slovenian'), ('sq', 'Albanian'), ('sr', 'Serbian'), ('sr-latn', 'Serbian Latin'), ('sv', 'Swedish'), ('sw', 'Swahili'), ('ta', 'Tamil'), ('te', 'Telugu'), ('th', 'Thai'), ('tr', 'Turkish'), ('tt', 'Tatar'), ('udm', 'Udmurt'), ('uk', 'Ukrainian'), ('ur', 'Urdu'), ('vi', 'Vietnamese'), ('zh-hans', 'Simplified Chinese'), ('zh-hant', 'Traditional Chinese')]
LANGUAGES_BIDI = ['he', 'ar', 'fa', 'ur']
LANGUAGE_CODE = 'en-us'
LANGUAGE_COOKIE_AGE = None
LANGUAGE_COOKIE_DOMAIN = None
LANGUAGE_COOKIE_NAME = 'django_language'
LANGUAGE_COOKIE_PATH = '/'
LOCALE_PATHS = []
LOGGING = {}
LOGGING_CONFIG = 'logging.config.dictConfig'
LOGIN_REDIRECT_URL = '/accounts/profile/'
LOGIN_URL = '/accounts/login/'
LOGOUT_REDIRECT_URL = None
MANAGERS = []
MEDIA_ROOT = ''
MEDIA_URL = ''
MESSAGE_STORAGE = 'django.contrib.messages.storage.fallback.FallbackStorage'
MIDDLEWARE = ['corsheaders.middleware.CorsMiddleware', 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware']
MIGRATION_MODULES = {}
MONTH_DAY_FORMAT = 'F j'
NUMBER_GROUPING = 0
PASSWORD_HASHERS = '********************'
PASSWORD_RESET_TIMEOUT_DAYS = '********************'
PREPEND_WWW = False
ROOT_URLCONF = 'lqserver.urls'
SECRET_KEY = '********************'
SECURE_BROWSER_XSS_FILTER = False
SECURE_CONTENT_TYPE_NOSNIFF = False
SECURE_HSTS_INCLUDE_SUBDOMAINS = False
SECURE_HSTS_PRELOAD = False
SECURE_HSTS_SECONDS = 0
SECURE_PROXY_SSL_HEADER = None
SECURE_REDIRECT_EXEMPT = []
SECURE_SSL_HOST = None
SECURE_SSL_REDIRECT = False
SERVER_EMAIL = 'root@localhost'
SESSION_CACHE_ALIAS = 'default'
SESSION_COOKIE_AGE = 1209600
SESSION_COOKIE_DOMAIN = None
SESSION_COOKIE_HTTPONLY = True
SESSION_COOKIE_NAME = 'sessionid'
SESSION_COOKIE_PATH = '/'
SESSION_COOKIE_SAMESITE = 'Lax'
SESSION_COOKIE_SECURE = False
SESSION_ENGINE = 'django.contrib.sessions.backends.db'
SESSION_EXPIRE_AT_BROWSER_CLOSE = False
SESSION_FILE_PATH = None
SESSION_SAVE_EVERY_REQUEST = False
SESSION_SERIALIZER = 'django.contrib.sessions.serializers.JSONSerializer'
SETTINGS_MODULE = 'lqserver.settings'
SHORT_DATETIME_FORMAT = 'm/d/Y P'
SHORT_DATE_FORMAT = 'm/d/Y'
SIGNING_BACKEND = 'django.core.signing.TimestampSigner'
SILENCED_SYSTEM_CHECKS = []
SITE_ID = 1
STATICFILES_DIRS = []
STATICFILES_FINDERS = ['django.contrib.staticfiles.finders.FileSystemFinder', 'django.contrib.staticfiles.finders.AppDirectoriesFinder']
STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.StaticFilesStorage'
STATIC_ROOT = None
STATIC_URL = '/static/'
TEMPLATES = [{'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [], 'APP_DIRS': True, 'OPTIONS': {'context_processors': ['django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages']}}]
TEST_NON_SERIALIZED_APPS = []
TEST_RUNNER = 'django.test.runner.DiscoverRunner'
THOUSAND_SEPARATOR = ','
TIME_FORMAT = 'P'
TIME_INPUT_FORMATS = ['%H:%M:%S', '%H:%M:%S.%f', '%H:%M']
TIME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = True
USE_THOUSAND_SEPARATOR = False
USE_TZ = True
USE_X_FORWARDED_HOST = False
USE_X_FORWARDED_PORT = False
WSGI_APPLICATION = 'lqserver.wsgi.application'
X_FRAME_OPTIONS = 'SAMEORIGIN'
YEAR_MONTH_FORMAT = 'F Y'

You're seeing this error because you have DEBUG = True in your
Django settings file. Change that to False, and Django will
display a standard page generated by the handler for this status code.
jelmd commented 4 years ago

If in trouble, looking at ~/etc/quiz-update.sh may help.

ISo e.g. if you update python_modules, make sure all subdirs in ${PYTHONUSERBASE}/ are searchable (x) by the world, whereby in our case searchable by the group is sufficient as well because the user webadm and executing daemon webservd have the same group (i.e. webservd).

Similar, if the service wants to write somewhere, it needs write permission. Unfortunately I can't find any hint in the output above, what it wants to write (hint: proper exception handling). backend/lqserver/db.sqlite3 is group writable ( =8-( ) and thus might not be the problem here.

Anyway, as pointed out several times, there should be a dedicated directory, where the running service is able to persist its data, no matter in which group it is running (debian nerds would probably make such a dir readable by the service, only). And this directory should be a runtime parameter! Because some day the app might be run as an apache httpd "plugin", the probably easiest way to pass it is to use an environment variable ...

tillmo commented 4 years ago

sure there should be a configurable data directory, but this is the topic of #25. If I give a+w permissions to db.sqlite3, it works. Hence it is very clear that db.sqlite3 is the problem. Also, a manually started python server does not exhibit the problem - but the user is then webadm. Could you please try to manually start the server as webservd?

serajushsalekin commented 4 years ago

I think you just forgot to migrate.

tillmo commented 4 years ago

I think you just forgot to migrate.

No:

python3 manage.py migrate
Operations to perform:
  Apply all migrations: QuizBoard, account, admin, auth, authtoken, contenttypes, sessions, sites, socialaccount
Running migrations:
  No migrations to apply.
tillmo commented 4 years ago

It seems that sqlite3 is not installed on the server. @jelmd, please install it.

apt-cache policy sqlite3
sqlite3:
  Installed: (none)
  Candidate: 3.22.0-1ubuntu0.3
  Version table:
     3.22.0-1ubuntu0.3 500
        500 http://de.archive.ubuntu.com/ubuntu bionic-updates/main amd64 Packages
        500 http://security.ubuntu.com/ubuntu bionic-security/main amd64 Packages
     3.22.0-1 500
        500 http://de.archive.ubuntu.com/ubuntu bionic/main amd64 Packages
webadm.quiz ~/ttq/backend/lqserver > sqlite3
sqlite3: Command not found.
webadm.quiz ~/ttq/backend/lqserver > /usr/bin/sqlite3
/usr/bin/sqlite3: Command not found.
jelmd commented 4 years ago

dpkg -l |grep sqlit

ii  libaprutil1-dbd-sqlite3:amd64     1.6.1-2                             amd64        Apache Portable Runtime Utility Library - SQLite3 Driver
ii  libsqlite3-0:amd64                3.22.0-1ubuntu0.3                   amd64        SQLite 3 shared library

Python doe snot need the frontend, just the libs.

jelmd commented 4 years ago

The service is running as webservd. Use ps to check. If you chmod a+w db.sqlite3 and it works, it is obviously an app bug. I guess, someone reinvented the wheel and does not open the file RW but uses some stat results to find out, whether it is readable, and does this in a wrong way ...

jelmd commented 4 years ago

s/readable/writable/

tillmo commented 4 years ago

The service is running as webservd. Use ps to check. If you chmod a+w db.sqlite3 and it works, it is obviously an app bug. I guess, someone reinvented the wheel and does not open the file RW but uses some stat results to find out, whether it is readable, and does this in a wrong way ...

But if this were true, then why does it work when started manually? Could you please try to start it manually as webservd?

tillmo commented 4 years ago

by the way, the app can successfully read from the database. Only if the database needs to be modified, the error occurs.

jelmd commented 4 years ago

Can you check now? The db file has now 0664 mode. Also can you insert a short check? When trying the op which fails, create a new file right before and after in /tmp/ (/tmp/ is writable for all unless the file already exists and belongs to someone else) . So one can see, as what the service is currently running by ls -al /tmp/$file.

tillmo commented 4 years ago

Currently, it does not even work with 666 permissions. When writing a temp file immediately before the operation, I get

-rw-------  1 webservd webservd    0 Apr  4 18:09 tmp.RNntNg70Z7
-rw-------  1 webservd webservd    0 Apr  4 18:09 tmp.prBSJYNIKP
-rw-------  1 webservd webservd    0 Apr  4 18:09 tmp.cWEWMYnpge
-rw-------  1 webservd webservd    0 Apr  4 18:09 tmp.3BST55GEWx
-rw-------  1 webservd webservd    0 Apr  4 18:09 tmp.J2WJl458ww
-rw-------  1 webservd webservd    0 Apr  4 18:09 tmp.xOGlTmGWmO
-rw-------  1 webservd webservd    0 Apr  4 18:09 tmp.ZxqS9QB5hl
tillmo commented 4 years ago

solved it! The folder containing the database also needs 664 permissions.

tillmo commented 4 years ago

@jelmd please integrate this into ~/etc/quiz-update.sh

jelmd commented 4 years ago

Change and commit via git? IIRC git preserves permissions?

tillmo commented 4 years ago

Change and commit via git? IIRC git preserves permissions?

I think git can handle this if the repo is initialised with --share. But we did not do this. Afterwards, you can still locally change the .git/config, but I do not know how to propagate this to the github repo.

jelmd commented 4 years ago

Just checked: Once upon a time, git saved/restored file permissions as well. Now it always applies the user's umask and thus the group writable usually gets masked out. --chmod=[+-]x seems to be the only "hook" to add a hint wrt. checkout permissions.

--share makes sense for local repositories, only - e.g. if a group wants to have a common directory with the repo inside ...

etc/quiz-update.sh changed.