diff --git a/copaw/src/copaw_worker/sync.py b/copaw/src/copaw_worker/sync.py index 4a95a1665..6005a36f6 100644 --- a/copaw/src/copaw_worker/sync.py +++ b/copaw/src/copaw_worker/sync.py @@ -303,9 +303,14 @@ def _ensure_alias(self) -> None: Cloud mode (RRSA/STS): refresh credentials before every mc batch via the shared shell function (lazy, no-op when token is valid). - Local mode: set mc alias once with static credentials. + Kubernetes uses an existing MC_HOST alias for OSS, or sets the alias + once with static credentials for MinIO. + Local mode also sets the alias once with static credentials. """ runtime = os.environ.get("AGENTTEAMS_RUNTIME", "") + storage_provider = ( + os.environ.get("AGENTTEAMS_STORAGE_PROVIDER", "").strip().lower() + ) mc_host_set = bool(os.environ.get(f"MC_HOST_{_MC_ALIAS}")) controller_url = os.environ.get("AGENTTEAMS_CONTROLLER_URL", "") logger.info( @@ -322,9 +327,17 @@ def _ensure_alias(self) -> None: controller_url, ) if self._k8s_mode: - logger.info("_ensure_alias: k8s mode, skipping mc alias set (mc-wrapper handles credentials)") - self._alias_set = True - return + if mc_host_set: + logger.info( + "_ensure_alias: k8s mode, MC_HOST_%s already set, skipping mc alias set", + _MC_ALIAS, + ) + self._alias_set = True + return + if storage_provider == "oss": + raise RuntimeError( + f"OSS storage requires controller-issued MC_HOST_{_MC_ALIAS} credentials" + ) if self._cloud_mode: logger.info("_ensure_alias: credential path=sts, refreshing MC_HOST_%s", _MC_ALIAS) self._refresh_cloud_credentials() diff --git a/copaw/tests/test_worker_sync.py b/copaw/tests/test_worker_sync.py index 9aa0483af..9e7322c62 100644 --- a/copaw/tests/test_worker_sync.py +++ b/copaw/tests/test_worker_sync.py @@ -3,17 +3,14 @@ import logging import subprocess +import pytest + from copaw_worker import sync from copaw_worker.sync import FileSync -def test_ensure_alias_skips_static_alias_in_k8s_mode(monkeypatch, tmp_path): - calls = [] - - monkeypatch.setenv("AGENTTEAMS_RUNTIME", "k8s") - monkeypatch.setattr(sync, "_mc", lambda *args, **_kwargs: calls.append(args)) - - fs = FileSync( +def _file_sync(tmp_path): + return FileSync( endpoint="minio:9000", access_key="tt", secret_key="secret", @@ -22,6 +19,69 @@ def test_ensure_alias_skips_static_alias_in_k8s_mode(monkeypatch, tmp_path): local_dir=tmp_path, ) + +@pytest.mark.parametrize("storage_provider", ["minio", None]) +def test_ensure_alias_sets_static_alias_for_minio_in_k8s_mode( + monkeypatch, tmp_path, storage_provider +): + calls = [] + + monkeypatch.setenv("AGENTTEAMS_RUNTIME", "k8s") + if storage_provider is None: + monkeypatch.delenv("AGENTTEAMS_STORAGE_PROVIDER", raising=False) + else: + monkeypatch.setenv("AGENTTEAMS_STORAGE_PROVIDER", storage_provider) + monkeypatch.delenv(f"MC_HOST_{sync._MC_ALIAS}", raising=False) + monkeypatch.setattr(sync, "_mc", lambda *args, **_kwargs: calls.append(args)) + + fs = _file_sync(tmp_path) + + fs._ensure_alias() + + assert fs._alias_set is True + assert calls == [ + ( + "alias", + "set", + sync._MC_ALIAS, + "http://minio:9000", + "tt", + "secret", + ) + ] + + +def test_ensure_alias_requires_mc_host_for_oss_in_k8s_mode(monkeypatch, tmp_path): + calls = [] + + monkeypatch.setenv("AGENTTEAMS_RUNTIME", "k8s") + monkeypatch.setenv("AGENTTEAMS_STORAGE_PROVIDER", "oss") + monkeypatch.delenv(f"MC_HOST_{sync._MC_ALIAS}", raising=False) + monkeypatch.setattr(sync, "_mc", lambda *args, **_kwargs: calls.append(args)) + + fs = _file_sync(tmp_path) + + with pytest.raises(RuntimeError, match=f"MC_HOST_{sync._MC_ALIAS}"): + fs._ensure_alias() + + assert calls == [] + + +def test_ensure_alias_uses_existing_mc_host_for_oss_in_k8s_mode( + monkeypatch, tmp_path +): + calls = [] + + monkeypatch.setenv("AGENTTEAMS_RUNTIME", "k8s") + monkeypatch.setenv("AGENTTEAMS_STORAGE_PROVIDER", "oss") + monkeypatch.setenv( + f"MC_HOST_{sync._MC_ALIAS}", + "https://access:secret:token@oss-cn-hangzhou.aliyuncs.com", + ) + monkeypatch.setattr(sync, "_mc", lambda *args, **_kwargs: calls.append(args)) + + fs = _file_sync(tmp_path) + fs._ensure_alias() assert fs._alias_set is True