mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-06 02:54:26 +00:00
fix(web-app-bigbluebutton): run BBB v3.0.39 with the shared-notes server
The version-source update in #1146 moved the bigbluebutton/docker ref from v3.0.23 to v3.0.39. That tag changes three things the role did not handle, and it exposed a fourth defect in compose_file_args. 1. generate-compose renders etherpad and bbb-pads only behind USE_INSECURE_ETHERPAD and otherwise emits bbb-shared-notes-server with a `build:` block and no `image:` (upstream adds the image only after the tag, in 9a6a9a9a4c). compose_mods drops `build` only where an image is set, so the guard "Fail if any service still builds locally" stopped every BigBlueButton deploy (main run 39749899667, Nextcloud#11: `rc: 0`, `stdout: ' build:'`, bootstrap_compose_project.yml:35). meta/services.yml now pins alangecker/bbb-shared-notes-server:v3.0.39, compose_mods takes `pinned` (BBB_PINNED_SERVICES, every service the role config pins an image for) and drops their `build`, and the etherpad leftovers go (ep_redis_publisher patch, etherpad postgres entrypoint and initdb hook, etherpad database tasks, ETHERPAD_* env, etherpad_api_key secret). 2. The notes server connects to postgres once at start and exits with 2 when it is not up yet; upstream gives it no restart policy. The override sets the role's restart policy, so it retries until postgres accepts connections. 3. Greenlight moves from v3.8.0 to v3.9.0.1, which sets `config.hosts = URL_HOST`, and the template passes `URL_HOST: https://${DOMAIN}`. Rails compares hostnames, so every request was blocked (`Blocked hosts: bbb.talk.infinito.test`, 403). Greenlight documents URL_HOST as the bare hostname; the override sets it to the role domain. 4. compose_file_args decided whether a role ships a compose override by templating "{{ application_id | abs_role_path_by_application_id }}" through the templar. ansible-core 2.21 does not render an untrusted string, so the check saw the literal and always returned False: the CA override generation and the pull handler never read BBB's compose.override.yml. That was harmless while compose.yml alone was valid; with the notes-server image living in the override, `compose config` failed ("has neither an image nor a build context"). The check now resolves the role path for the application id it is given. BBB is the only role that ships an override, so no other role's file list changes. Existing installations drop the etherpad and bbb-pads containers on the next `compose up --remove-orphans`; the old `etherpad` database stays in PostgreSQL untouched. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
16f6350aba
commit
b83b361ea9
17 files changed
+61
-299
No files matched your search
@@ -30,6 +30,7 @@ from ansible.errors import AnsibleError
|
||||
from ansible.plugins.loader import lookup_loader
|
||||
from ansible.plugins.lookup import LookupBase
|
||||
|
||||
from plugins.filter.role_path_by_app_id import abs_role_path_by_application_id
|
||||
from utils.docker.paths_utils import get_docker_paths
|
||||
from utils.templating.jinja import render_strict
|
||||
|
||||
@@ -80,7 +81,7 @@ def _has_domain(domains: Any, application_id: str) -> bool:
|
||||
return _value_has_domain(domains)
|
||||
|
||||
|
||||
def _role_provides_override(*, application_id: str, templar: Any) -> bool:
|
||||
def _role_provides_override(*, application_id: str) -> bool:
|
||||
"""
|
||||
Mirror tasks/04_files.yml "with_first_found" logic:
|
||||
|
||||
@@ -89,22 +90,10 @@ def _role_provides_override(*, application_id: str, templar: Any) -> bool:
|
||||
|
||||
Only if one of these exists, we append "-f <compose.files.compose_override>".
|
||||
"""
|
||||
tpl = getattr(templar, "template", None)
|
||||
if not callable(tpl):
|
||||
raise AnsibleError(
|
||||
"compose_file_args: templar is required to resolve abs_role_path_by_application_id"
|
||||
)
|
||||
|
||||
role_base = _as_str(tpl("{{ application_id | abs_role_path_by_application_id }}"))
|
||||
if not role_base:
|
||||
raise AnsibleError(
|
||||
"compose_file_args: abs_role_path_by_application_id resolved to empty"
|
||||
)
|
||||
|
||||
c1 = str(Path(role_base) / "templates" / "compose.override.yml.j2")
|
||||
c2 = str(Path(role_base) / "files" / "compose.override.yml")
|
||||
|
||||
return Path(c1).is_file() or Path(c2).is_file()
|
||||
role_base = Path(abs_role_path_by_application_id(application_id))
|
||||
return (role_base / "templates" / "compose.override.yml.j2").is_file() or (
|
||||
role_base / "files" / "compose.override.yml"
|
||||
).is_file()
|
||||
|
||||
|
||||
class LookupModule(LookupBase):
|
||||
@@ -174,7 +163,7 @@ class LookupModule(LookupBase):
|
||||
|
||||
parts = [f"{flag} {base}"]
|
||||
|
||||
if _role_provides_override(application_id=application_id, templar=templar):
|
||||
if _role_provides_override(application_id=application_id):
|
||||
if not _as_str(override):
|
||||
raise AnsibleError(
|
||||
"compose_file_args: compose.files.compose_override is required "
|
||||
|
||||
@@ -48,8 +48,7 @@ flowchart LR
|
||||
svc_bbb_web["bbb-web"]
|
||||
svc_freeswitch["freeswitch"]
|
||||
svc_nginx["nginx"]
|
||||
svc_etherpad["etherpad"]
|
||||
svc_bbb_pads["bbb-pads"]
|
||||
svc_bbb_shared_notes_server["bbb-shared-notes-server"]
|
||||
svc_bbb_export_annotations["bbb-export-annotations"]
|
||||
svc_webrtc_sfu["webrtc-sfu"]
|
||||
svc_fsesl_akka["fsesl-akka"]
|
||||
@@ -91,7 +90,7 @@ Solid `1:1` edges are fixed relationships; dashed `0..1` edges are conditional (
|
||||
- 🧱 Automatic `.env` templating and domain/NGINX integration
|
||||
- 🛠 Volume patching and Docker Compose customization
|
||||
- 📬 SMTP integration and Greenlight admin creation
|
||||
- 🧪 Workarounds for known Docker Compose or Etherpad issues
|
||||
- 🧪 Workarounds for known Docker Compose issues
|
||||
|
||||
## Quick Setup
|
||||
|
||||
|
||||
@@ -1,148 +0,0 @@
|
||||
// nocheck: mirrored-unit-test - requires ep_etherpad-lite's Settings module at load
|
||||
// time and reads settings.ep_redis_publisher, so it cannot be imported outside an
|
||||
// Etherpad install
|
||||
const redis = require('redis');
|
||||
const settings = require('ep_etherpad-lite/node/utils/Settings');
|
||||
const logger = { error: (...args) => console.error('[ep_redis_publisher]', ...args) };
|
||||
|
||||
const CHANNEL = settings.ep_redis_publisher.channel || 'from-etherpad-redis-channel';
|
||||
|
||||
const sanitizeMessageBody = (body) => {
|
||||
let response = { ...body };
|
||||
|
||||
if (response.pad && response.pad._db) {
|
||||
response = {
|
||||
...response,
|
||||
pad: {
|
||||
...response.pad,
|
||||
_db: undefined,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
if (body?.pad?.id) { body.pad.padId = body.pad.id; }
|
||||
|
||||
return response;
|
||||
};
|
||||
|
||||
const getCircularReplacer = () => {
|
||||
const seen = new WeakSet();
|
||||
|
||||
return (key, value) => {
|
||||
if (typeof value === "object" && value !== null) {
|
||||
if (seen.has(value)) return;
|
||||
|
||||
seen.add(value);
|
||||
}
|
||||
|
||||
return value;
|
||||
};
|
||||
};
|
||||
|
||||
const retry = (options) => {
|
||||
if (options.error && options.error.code === 'ECONNREFUSED') {
|
||||
logger.error('redis', 'connection refused');
|
||||
|
||||
return new Error('refused');
|
||||
}
|
||||
|
||||
if (options.total_retry_time > 1000 * 60 * 60) {
|
||||
logger.error('redis', 'retry exhausted');
|
||||
|
||||
return new Error('exhausted');
|
||||
}
|
||||
|
||||
if (options.attempt > 10) {
|
||||
logger.error('redis', 'attempt limit');
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return Math.min(options.attempt * 100, 3000);
|
||||
};
|
||||
|
||||
const options = {
|
||||
host: settings.ep_redis_publisher.host || '127.0.0.1',
|
||||
port: settings.ep_redis_publisher.port || 6379,
|
||||
retry_strategy: retry,
|
||||
};
|
||||
|
||||
if (settings.ep_redis_publisher.password) {
|
||||
options.password = settings.ep_redis_publisher.password;
|
||||
}
|
||||
|
||||
const publisher = redis.createClient(options);
|
||||
|
||||
const buildEnvelope = (name) => {
|
||||
|
||||
return {
|
||||
name,
|
||||
routing: { sender: 'etherpad' },
|
||||
timestamp: (new Date()).getTime(),
|
||||
};
|
||||
};
|
||||
|
||||
const buildCore = (name, body) => {
|
||||
|
||||
return {
|
||||
header: { name },
|
||||
body,
|
||||
};
|
||||
};
|
||||
|
||||
const build = (name, body) => {
|
||||
|
||||
return JSON.stringify({
|
||||
envelope: buildEnvelope(name),
|
||||
core: buildCore(name, sanitizeMessageBody(body)),
|
||||
}, getCircularReplacer());
|
||||
};
|
||||
|
||||
exports.publish = (event, body) => {
|
||||
let message;
|
||||
switch (event) {
|
||||
case 'loadSettings':
|
||||
message = build('PadLoadSettingsSysMsg', body);
|
||||
break;
|
||||
case 'shutdown':
|
||||
message = build('PadShutdownSysMsg', body);
|
||||
break;
|
||||
case 'expressConfigure':
|
||||
message = build('PadConfigureSysMsg', body);
|
||||
break;
|
||||
case 'expressCreateServer':
|
||||
message = build('PadCreateServerSysMsg', body);
|
||||
break;
|
||||
case 'expressCloseServer':
|
||||
message = build('PadCloseServerSysMsg', body);
|
||||
break;
|
||||
case 'onAccessCheck':
|
||||
message = build('PadAccessCheckSysMsg', body);
|
||||
break;
|
||||
case 'padCreate':
|
||||
message = build('PadCreateSysMsg', body);
|
||||
break;
|
||||
case 'padLoad':
|
||||
message = build('PadLoadSysMsg', body);
|
||||
break;
|
||||
case 'padUpdate':
|
||||
message = build('PadUpdateSysMsg', body);
|
||||
break;
|
||||
case 'padCopy':
|
||||
message = build('PadCopySysMsg', body);
|
||||
break;
|
||||
case 'padRemove':
|
||||
message = build('PadRemoveSysMsg', body);
|
||||
break;
|
||||
case 'userLeave':
|
||||
message = build('PadUserLeaveSysMsg', body);
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
if (message) {
|
||||
publisher.publish(CHANNEL, message);
|
||||
}
|
||||
};
|
||||
@@ -1,9 +0,0 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
sed -i \
|
||||
-e 's#"dbType": "redis"#"dbType": "postgres"#' \
|
||||
-e "s#\"url\": \"redis://redis:6379\"#\"host\": \"${ETHERPAD_DB_HOST}\", \"port\": ${ETHERPAD_DB_PORT}, \"database\": \"${ETHERPAD_DB_NAME}\", \"user\": \"${ETHERPAD_DB_USER}\", \"password\": \"${ETHERPAD_DB_PASSWORD}\"#" \
|
||||
/opt/etherpad-lite/settings.json
|
||||
|
||||
exec /entrypoint.sh
|
||||
@@ -1,11 +0,0 @@
|
||||
#!/bin/sh
|
||||
set -eu
|
||||
|
||||
: "${POSTGRES_USER:?set by the upstream compose file}"
|
||||
: "${ETHERPAD_DB_NAME:?set in env.j2 and broadcast to every service}"
|
||||
|
||||
if ! psql --username "${POSTGRES_USER}" --dbname postgres -tAc \
|
||||
"SELECT 1 FROM pg_database WHERE datname = '${ETHERPAD_DB_NAME}'" | grep -q 1; then
|
||||
psql --username "${POSTGRES_USER}" --dbname postgres \
|
||||
-c "CREATE DATABASE \"${ETHERPAD_DB_NAME}\""
|
||||
fi
|
||||
@@ -3,7 +3,9 @@ import re
|
||||
from utils.cache.yaml import dump_yaml_str, load_yaml_str
|
||||
|
||||
|
||||
def compose_mods(yml_text, compose_repository_path, env_file, extra_hosts=None):
|
||||
def compose_mods(
|
||||
yml_text, compose_repository_path, env_file, extra_hosts=None, pinned=None
|
||||
):
|
||||
"""Normalize the upstream-generated bigbluebutton compose file.
|
||||
|
||||
Args:
|
||||
@@ -14,6 +16,9 @@ def compose_mods(yml_text, compose_repository_path, env_file, extra_hosts=None):
|
||||
env_file: env file broadcast to every service via ``env_file``.
|
||||
extra_hosts: optional host mappings added to every service that is
|
||||
not on the host network.
|
||||
pinned: names of services whose image the role pins in
|
||||
compose.override.yml; their upstream ``build`` is dropped even
|
||||
where the upstream file names no image.
|
||||
|
||||
Returns:
|
||||
Transformed compose YAML text. Structural deltas (named data
|
||||
@@ -32,7 +37,7 @@ def compose_mods(yml_text, compose_repository_path, env_file, extra_hosts=None):
|
||||
data = load_yaml_str(yml_text) or {}
|
||||
services = data.get("services", {}) or {}
|
||||
|
||||
for svc in services.values():
|
||||
for name, svc in services.items():
|
||||
if not isinstance(svc, dict):
|
||||
continue
|
||||
|
||||
@@ -49,7 +54,7 @@ def compose_mods(yml_text, compose_repository_path, env_file, extra_hosts=None):
|
||||
hosts.append(entry)
|
||||
svc["extra_hosts"] = hosts
|
||||
|
||||
if "build" in svc and svc.get("image"):
|
||||
if "build" in svc and (svc.get("image") or name in (pinned or [])):
|
||||
svc.pop("build")
|
||||
|
||||
data["services"] = services
|
||||
|
||||
@@ -4,10 +4,6 @@ credentials:
|
||||
description: Shared secret for BigBlueButton API authentication
|
||||
algorithm: sha256
|
||||
validation: ^[a-f0-9]{64}$
|
||||
etherpad_api_key:
|
||||
description: API key for Etherpad integration
|
||||
algorithm: random_hex_32
|
||||
validation: ^[a-zA-Z0-9]{32}$
|
||||
rails_secret:
|
||||
description: Secret key for Rails backend
|
||||
algorithm: random_hex
|
||||
|
||||
@@ -137,26 +137,13 @@ nginx:
|
||||
enabled: false
|
||||
# nocheck: playwright-service-flag: prebuilt upstream-compose image, mirror pre-pull only
|
||||
# nocheck: dynamic-flag: fixed upstream-compose sub-service, not group-gated
|
||||
etherpad:
|
||||
image: alangecker/bbb-docker-etherpad
|
||||
version: "2.4.2-s8328b77-p88f3f6b"
|
||||
update:
|
||||
type: http_regex
|
||||
url:
|
||||
- https://raw.githubusercontent.com/bigbluebutton/docker/develop/repos/tags
|
||||
- https://raw.githubusercontent.com/bigbluebutton/docker/develop/docker-compose.tmpl.yml
|
||||
pattern: "repos/bbb-etherpad-plugin (?P<plugin>[0-9a-f]+)\\nrepos/bbb-etherpad-skin (?P<skin>[0-9a-f]+)\\n(?:.*\\n)*?.*bbb-docker-etherpad:(?P<base>[0-9.]+)-s"
|
||||
template: "{base}-s{skin}-p{plugin}"
|
||||
enabled: false
|
||||
# nocheck: playwright-service-flag: prebuilt upstream-compose image, mirror pre-pull only
|
||||
# nocheck: dynamic-flag: fixed upstream-compose sub-service, not group-gated
|
||||
bbb-pads:
|
||||
image: alangecker/bbb-docker-pads
|
||||
version: "v1.5.8"
|
||||
bbb-shared-notes-server:
|
||||
image: alangecker/bbb-shared-notes-server
|
||||
version: "v3.0.39"
|
||||
update:
|
||||
type: http_regex
|
||||
url: https://raw.githubusercontent.com/bigbluebutton/docker/develop/repos/tags
|
||||
pattern: "repos/bbb-pads (v[0-9.]+)"
|
||||
pattern: "repos/bigbluebutton (v[0-9.]+)"
|
||||
enabled: false
|
||||
# nocheck: playwright-service-flag: prebuilt upstream-compose image, mirror pre-pull only
|
||||
# nocheck: dynamic-flag: fixed upstream-compose sub-service, not group-gated
|
||||
|
||||
@@ -62,25 +62,3 @@ coturn:
|
||||
mounts:
|
||||
- service: coturn
|
||||
target: /var/lib/coturn
|
||||
ep_redis_publisher_patch:
|
||||
type: bind
|
||||
source: "{{ [lookup('container', 'web-app-bigbluebutton', 'directories.instance'), 'ep_redis_publisher_index.js'] | path_join }}"
|
||||
read_only: true
|
||||
mounts:
|
||||
- service: etherpad
|
||||
target: /opt/etherpad-lite/src/plugin_packages/.versions/ep_redis_publisher@0.0.3/index.js
|
||||
etherpad_pg_entrypoint:
|
||||
type: config
|
||||
source: "{{ [lookup('container', 'web-app-bigbluebutton', 'directories.instance'), 'etherpad_pg_entrypoint.sh'] | path_join }}"
|
||||
mode: "0444"
|
||||
mounts:
|
||||
- service: etherpad
|
||||
target: /etherpad_pg_entrypoint.sh
|
||||
|
||||
postgres_initdb_etherpad:
|
||||
type: config
|
||||
source: "{{ [lookup('container', 'web-app-bigbluebutton', 'directories.instance'), 'postgres_initdb_etherpad.sh'] | path_join }}"
|
||||
mode: "0555"
|
||||
mounts:
|
||||
- service: postgres
|
||||
target: /docker-entrypoint-initdb.d/zz-etherpad.sh
|
||||
@@ -31,27 +31,6 @@
|
||||
dest: "{{ [lookup('container', application_id, 'directories.instance'), 'compose.override.yml'] | path_join }}"
|
||||
notify: compose-up
|
||||
|
||||
- name: "🩹 Vendor the ep_redis_publisher fix mounted over the etherpad plugin"
|
||||
stack_host_copy:
|
||||
src: javascript/ep_redis_publisher_index.js
|
||||
dest: "{{ [lookup('container', application_id, 'directories.instance'), 'ep_redis_publisher_index.js'] | path_join }}"
|
||||
mode: "0444"
|
||||
notify: compose-up
|
||||
|
||||
- name: "🩹 Vendor the etherpad postgres-DB entrypoint wrapper"
|
||||
stack_host_copy:
|
||||
src: shell/etherpad_pg_entrypoint.sh
|
||||
dest: "{{ [lookup('container', application_id, 'directories.instance'), 'etherpad_pg_entrypoint.sh'] | path_join }}"
|
||||
mode: "0444"
|
||||
notify: compose-up
|
||||
|
||||
- name: "🩹 Vendor the initdb hook that creates the etherpad database"
|
||||
stack_host_copy:
|
||||
src: shell/postgres_initdb_etherpad.sh
|
||||
dest: "{{ [lookup('container', application_id, 'directories.instance'), 'postgres_initdb_etherpad.sh'] | path_join }}"
|
||||
mode: "0555"
|
||||
notify: compose-up
|
||||
|
||||
- name: 📁 Create symbolic link from .env file to target location
|
||||
file:
|
||||
src: "{{ BBB_ENV_FILE_ORIGINE }}"
|
||||
|
||||
@@ -27,7 +27,8 @@
|
||||
extra_hosts=(
|
||||
[lookup('domain', 'web-app-keycloak') ~ ':host-gateway']
|
||||
if 'web-app-keycloak' in group_names else []
|
||||
)
|
||||
),
|
||||
pinned=BBB_PINNED_SERVICES
|
||||
) }}
|
||||
dest: "{{ BBB_COMPOSE_FILE_FINAL }}"
|
||||
notify:
|
||||
|
||||
@@ -30,26 +30,3 @@
|
||||
delay: 3
|
||||
until: bbb_pg_alter.rc == 0
|
||||
changed_when: false
|
||||
|
||||
- name: "🔎 Check whether the etherpad database exists"
|
||||
ansible.builtin.shell: > # nocheck: container-address-quote compose_mode_force role
|
||||
container exec -i {{ BBB_POSTGRES_CONTAINER_ADDRESS | quote }}
|
||||
psql -U postgres -d postgres -tAc
|
||||
"SELECT 1 FROM pg_database WHERE datname = 'etherpad'"
|
||||
register: bbb_etherpad_db
|
||||
retries: 20
|
||||
delay: 3
|
||||
until: bbb_etherpad_db.rc == 0
|
||||
changed_when: false
|
||||
|
||||
- name: "🗄️ Create the etherpad database"
|
||||
ansible.builtin.shell: > # nocheck: container-address-quote compose_mode_force role
|
||||
container exec -i {{ BBB_POSTGRES_CONTAINER_ADDRESS | quote }}
|
||||
psql -U postgres -d postgres -c "CREATE DATABASE etherpad"
|
||||
register: bbb_etherpad_create
|
||||
retries: 20
|
||||
delay: 3
|
||||
until: bbb_etherpad_create.rc == 0 or 'already exists' in bbb_etherpad_create.stderr
|
||||
failed_when: bbb_etherpad_create.rc != 0 and 'already exists' not in bbb_etherpad_create.stderr
|
||||
when: (bbb_etherpad_db.stdout | trim) != '1'
|
||||
changed_when: bbb_etherpad_create.rc == 0
|
||||
@@ -5,7 +5,7 @@ services:
|
||||
{{ lookup('container_volumes', service_name) | indent(4) }}
|
||||
{{ lookup('container_extra_hosts') | indent(4) }}
|
||||
{% if BBB_COLLABORA_ENABLED | bool %}
|
||||
{{ lookup('depends_on', ['redis', 'etherpad', 'bbb-pads']) }}
|
||||
{{ lookup('depends_on', ['redis']) }}
|
||||
{% endif %}
|
||||
{% set service_name = 'freeswitch' %}
|
||||
{{ service_name }}:
|
||||
@@ -15,19 +15,10 @@ services:
|
||||
{{ service_name }}:
|
||||
{{ lookup('container_image', application_id, service_name) }}
|
||||
{{ lookup('container_volumes', service_name) | indent(4) }}
|
||||
{% set service_name = 'etherpad' %}
|
||||
{{ service_name }}:
|
||||
{{ lookup('container_image', application_id, service_name) }}
|
||||
{{ lookup('container_volumes', service_name) | indent(4) }}
|
||||
entrypoint: ["sh", "{{ lookup('volume', 'web-app-bigbluebutton', 'etherpad_pg_entrypoint').target }}"]
|
||||
{% if BBB_COLLABORA_ENABLED | bool %}
|
||||
{{ lookup('depends_on', ['redis', 'postgres']) }}
|
||||
{% else %}
|
||||
{{ lookup('depends_on', ['postgres']) }}
|
||||
{% endif %}
|
||||
{% set service_name = 'bbb-pads' %}
|
||||
{% set service_name = 'bbb-shared-notes-server' %}
|
||||
{{ service_name }}:
|
||||
{{ lookup('container_image', application_id, service_name) }}
|
||||
{{ lookup('compose_restart') }}
|
||||
{% set service_name = 'bbb-export-annotations' %}
|
||||
{{ service_name }}:
|
||||
{{ lookup('container_image', application_id, service_name) }}
|
||||
@@ -68,6 +59,8 @@ services:
|
||||
{% set service_name = 'greenlight' %}
|
||||
{{ service_name }}:
|
||||
{{ lookup('container_volumes', service_name) | indent(4) }}
|
||||
environment:
|
||||
URL_HOST: "{{ domain }}"
|
||||
{% endif %}
|
||||
{% if BBB_RECORDING_ENABLED | bool %}
|
||||
{% set service_name = 'recordings' %}
|
||||
|
||||
@@ -23,12 +23,6 @@ REMOVE_OLD_RECORDING={{ BBB_RECORDING_CLEANUP_ENABLED | lower }}
|
||||
RECORDING_MAX_AGE_DAYS={{ BBB_RECORDING_MAX_AGE_DAYS }}
|
||||
|
||||
SHARED_SECRET={{ BBB_SHARED_SECRET }}
|
||||
ETHERPAD_API_KEY={{ BBB_ETHERPAD_API_KEY }}
|
||||
ETHERPAD_DB_HOST=postgres
|
||||
ETHERPAD_DB_PORT=5432
|
||||
ETHERPAD_DB_NAME=etherpad
|
||||
ETHERPAD_DB_USER=postgres
|
||||
ETHERPAD_DB_PASSWORD={{ BBB_POSTGRESQL_SECRET | dotenv_quote }}
|
||||
RAILS_SECRET={{ BBB_RAILS_SECRET }}
|
||||
POSTGRESQL_SECRET={{ BBB_POSTGRESQL_SECRET }}
|
||||
FSESL_PASSWORD={{ BBB_FSESL_PASSWORD | dotenv_quote }}
|
||||
|
||||
@@ -9,11 +9,11 @@ http_port: "{{ lookup('config', application_id, 'services.bigbluebutton.ports.lo
|
||||
|
||||
BBB_REPOSITORY: "{{ lookup('config', 'web-app-bigbluebutton', 'services.' ~ ('web-app-bigbluebutton' | get_entity_name) ~ '.repository') }}"
|
||||
BBB_REF: "{{ lookup('config', 'web-app-bigbluebutton', 'services.' ~ ('web-app-bigbluebutton' | get_entity_name) ~ '.ref') }}"
|
||||
BBB_PINNED_SERVICES: "{{ lookup('config', application_id, 'services') | dict2items | selectattr('value.image', 'defined') | map(attribute='key') | list }}"
|
||||
|
||||
_BBB_COTURN_ROLE: "web-svc-coturn"
|
||||
|
||||
BBB_SHARED_SECRET: "{{ lookup('config', application_id, 'secrets.credentials.shared_secret') }}"
|
||||
BBB_ETHERPAD_API_KEY: "{{ lookup('config', application_id, 'secrets.credentials.etherpad_api_key') }}"
|
||||
BBB_RAILS_SECRET: "{{ lookup('config', application_id, 'secrets.credentials.rails_secret') }}"
|
||||
BBB_POSTGRESQL_SECRET: "{{ lookup('config', application_id, 'secrets.credentials.postgresql_secret') }}"
|
||||
BBB_FSESL_PASSWORD: "{{ lookup('config', application_id, 'secrets.credentials.fsesl_password') }}"
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import importlib.util
|
||||
import tempfile
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
from unittest.mock import patch
|
||||
|
||||
from ansible.errors import AnsibleError
|
||||
@@ -168,6 +170,16 @@ class TestComposeFArgs(unittest.TestCase):
|
||||
|
||||
self.assertEqual(out, "-f /x/compose.yml")
|
||||
|
||||
def test_role_provides_override_reads_the_role_of_the_given_application(self):
|
||||
with (
|
||||
tempfile.TemporaryDirectory() as role,
|
||||
patch.object(self.m, "abs_role_path_by_application_id", return_value=role),
|
||||
):
|
||||
self.assertFalse(self.m._role_provides_override(application_id="x"))
|
||||
(Path(role) / "templates").mkdir()
|
||||
(Path(role) / "templates" / "compose.override.yml.j2").write_text("")
|
||||
self.assertTrue(self.m._role_provides_override(application_id="x"))
|
||||
|
||||
def test_requires_one_term(self):
|
||||
with self.assertRaises(AnsibleError):
|
||||
self.lookup.run([], variables=self.vars)
|
||||
|
||||
@@ -197,6 +197,26 @@ services:
|
||||
self.compose_repository_path + "/mod/html5-dev",
|
||||
)
|
||||
|
||||
def test_build_stripped_for_a_pinned_service_without_upstream_image(self):
|
||||
original = """services:
|
||||
bbb-shared-notes-server:
|
||||
build:
|
||||
context: mod/bbb-shared-notes-server
|
||||
html5-dev:
|
||||
build:
|
||||
context: mod/html5-dev
|
||||
"""
|
||||
services = load_yaml_str(
|
||||
compose_mods(
|
||||
original,
|
||||
self.compose_repository_path,
|
||||
self.env_file,
|
||||
pinned=["bbb-shared-notes-server"],
|
||||
)
|
||||
)["services"]
|
||||
self.assertNotIn("build", services["bbb-shared-notes-server"])
|
||||
self.assertIn("build", services["html5-dev"])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in new issue
Block a user