-
Notifications
You must be signed in to change notification settings - Fork 31
Description
Package version (if known): ghcr.io/inveniosoftware/demo-inveniordm/demo-inveniordm:12.0.10
Helm chart version: 0.8.1
Describe the bug
Not really sure if this is the proper repository for raising this issue, but I used this Helm chart for installation and configuration.
I am trying to setup a test/PoC instance of Invenio (that's why I'm currently using the demo-inveniordm image). So far, I managed to get all the services up and running and connect to S3 storage and Keycloak IdM, by mounting a customized invenio.cfg file. I can login and look around but there are several actions that do not work, but instead just throw internal server errors, such as creating a new record or opening the configuration page of a community.
Here is an exemplary stack trace from the invenio-web service's logs:
[2025-08-01 14:55:46,942] ERROR in app: Exception on /uploads/new [GET]
Traceback (most recent call last):
File "/usr/local/lib/python3.9/site-packages/flask/app.py", line 2529, in wsgi_app
response = self.full_dispatch_request()
File "/usr/local/lib/python3.9/site-packages/flask/app.py", line 1825, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/usr/local/lib/python3.9/site-packages/flask/app.py", line 1823, in full_dispatch_request
rv = self.dispatch_request()
File "/usr/local/lib/python3.9/site-packages/flask/app.py", line 1799, in dispatch_request
return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args)
File "/usr/local/lib/python3.9/site-packages/flask_login/utils.py", line 290, in decorated_view
return current_app.ensure_sync(func)(*args, **kwargs)
File "/usr/local/lib/python3.9/site-packages/invenio_app_rdm/records_ui/views/decorators.py", line 363, in view
return f(**kwargs)
File "/usr/local/lib/python3.9/site-packages/invenio_app_rdm/records_ui/views/deposits.py", line 394, in deposit_create
forms_config=get_form_config(
File "/usr/local/lib/python3.9/site-packages/invenio_app_rdm/records_ui/views/deposits.py", line 317, in get_form_config
custom_fields = load_custom_fields()
File "/usr/local/lib/python3.9/site-packages/invenio_app_rdm/records_ui/views/deposits.py", line 297, in load_custom_fields
field["props"]["options"] = field_instance.options(g.identity)
File "/usr/local/lib/python3.9/site-packages/invenio_vocabularies/services/custom_fields/vocabulary.py", line 86, in options
vocabs = current_service.read_all(
File "/usr/local/lib/python3.9/site-packages/invenio_vocabularies/services/service.py", line 174, in read_all
vocabulary_type = VocabularyType.query.filter_by(id=type).one()
File "/usr/local/lib64/python3.9/site-packages/sqlalchemy/orm/query.py", line 2870, in one
return self._iter().one()
File "/usr/local/lib64/python3.9/site-packages/sqlalchemy/engine/result.py", line 1522, in one
return self._only_one_row(
File "/usr/local/lib64/python3.9/site-packages/sqlalchemy/engine/result.py", line 562, in _only_one_row
raise exc.NoResultFound(
sqlalchemy.exc.NoResultFound: No row was found when one was required
Looks like an issue with the database, but it has been connected to and initialized without any problems.
Steps to Reproduce
Installed with the following Helm values (we use umbrella charts to deploy stuff, the helm-invenio chart values are located under key invenio):
invenio:
ingress:
enabled: true
invenio:
hostname: invenio.example.org
existingSecret: invenio-secret-salts
web:
# inject custom CA certificates (required for S3)
# this effectively mounts a file to /etc/ssl/certs/ca-certificates.crt from a ConfigMap
podAnnotations:
trust-manager.example.org/inject-ca-bundle: "true"
# add S3 parameters and credentials (from OBC) as ENVs
extraEnvFrom:
- configMapRef:
name: invenio-data
- secretRef:
name: invenio-data
extraEnvVars:
# used in invenio.cfg
- name: OIDC_CLIENT_SECRET
valueFrom:
secretKeyRef:
name: invenio-oidc
key: clientSecret
# mount custom invenio.cfg
extraVolumes:
- name: custom-config
configMap:
name: invenio-cfg
extraVolumeMounts:
- name: custom-config
subPath: invenio.cfg
mountPath: /opt/invenio/var/instance/invenio.cfg
readOnly: true
# We use S3 instead of shared PVC
persistence:
enabled: false
redis:
enabled: true
auth:
existingSecret: invenio-redis
existingSecretPasswordKey: password
rabbitmq:
enabled: true
auth:
existingPasswordSecret: invenio-rabbitmq
existingSecretPasswordKey: password
existingErlangSecret: invenio-rabbitmq
existingSecretErlangKey: erlang-cookie
# I have no idea what this is for
flower:
enabled: true
existing_secret: true
secret_name: inveio-flower
host: ""
opensearch:
sysctlImage:
enabled: false # we have the proper kernel params set on node level by default
postgresql:
enabled: false
postgresqlExternal:
hostname: invenio-postgres-rw
port: 5432
username: app
database: app
existingSecret: invenio-postgres-app
existingSecretPasswordKey: password
# just a cloudnative-pg cluster with pretty default settings
postgres:
instances: 1
imageName: ghcr.io/cloudnative-pg/postgresql:17.5
storage:
size: 1GiAfter that, initialized the instance by manually running the following commands within one of the invenio-web containers (took them from the chart's init job template and adapted as required):
invenio db init
invenio db create
invenio index init
invenio index queue init purge
invenio files location s3-default "s3://$BUCKET_NAME" --default
invenio roles create admin
invenio access allow superuser-access role admin
invenio rdm-records demoThen, logged in as normal user via Keycloak
Expected behavior
Invenio should be working without problems
Additional context
The custom invenio.cfg file (most of it is just copied from the demo-invenio image, adaptations are mostly at the bottom with authentication and S3):
import os
# Invenio-App
# ===========
# See https://invenio-app.readthedocs.io/en/latest/configuration.html
APP_DEFAULT_SECURE_HEADERS = {
'content_security_policy': {
'default-src': [
"'self'",
'data:', # for fonts
"'unsafe-inline'", # for inline scripts and styles
"blob:", # for pdf preview
# Add your own policies here (e.g. analytics)
],
},
'content_security_policy_report_only': False,
'content_security_policy_report_uri': None,
'force_file_save': False,
'force_https': True,
'force_https_permanent': False,
'frame_options': 'sameorigin',
'frame_options_allow_from': None,
'session_cookie_http_only': True,
'session_cookie_secure': True,
'strict_transport_security': True,
'strict_transport_security_include_subdomains': True,
'strict_transport_security_max_age': 31556926, # One year in seconds
'strict_transport_security_preload': False,
}
# Flask-Babel
# ===========
# See https://pythonhosted.org/Flask-Babel/#configuration
# Default locale (language)
BABEL_DEFAULT_LOCALE = 'en'
# Default time zone
BABEL_DEFAULT_TIMEZONE = 'Europe/Zurich'
# Invenio-I18N
# ============
# See https://invenio-i18n.readthedocs.io/en/latest/configuration.html
# Other supported languages (do not include BABEL_DEFAULT_LOCALE in list).
# I18N_LANGUAGES = [
# ('fr', _('French'))
# ]
# Invenio-Theme
# =============
# See https://invenio-theme.readthedocs.io/en/latest/configuration.html
# Frontpage title
THEME_FRONTPAGE_TITLE = "InvenioRDM test instance"
# Frontpage template
THEME_FRONTPAGE_TEMPLATE = 'demo_inveniordm/demo_frontpage.html'
# Header logo
THEME_LOGO="images/invenio-rdm.svg"
# Site tracking code template for matomo analytics
# Enable the below on the dedicated environment
# THEME_TRACKINGCODE_TEMPLATE = "demo_inveniordm/trackingcode-prod.html"
# Invenio-App-RDM
# ===============
# See https://invenio-app-rdm.readthedocs.io/en/latest/configuration.html
# Instance's theme entrypoint file. Path relative to the ``assets/`` folder.
INSTANCE_THEME_FILE = './less/theme.less'
# For invenio-vocabularies
JSONSCHEMAS_HOST = "localhost"
# admin user password
RDM_RECORDS_USER_FIXTURE_PASSWORDS = {
'[email protected]': '123456'
}
# Invenio-Records-Resources
# =========================
# See https://github.com/inveniosoftware/invenio-records-resources/blob/master/invenio_records_resources/config.py
SITE_UI_URL = "https://127.0.0.1"
SITE_API_URL = "https://127.0.0.1/api"
# Invenio-RDM-Records
# ===================
# See https://github.com/inveniosoftware/invenio-rdm-records/blob/master/invenio_rdm_records/config.py
DATACITE_ENABLED = True
DATACITE_USERNAME = ""
DATACITE_PASSWORD = ""
DATACITE_PREFIX = "10.1234"
DATACITE_TEST_MODE = True
# Custom Fields
# =============
from invenio_i18n import lazy_gettext as _
from invenio_records_resources.services.custom_fields import (
BaseCF,
BooleanCF,
DoubleCF,
EDTFDateStringCF,
IntegerCF,
ISODateStringCF,
KeywordCF,
TextCF,
)
from invenio_records_resources.services.records.facets import CFTermsFacet
from invenio_rdm_records.config import RDM_FACETS, RDM_SEARCH
from invenio_rdm_records.services.schemas.metadata import _valid_url
from invenio_vocabularies.services.custom_fields import VocabularyCF
from invenio_vocabularies.services.facets import VocabularyLabels
from marshmallow_utils.fields.edtfdatestring import EDTFValidator
from marshmallow import ValidationError
#
# Namespaces
#
RDM_NAMESPACES = {
"rdm": "https://inveniordm.docs.cern.ch"
}
#
# Records custom fields
#
def _validate_release_year(value):
"""Accept only edtf year values i.e YYYY."""
_validate = EDTFValidator()
_value = _validate(value)
if not _value.isdigit():
raise ValidationError("Please provide a valid year.", field_name="release_year")
RDM_CUSTOM_FIELDS = [
TextCF(
name="rdm:repository_url",
field_args={"validate": _valid_url(_("Not a valid URL."))},
),
VocabularyCF(
name="rdm:development_status",
vocabulary_id="developmentstatus",
dump_options=True,
multiple=False,
),
VocabularyCF(
name="rdm:programming_languages",
vocabulary_id="programminglanguages",
dump_options=True,
multiple=True
),
EDTFDateStringCF(
name="rdm:release_year",
field_args={"validate": _validate_release_year}
),
ISODateStringCF(name="rdm:release_date"),
TextCF(name="rdm:release_notes"),
IntegerCF(name="rdm:release_number_of_lines"),
DoubleCF(name="rdm:release_test_percentage"),
BooleanCF(name="rdm:lts_release")
]
RDM_CUSTOM_FIELDS_UI = [
{
"section": _("Software"),
"fields": [
dict(
field="rdm:repository_url",
ui_widget="Input",
props=dict(
label="Repository URL",
placeholder="https://your.repository.url",
icon="linkify",
description="URL of the repository where the software is hosted.",
)
),
dict(
field="rdm:development_status",
ui_widget="Dropdown", # predefined widget
props=dict(
label="Development Status",
placeholder="Concept, WIP, Active...",
icon="group",
description="Find more at repostatus.org",
search=False,
multiple=False,
clearable=True
)
),
dict(
field="rdm:programming_languages",
ui_widget="AutocompleteDropdown", # predefined widget
props=dict(
label="Programming Languages",
placeholder="Type a programming language...",
icon="language",
description="List of programming fields used in this project.",
autocompleteFrom="/api/vocabularies/programminglanguages",
clearable=True,
multiple=True,
)
),
dict(
field="rdm:release_year",
ui_widget="Input",
props=dict(
label="Release Year",
placeholder="Release year (EDTF date of format YYYY).",
icon="calendar",
description="Format: DATE where DATE is YYYY.",
)
),
dict(
field="rdm:release_date",
ui_widget="Input",
props=dict(
label="Release Date",
placeholder="Release date in ISO format (YYYY-MM-DD).",
icon="calendar",
description="Format: YYYY-MM-DD.",
)
),
dict(
field="rdm:release_notes",
ui_widget="RichInput",
props=dict(
label="Release Notes",
placeholder="Added new feature X...",
icon="book",
description="Changes made in the release.",
)
),
dict(
field="rdm:release_number_of_lines",
ui_widget="NumberInput",
props=dict(
label="Release number of lines",
placeholder="Number of lines in code.",
icon="calculator",
description="Insert the integer number of code lines changed in this release.",
)
),
dict(
field="rdm:release_test_percentage",
ui_widget="NumberInput",
props=dict(
label="Release test coverage (%)",
placeholder="Release test coverage (e.g 95,75).",
icon="calculator",
description="Format: double number.",
)
),
dict(
field="rdm:lts_release",
ui_widget="BooleanCheckbox",
props=dict(
label="LTS release",
trueLabel="Yes",
falseLabel="No",
icon="tag",
description="Mark if this is a Long Term Support release (LTS).",
)
)
]
}
]
RDM_FACETS = {
**RDM_FACETS,
"development_status": {
"facet": CFTermsFacet(
field="rdm:development_status.id",
label=_("Development Status"),
value_labels=VocabularyLabels("developmentstatus"),
),
"ui": {
"field": CFTermsFacet.field("rdm:development_status"),
},
},
"programming_language": {
"facet": CFTermsFacet(
field="rdm:programming_languages.id",
label=_("Programming Languages"),
value_labels=VocabularyLabels("programminglanguages"),
),
"ui": {
"field": CFTermsFacet.field("rdm:programming_languages"),
},
},
}
RDM_SEARCH = {
**RDM_SEARCH,
"facets": RDM_SEARCH["facets"] + ["programming_language", "development_status"]
}
#
# Communities custom fields
#
COMMUNITIES_CUSTOM_FIELDS = [
TextCF(
name="rdm:external_url",
field_args={"validate": _valid_url(_("Not a valid URL."))},
),
TextCF(name="rdm:policy"),
]
COMMUNITIES_CUSTOM_FIELDS_UI = [
{
"section": _("Other details"),
"fields": [
dict(
field="rdm:external_url",
ui_widget="Input",
props=dict(
label="External URL",
placeholder="https://your.community.url",
icon="linkify",
description="External URL of the community...",
)
),
dict(
field="rdm:policy",
ui_widget="RichInput",
props=dict(
label="Policy",
placeholder="For a record to be accepted into this community it must...",
icon="pencil",
description="Conditions for a record to be accepted into the community",
)
),
]
}
]
# Authentication
# ==============
# Disable local authentication
ACCOUNTS_LOCAL_LOGIN_ENABLED = False
SECURITY_REGISTERABLE = False
SECURITY_RECOVERABLE = False
SECURITY_CHANGEABLE = False
USERPROFILES_READ_ONLY = True
# Redirect directly to auth server as there is only one auth method
from invenio_oauthclient.views.client import auto_redirect_login
ACCOUNTS_LOGIN_VIEW_FUNCTION = auto_redirect_login
OAUTHCLIENT_AUTO_REDIRECT_TO_EXTERNAL_LOGIN = True
from invenio_oauthclient.contrib.keycloak import KeycloakSettingsHelper
_keycloak_helper = KeycloakSettingsHelper(
title="SSO",
description="OIDC authentication via Keycloak",
base_url="https://auth.example.org/",
realm="example"
)
OAUTHCLIENT_KEYCLOAK_REALM_URL = _keycloak_helper.realm_url
OAUTHCLIENT_KEYCLOAK_USER_INFO_URL = _keycloak_helper.user_info_url
OAUTHCLIENT_KEYCLOAK_VERIFY_EXP = True
OAUTHCLIENT_KEYCLOAK_VERIFY_AUD = True
OAUTHCLIENT_KEYCLOAK_AUD = "invenio"
# without this variable, authentication fails
OAUTHCLIENT_KEYCLOAK_USER_INFO_FROM_ENDPOINT = False
OAUTHCLIENT_REMOTE_APPS = {
"keycloak": _keycloak_helper.remote_app
}
KEYCLOAK_APP_CREDENTIALS = {
"consumer_key": "invenio",
"consumer_secret": os.environ['OIDC_CLIENT_SECRET'],
}
# S3 Storage
# ==========
# ENVs added from the Ceph bucket secret/configmap
_scheme = "https" if os.environ['BUCKET_PORT'] == '443' else "http"
S3_ENDPOINT_URL = f"{_scheme}://{os.environ['BUCKET_HOST']}:{os.environ['BUCKET_PORT']}/"
print(f"Configured S3 endpoint {S3_ENDPOINT_URL}")
S3_ACCESS_KEY_ID = os.environ['AWS_ACCESS_KEY_ID']
S3_SECRET_ACCESS_KEY = os.environ['AWS_SECRET_ACCESS_KEY']
#
# Invenio-Search
#
SEARCH_INDEX_PREFIX = "demo-inveniordm-"