Support readonly datastores for matrix-media-repo

The configuration template only rendered a datastore when its for_kinds
list was non-empty, even though the inline documentation (matching
upstream's) describes forKinds: [] as the way to make a datastore
readonly. That made the documented migration scenario impossible: moving
media between the file and s3 datastores while keeping the old one
readable.

Introduce matrix_media_repo_datastore_file_enabled and
matrix_media_repo_datastore_s3_enabled, which default to the previous
kinds-based behavior. A readonly datastore is now expressed by enabling
the datastore explicitly while assigning it no kinds.

Fixes #4303

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Slavi Pantaleev
2026-07-13 21:17:09 +03:00
parent 6b4b7647e4
commit 94d8e28306
3 changed files with 20 additions and 4 deletions
@@ -413,6 +413,14 @@ matrix_media_repo_shared_secret_auth_token: "PutSomeRandomSecureValueHere"
# thumbnails and other misc data is also stored in these places. The media repo, when looking # thumbnails and other misc data is also stored in these places. The media repo, when looking
# for a datastore to use, will always use the smallest datastore first. # for a datastore to use, will always use the smallest datastore first.
# Controls whether the file datastore is defined in the configuration at all.
# A datastore can be defined but disabled for uploads (making it readonly) by keeping this enabled
# while setting `matrix_media_repo_datastore_file_for_kinds: []`. This is useful when migrating
# media to another datastore, as previously stored media remains readable.
# By default, the datastore is defined whenever some kinds are assigned to it, matching the
# previous behavior of this role.
matrix_media_repo_datastore_file_enabled: "{{ (matrix_media_repo_datastore_file_for_kinds | length) > 0 }}"
# ID for the file datastore. Any unique alphanumeric string (e.g. generated via `pwgen -s 64 1`). # ID for the file datastore. Any unique alphanumeric string (e.g. generated via `pwgen -s 64 1`).
# This value CANNOT be changed after media has been stored — matrix-media-repo ties media to this ID. # This value CANNOT be changed after media has been stored — matrix-media-repo ties media to this ID.
matrix_media_repo_datastore_file_id: "" matrix_media_repo_datastore_file_id: ""
@@ -434,6 +442,14 @@ matrix_media_repo_datastore_file_for_kinds: ["thumbnails", "remote_media", "loca
# Path to datastore, relative to matrix-media-repo directory root # Path to datastore, relative to matrix-media-repo directory root
matrix_media_repo_datastore_opts_path: "/data/media" matrix_media_repo_datastore_opts_path: "/data/media"
# Controls whether the S3 datastore is defined in the configuration at all.
# A datastore can be defined but disabled for uploads (making it readonly) by keeping this enabled
# while setting `matrix_media_repo_datastore_s3_for_kinds: []`. This is useful when migrating
# media to another datastore, as previously stored media remains readable.
# By default, the datastore is defined whenever some kinds are assigned to it, matching the
# previous behavior of this role.
matrix_media_repo_datastore_s3_enabled: "{{ (matrix_media_repo_datastore_s3_for_kinds | length) > 0 }}"
# ID for the S3 datastore. Any unique alphanumeric string (e.g. generated via `pwgen -s 64 1`). # ID for the S3 datastore. Any unique alphanumeric string (e.g. generated via `pwgen -s 64 1`).
# This value CANNOT be changed after media has been stored — matrix-media-repo ties media to this ID. # This value CANNOT be changed after media has been stored — matrix-media-repo ties media to this ID.
matrix_media_repo_datastore_s3_id: "" matrix_media_repo_datastore_s3_id: ""
@@ -50,5 +50,5 @@
- {'name': 'matrix_media_repo_database_hostname', when: true} - {'name': 'matrix_media_repo_database_hostname', when: true}
- {'name': 'matrix_media_repo_container_labels_traefik_internal_media_entrypoints', when: "{{ matrix_media_repo_container_labels_traefik_internal_media_enabled }}"} - {'name': 'matrix_media_repo_container_labels_traefik_internal_media_entrypoints', when: "{{ matrix_media_repo_container_labels_traefik_internal_media_enabled }}"}
- {'name': 'matrix_media_repo_container_labels_traefik_internal_matrix_client_media_entrypoints', when: "{{ matrix_media_repo_container_labels_traefik_internal_matrix_client_media_enabled }}"} - {'name': 'matrix_media_repo_container_labels_traefik_internal_matrix_client_media_entrypoints', when: "{{ matrix_media_repo_container_labels_traefik_internal_matrix_client_media_enabled }}"}
- {'name': 'matrix_media_repo_datastore_file_id', when: "{{ (matrix_media_repo_datastore_file_for_kinds | length) > 0 }}"} - {'name': 'matrix_media_repo_datastore_file_id', when: "{{ matrix_media_repo_datastore_file_enabled }}"}
- {'name': 'matrix_media_repo_datastore_s3_id', when: "{{ (matrix_media_repo_datastore_s3_for_kinds | length) > 0 }}"} - {'name': 'matrix_media_repo_datastore_s3_id', when: "{{ matrix_media_repo_datastore_s3_enabled }}"}
@@ -198,7 +198,7 @@ sharedSecretAuth:
# thumbnails and other misc data is also stored in these places. The media repo, when looking # thumbnails and other misc data is also stored in these places. The media repo, when looking
# for a datastore to use, will always use the smallest datastore first. # for a datastore to use, will always use the smallest datastore first.
datastores: datastores:
{% if (matrix_media_repo_datastore_file_for_kinds | length) > 0 %} {% if matrix_media_repo_datastore_file_enabled %}
- type: file - type: file
# ID for this datastore (cannot change). Alphanumeric recommended. # ID for this datastore (cannot change). Alphanumeric recommended.
id: {{ matrix_media_repo_datastore_file_id | to_json }} id: {{ matrix_media_repo_datastore_file_id | to_json }}
@@ -218,7 +218,7 @@ datastores:
opts: opts:
path: {{ matrix_media_repo_datastore_opts_path | to_json }} path: {{ matrix_media_repo_datastore_opts_path | to_json }}
{% endif %} {% endif %}
{% if (matrix_media_repo_datastore_s3_for_kinds | length) > 0 %} {% if matrix_media_repo_datastore_s3_enabled %}
- type: s3 - type: s3
# ID for this datastore (cannot change). Alphanumeric recommended. # ID for this datastore (cannot change). Alphanumeric recommended.
id: {{ matrix_media_repo_datastore_s3_id | to_json }} id: {{ matrix_media_repo_datastore_s3_id | to_json }}