적용 우선순위 (2026-09-09 후속 결함 반영)
P1 구현·시험 후 병합/잔여 회귀 완료 트랙을 유지한다. #965 serializer 수정도 같은 완료 트랙에서 추적한다. 전체 순서·완료 트랙은 #950을 기준으로 한다. 기술적 의존성은 본문의 계약을 유지한다.
부모 에픽: #950
우선순위: P1 — 현재 기능 오류 수정
사용자 보고 및 실제 동작
Europa 전역 설정에서 cloud.dr.service.enabled를 켜서 저장하면 아래 오류가 표시되며 설정 저장이 실패한다.
Disaster recovery service can only be activated if you have rbd type storage.
첨부 화면에는 Cloud dr service enabled 항목과 위 오류, 설정 저장 실패 알림이 함께 나타난다. 사용자 제공 화면을 근거로 하며, 이번 분석에서 운영 서버의 스토리지 목록·설정 DB·로그를 직접 조회하거나 설정을 변경하지 않았다. 따라서 해당 환경에 RBD가 실제로 없는지, 설치 패키지가 어느 커밋인지까지 단정하지 않는다.
코드에서 확인된 직접 원인
최신 upstream ablestack-europa 커밋 92e12845a2585e75c9558c780029c896e295fedf에서 동일 조건과 오류 문구를 직접 확인했다.
ConfigurationManagerImpl.validateDisasterRecoveryValues()는 설정 이름이 cloud.dr.service.enabled이고 값이 true이면 _storagePoolDao.listAll()로 로컬 pool을 조회한다.
- pool 중
StoragePoolType.RBD가 하나도 없으면 화면과 동일한 InvalidParameterValueException을 던진다.
- 이 검증은 서비스 활성화 단계에서 특정 Plan·대상 사이트·provider capability와 무관하게 실행된다.
- 따라서 RBD 없이 SharedMountPoint qcow2를 사용하는 구성은 차단된다. 반대로 로컬에 RBD가 하나 있다는 사실만으로 선택한 DR 경로의 실행 가능성이 보장되지도 않는다.
최신 upstream 오류 발생 코드
영향 분석
Cloud PR #940과 qemu PR #54는 RBD뿐 아니라 SharedMountPoint qcow2를 포함하는 다중 경로 DR 계약을 도입했다. 전역 설정에 남은 RBD 존재 조건은 이 계약과 맞지 않는다.
PR #940 기준 코드에서 다음 신규 작업도 DisasterRecoveryServiceEnabled가 false이면 조기 반환한다. 설정 실패는 화면상 토글 문제에 그치지 않고 이 작업들이 실행되지 않는 조건을 유지할 수 있다. 실제 서버에서 발생한 후속 장애 여부는 별도 검증이 필요하다.
동일 키는 레거시 DR cluster API 등록과 VM 시작/삭제 검사, capability 응답에도 사용된다. 레거시 cluster는 Deprecated 대상으로 항상 비활성화해야 하며, 기존 데이터의 VM 보호 검사는 기능 활성화와 구분해 보존한다.
기대 동작 및 수정 범위
- 전역 서비스 활성화와 특정 Plan의 실행 준비 상태를 분리한다. 전역 enable 조건에서 로컬 RBD 존재를 필수로 요구하지 않는다.
- 단순히
RBD || SharedMountPoint로 확장하는 데 그치지 않는다. 서비스 초기 설정, 로컬 pool 미등록, 원격 사이트 자원 사용도 고려해 전역 토글이 일시적인 로컬 inventory에 종속되지 않도록 한다.
- 스토리지 type·상태·접근성·용량·Agent/worker·provider 등 실행 조건은 해당 Site/Plan/action readiness에서 검증한다. 전역 활성화 성공이 모든 경로의 지원/실행 가능 판정이 되어서는 안 된다.
- 레거시 DR cluster는 Deprecated 대상으로 API 등록·UI 노출·서비스 실행을 항상 차단한다. RBD 존재나 전역 true 설정으로 다시 활성화하지 않는다. 기존 데이터는 보존하고 VM 보호 검사는 별도로 유지한다.
- 기존 설정 키와 저장값·기본값의 호환성을 유지하고 UI/API/capability 및 scheduler의 의미를 일치시킨다. 키를 분리해야 한다면 명시적인 업그레이드·호환 설계와 테스트가 선행되어야 한다.
- 설명에 관리 서버 재시작 필요가 명시되어 있으므로 실제 ConfigKey 적용 방식에 맞춰 저장 성공·적용 시점·재시작 안내를 검증한다. 저장 성공만으로 즉시 scheduler 활성화가 확인되었다고 표시하지 않는다.
- readiness 실패는 잘못된 전역 RBD 오류 대신 대상 경로의 구체적 원인으로 안내한다.
구현 책임과 다른 과제와의 관계
재현 및 회귀 매트릭스
| 구성/동작 |
기대 결과 |
| RBD 없음, 정상 SharedMountPoint qcow2 구성 |
전역 enable 저장 성공; 해당 경로 readiness는 별도로 판정 |
| RBD만 존재 |
신규 enable 정상; 레거시 DR cluster는 계속 비활성 |
| RBD + SharedMountPoint 혼합 |
전역 enable 및 경로별 올바른 readiness |
| 로컬 pool 없음/아직 자원 미구성 |
서비스 enable은 가능; 실행 불가 Plan은 구체적 사유로 차단 |
| 원격 사이트 대상 자원 사용 |
로컬 RBD 유무를 전역 조건으로 강제하지 않음 |
| 미지원/비정상 스토리지·worker 없음 |
전역 enable과 별개로 해당 Plan/action을 안전하게 차단 |
| false 저장, true 재저장, 관리 서버 재시작 |
저장·적용·capability·scheduler 동작 일치 |
완료 기준
개발은 dhslove 저장소에서 진행하고 Cloud 변경 Maven 모듈은 WSL ext4에서 검증한다. 전체 빌드는 별도 요청 시 수행한다. 본 이슈 등록 과정에서는 소스 수정·배포·재시작·환경 설정 변경을 수행하지 않는다.
코드 수준 설계 — #960 (2026-09-09, 레거시 비활성화 계약 반영)
사용자 확정 조건: 레거시 DR cluster는 Deprecated 대상이며 활성화하면 안 된다. 앞서 검토했던 “레거시 RBD 제약을 create/setup/enable로 이동해 사용 가능하게 유지”하는 안은 폐기한다. 이 절은 구현 전 설계이며 소스·빌드·배포·설정 변경은 수행하지 않았다.
1. 최종 동작 계약
| 전역 설정 |
신규 DrSite/DrPlan API 및 scheduler |
레거시 DR cluster API/기능 |
| false |
기존 비활성 계약 유지 |
항상 비활성 |
| true + RBD 없음/qcow2만/미구성 |
신규 서비스 활성; 실행 readiness는 별도 판정 |
항상 비활성 |
| true + RBD 존재 |
신규 서비스 활성; 실행 readiness는 별도 판정 |
항상 비활성 |
cloud.dr.service.enabled의 key/default=false/Boolean/비동적 적용 속성은 유지한다.
- 이 설정의 의미는 신규 DR 서비스 활성화로 정리한다. RBD가 있거나 관리자 계정이어도 레거시 기능을 다시 열지 않는다.
- 레거시용 재활성화 설정, force 우회, RBD 감지 fallback을 추가하지 않는다.
- 기존 DB/VM/볼륨은 삭제·자동 변환하지 않는다. 기존 VM 보호 검사와 레거시 기능 활성화는 구분한다.
- 신규 DrPlan 기능의 공유 구현이 현재
DisasterRecoveryClusterServiceImpl에 들어 있다는 이유로 bean 전체를 제거하지 않는다.
2. cloud-server: 전역 RBD 검증 제거
대상: server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java
현재 validateConfigurationValue(name, value, scope) 순서는 설정 존재/권한/scope→타입 해석→specific 검증→DR RBD 검증→타입 검증→범위 검증이다.
변경:
validateSpecificConfigurationValues(name, value, type);
-validateDisasterRecoveryValues(name, value, type);
boolean isTypeValid = validateValueType(value, type);
...
-protected void validateDisasterRecoveryValues(String name, String value, Class<?> type) {
- // cloud.dr.service.enabled=true -> storagePoolDao.listAll() -> RBD required
-}
- 호출과 전용 메서드를 함께 제거한다. 빈 메서드나 true를 위한 early-return을 두지 않는다.
- Boolean은 현재 true/false만 허용하는
validateValueType()를 그대로 통과시킨다. invalid scope/권한/범위 검증과 저장·감사 경로를 유지한다.
- StoragePool DAO/import는 다른 기능에서 쓰이는지 확인해 필요한 참조를 보존한다.
- RBD 조건을 SharedMountPoint 조건으로 바꾸거나 원격 사이트를 전역 저장 시 조회하지 않는다.
3. DR API 등록: 신규 allowlist만 유지
대상: plugins/integrations/disaster-recovery/src/main/java/com/cloud/dr/cluster/DisasterRecoveryClusterServiceImpl.java#getCommands()
현재 같은 DisasterRecoveryServiceEnabled 분기에서 레거시 명령과 신규 명령을 연속 등록한다. 전역 RBD 검증 제거와 이 등록 변경은 같은 수정에 포함해야 한다.
public List<Class<?>> getCommands() {
List<Class<?>> commands = new ArrayList<>();
if (!DisasterRecoveryServiceEnabled.value()) {
return commands;
}
// 현재 CreateDrSiteCmd 이후의 신규 DR 명령을 명시적으로 등록.
// 레거시 cluster 명령은 설정/스토리지 종류와 무관하게 등록하지 않음.
return commands;
}
명시적 등록에서 제외할 기존 명령:
ListScvmIpAddressCmd, ConnectivityTestsDisasterRecoveryClusterCmd, GetDisasterRecoveryClusterListCmd
Create/Update/Delete/Enable/Disable/Promote/Demote/Resync/ClearDisasterRecoveryClusterCmd
Create/Update/Delete/Start/Stop/Promote/Demote/TakeSnapshotDisasterRecoveryClusterVmCmd
위 slash 표기는 해당 접두어 각각의 기존 클래스다. 신규 목록은 현재 CreateDrSiteCmd부터 RefreshDrProtectionViewCmd까지의 명시적 Dr* 목록을 기준으로 그대로 유지한다. 이름 prefix 자동 필터보다 실제 class allowlist를 사용한다.
- 신규
ExecuteDrSiteAgentCommandCmd, protection group, failback/reprotect/release API도 유지한다.
- 다른
PluggableService#getCommands()나 Spring/API registry에 같은 레거시 클래스가 중복 등록되는지 검색하고, 전체 registry 기준으로 미노출을 테스트한다.
- 등록되지 않은 옛 API 직접 호출은 플랫폼의 기존 “미지원/알 수 없는 API” 응답을 사용한다. 신규 API 오류로 위장하지 않는다.
4. 서비스 직접 호출도 레거시 실행 차단
API 미등록만으로 내부 호출·비동기 경로의 레거시 동작을 보장할 수 없으므로 동일 클래스의 레거시 전용 외부 서비스 진입점에도 차단을 적용한다.
새 내부 helper 제안:
private void rejectDeprecatedLegacyDrClusterOperation(String operation) {
throw new InvalidParameterValueException(
"LEGACY_DR_CLUSTER_DEPRECATED: " + operation
+ " is unavailable; use DR Site and DR Plan APIs");
}
- 레거시 create/setup/enable/update/promote/demote/resync/VM lifecycle/snapshot/connectivity 및 legacy list/delete/disable/clear의 호출 경로를 열거해 외부 진입점에서 즉시 거절한다.
setupDisasterRecoveryCluster()는 기존 queued 작업도 DB/파일/원격 명령 변경 전에 거절한다.
- 기존 boolean enable 조건을 이 helper로 바꾸되 “레거시 전용” 메서드에만 적용한다.
getCommands(), getConfigKeys() 및 신규 Dr* 구현은 차단하지 않는다.
- 내부 DTO 구성/DAO 조회 등 신규 기능에서도 재사용할 수 있는 helper에는 이름만 보고 일괄 throw를 추가하지 않는다. 호출 관계를 확인한다.
- 신규 DrSite/DrPlan이 레거시 기능 실행 메서드에 의존하는 호출이 발견되면 필요한 공통 부분을 부작용 없는 helper로 분리한다. 레거시 공개 진입점을 예외적으로 재개방하지 않는다.
- 레거시 전용 background/예약 작업이 있다면 등록/시작도 차단한다. 신규
DrProjectionScheduler, DrSchedulerRecoveryScheduler, DrSiteHealthCheckScheduler는 유지한다.
기존 레거시 자원 정리가 필요하더라도 이번 설정을 켜서 옛 delete/clear API를 다시 제공하지 않는다. 기존 데이터는 보존하고 별도 복구 범위로 다룬다. #962의 신규 DrPlan 강제 정리를 레거시 API 재활성화로 대체하지 않는다.
5. ConfigKey·UI·capability
대상 ConfigKey: DisasterRecoveryClusterService.DisasterRecoveryServiceEnabled
- 클래스/필드명이 legacy여도 이번 오류 수정에서 대규모 패키지 이동을 하지 않는다. 공유된 신규 기능을 보존하며 설명/Javadoc을 명확히 한다.
- 설명 제안:
Enables DR Site and DR Plan services. Legacy DR cluster APIs remain unavailable. Management server restart required after change.
- key/default/type/dynamic 속성 및 DB 기존 값 호환성을 유지한다. 새 schema/profile 버전을 만들지 않는다.
현재 UI 경로는 ui/src/config/router.js→section/disasterRecovery.js→infra/drSite, infra/drPlan이다. 레거시 infra/disasterRecovery.js 파일은 남아 있지만 활성 DR section에서는 가져오지 않는다.
- 현재 신규 메뉴 구성을 유지한다. 레거시 route/action을 다시 import하지 않는다.
listApis permission 기준에서도 레거시 메뉴/액션이 나타나지 않아야 한다. 캐시된 권한/직접 URL 진입도 검증한다.
ManagementServerImpl의 disasterRecoveryEnabled capability는 신규 DR 서비스의 설정값 의미로 유지하고 레거시 지원 신호로 쓰지 않는다.
- UI success는 설정 저장 성공이다. 관리 서버 재시작 후 effective ConfigKey/등록 API/scheduler 적용 확인과 구분한다. 여러 관리 서버라면 각 서버의 적용 결과를 확인한다.
- 기존
UserVmManagerImpl.checkDisasterRecoveryIfVmCanBeStarted/Destroyed()는 이번 수정에서 제거하지 않는다. 기존 데이터 보호용 검사이며 레거시 API 활성화가 아니다. 비보호 VM 영향이 없는지 회귀한다.
6. 신규 readiness 및 qemu 경계
DrPlanReadinessValidator.validateForExecution()의 source/worker/data plane/target placement/disk size 검증을 유지한다. 전역 enable에 성공해도 실행 불가 Plan은 기존 blocking reason으로 차단한다.
7. 변경 파일과 테스트
| 파일/영역 |
변경 및 검증 |
| ConfigurationManagerImpl.java |
전역 helper 삭제; 일반 검증 유지 |
| ConfigurationManagerImplTest.java |
true/false/잘못된 boolean/scope/non-RBD/DAO 무조회 |
| DisasterRecoveryClusterServiceImpl.java |
신규 API allowlist + 레거시 진입점 차단 |
| DisasterRecoveryClusterService.java |
설정 설명과 Deprecated 경계 문서화 |
| DR cluster 서비스/명령 등록 테스트 (필요 시 신규) |
API 등록 목록 및 레거시 부작용 없음 |
| 기존 DrSchedulerRecoverySchedulerTest 및 관련 scheduler 테스트 |
전역/개별 enabled 조합 |
| UI route/permission 테스트 |
신규 메뉴 유지, 레거시 route·액션 미노출 |
| docs/ftctl의 API/backend/운영 설정 문서 |
신규 enable·레거시 불가·재시작 계약 |
구체적 테스트:
validateDrServiceEnableDoesNotRequireStorage: 실제 validateConfigurationValue() 호출; 설정/Global scope/Boolean 타입 fixture를 구성하고 true 성공 및 storagePoolDao.listAll() never 검증.
- SharedMountPoint-only, RBD-only, 혼합, pool 없음에서도 같은 결과. 핵심은 inventory와 독립적이라는 것이며 unused mock stub을 만들지 않는다.
- false 성공, yes/1/TRUE 등 현재 미허용 Boolean 오류, invalid scope/설정 누락 및 기존 일반 타입·범위 검증 유지.
getCommands(): false이면 기존처럼 신규 목록 비어 있음; true이면 신규 expected class set 포함, 레거시 class set 전부 제외. RBD 유무와 무관하게 동일.
- 모든 레거시 외부 진입점의 직접 호출이
LEGACY_DR_CLUSTER_DEPRECATED로 거절되고 persist/파일 쓰기/mirror 호출이 없다. 최소 create/setup/enable/VM start/snapshot/delete/clear를 부작용 mock으로 검증하고 나머지 진입점은 목록 기반 커버리지로 확인한다.
- 신규 API 호출·DrSite/DrPlan 조회·기존 공유 helper가 legacy guard에 막히지 않는다.
- global=false 또는 individual=false인 scheduler는 작업 미실행, 둘 다 true이면 기존 본체 실행 조건 통과.
- 지원 qcow2 Plan readiness 양성, worker/target 부족 음성 사례 유지.
- 기존 VM 보호 검사·비보호 VM 시작/삭제 회귀. 레거시 활성화 성공을 기대하는 옛 테스트는 “항상 차단” 기대값으로 변경한다.
8. 구현·검증 실행안
- dhslove 작업 트리의 변경을 보존하고 Europa 기준 SHA를 먼저 확인한다.
- 설정 회귀 추가→전역 검증 제거→API allowlist/서비스 차단→설정 설명/문서→모듈·UI 회귀 순으로 진행한다.
- WSL ext4 clone에서 변경 모듈을 검증한다. 전체 Cloud 빌드는 요청 없이 실행하지 않는다.
mvn -pl server -Dtest=ConfigurationManagerImplTest test
mvn -pl plugins/integrations/disaster-recovery test
위 명령은 의존 artifact가 준비된 환경의 대상 모듈 검증안이다. 구현 시 실제 profile/기존 fixture를 확인하고 부족한 의존 모듈만 준비한다. 테스트 편의를 위해 전체 빌드를 자동 실행하지 않는다. UI 소스가 변경된 경우 해당 lint/단위 테스트를 추가한다.
실제 환경은 별도 승인된 절차로 검증한다:
- non-RBD 환경에서 true 저장 성공.
- 필요한 관리 서버 재시작 후 신규 DR API·scheduler 활성 확인.
- RBD 유무 모두에서 legacy API 미등록/직접 호출 차단·UI 미노출 확인.
- 신규 qcow2 readiness와 DB/API/runtime 확인. 더미 RBD나 직접 DB 수정 금지.
- 변경 JAR/설정 설명 적용 SHA 및 관리 로그 기록.
9. 범위·완료 판정
적용 우선순위 (2026-09-09 후속 결함 반영)
P1 구현·시험 후 병합/잔여 회귀 완료 트랙을 유지한다. #965 serializer 수정도 같은 완료 트랙에서 추적한다. 전체 순서·완료 트랙은 #950을 기준으로 한다. 기술적 의존성은 본문의 계약을 유지한다.
부모 에픽: #950
우선순위: P1 — 현재 기능 오류 수정
사용자 보고 및 실제 동작
Europa 전역 설정에서
cloud.dr.service.enabled를 켜서 저장하면 아래 오류가 표시되며 설정 저장이 실패한다.첨부 화면에는
Cloud dr service enabled항목과 위 오류, 설정 저장 실패 알림이 함께 나타난다. 사용자 제공 화면을 근거로 하며, 이번 분석에서 운영 서버의 스토리지 목록·설정 DB·로그를 직접 조회하거나 설정을 변경하지 않았다. 따라서 해당 환경에 RBD가 실제로 없는지, 설치 패키지가 어느 커밋인지까지 단정하지 않는다.코드에서 확인된 직접 원인
최신 upstream
ablestack-europa커밋92e12845a2585e75c9558c780029c896e295fedf에서 동일 조건과 오류 문구를 직접 확인했다.ConfigurationManagerImpl.validateDisasterRecoveryValues()는 설정 이름이cloud.dr.service.enabled이고 값이true이면_storagePoolDao.listAll()로 로컬 pool을 조회한다.StoragePoolType.RBD가 하나도 없으면 화면과 동일한InvalidParameterValueException을 던진다.최신 upstream 오류 발생 코드
영향 분석
Cloud PR #940과 qemu PR #54는 RBD뿐 아니라 SharedMountPoint qcow2를 포함하는 다중 경로 DR 계약을 도입했다. 전역 설정에 남은 RBD 존재 조건은 이 계약과 맞지 않는다.
PR #940 기준 코드에서 다음 신규 작업도
DisasterRecoveryServiceEnabled가 false이면 조기 반환한다. 설정 실패는 화면상 토글 문제에 그치지 않고 이 작업들이 실행되지 않는 조건을 유지할 수 있다. 실제 서버에서 발생한 후속 장애 여부는 별도 검증이 필요하다.동일 키는 레거시 DR cluster API 등록과 VM 시작/삭제 검사, capability 응답에도 사용된다. 레거시 cluster는 Deprecated 대상으로 항상 비활성화해야 하며, 기존 데이터의 VM 보호 검사는 기능 활성화와 구분해 보존한다.
기대 동작 및 수정 범위
RBD || SharedMountPoint로 확장하는 데 그치지 않는다. 서비스 초기 설정, 로컬 pool 미등록, 원격 사이트 자원 사용도 고려해 전역 토글이 일시적인 로컬 inventory에 종속되지 않도록 한다.구현 책임과 다른 과제와의 관계
재현 및 회귀 매트릭스
완료 기준
개발은 dhslove 저장소에서 진행하고 Cloud 변경 Maven 모듈은 WSL ext4에서 검증한다. 전체 빌드는 별도 요청 시 수행한다. 본 이슈 등록 과정에서는 소스 수정·배포·재시작·환경 설정 변경을 수행하지 않는다.
코드 수준 설계 — #960 (2026-09-09, 레거시 비활성화 계약 반영)
사용자 확정 조건: 레거시 DR cluster는 Deprecated 대상이며 활성화하면 안 된다. 앞서 검토했던 “레거시 RBD 제약을 create/setup/enable로 이동해 사용 가능하게 유지”하는 안은 폐기한다. 이 절은 구현 전 설계이며 소스·빌드·배포·설정 변경은 수행하지 않았다.
1. 최종 동작 계약
cloud.dr.service.enabled의 key/default=false/Boolean/비동적 적용 속성은 유지한다.DisasterRecoveryClusterServiceImpl에 들어 있다는 이유로 bean 전체를 제거하지 않는다.2. cloud-server: 전역 RBD 검증 제거
대상:
server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java현재
validateConfigurationValue(name, value, scope)순서는 설정 존재/권한/scope→타입 해석→specific 검증→DR RBD 검증→타입 검증→범위 검증이다.변경:
validateValueType()를 그대로 통과시킨다. invalid scope/권한/범위 검증과 저장·감사 경로를 유지한다.3. DR API 등록: 신규 allowlist만 유지
대상:
plugins/integrations/disaster-recovery/src/main/java/com/cloud/dr/cluster/DisasterRecoveryClusterServiceImpl.java#getCommands()현재 같은
DisasterRecoveryServiceEnabled분기에서 레거시 명령과 신규 명령을 연속 등록한다. 전역 RBD 검증 제거와 이 등록 변경은 같은 수정에 포함해야 한다.명시적 등록에서 제외할 기존 명령:
ListScvmIpAddressCmd,ConnectivityTestsDisasterRecoveryClusterCmd,GetDisasterRecoveryClusterListCmdCreate/Update/Delete/Enable/Disable/Promote/Demote/Resync/ClearDisasterRecoveryClusterCmdCreate/Update/Delete/Start/Stop/Promote/Demote/TakeSnapshotDisasterRecoveryClusterVmCmd위 slash 표기는 해당 접두어 각각의 기존 클래스다. 신규 목록은 현재
CreateDrSiteCmd부터RefreshDrProtectionViewCmd까지의 명시적 Dr* 목록을 기준으로 그대로 유지한다. 이름 prefix 자동 필터보다 실제 class allowlist를 사용한다.ExecuteDrSiteAgentCommandCmd, protection group, failback/reprotect/release API도 유지한다.PluggableService#getCommands()나 Spring/API registry에 같은 레거시 클래스가 중복 등록되는지 검색하고, 전체 registry 기준으로 미노출을 테스트한다.4. 서비스 직접 호출도 레거시 실행 차단
API 미등록만으로 내부 호출·비동기 경로의 레거시 동작을 보장할 수 없으므로 동일 클래스의 레거시 전용 외부 서비스 진입점에도 차단을 적용한다.
새 내부 helper 제안:
setupDisasterRecoveryCluster()는 기존 queued 작업도 DB/파일/원격 명령 변경 전에 거절한다.getCommands(),getConfigKeys()및 신규 Dr* 구현은 차단하지 않는다.DrProjectionScheduler,DrSchedulerRecoveryScheduler,DrSiteHealthCheckScheduler는 유지한다.기존 레거시 자원 정리가 필요하더라도 이번 설정을 켜서 옛 delete/clear API를 다시 제공하지 않는다. 기존 데이터는 보존하고 별도 복구 범위로 다룬다. #962의 신규 DrPlan 강제 정리를 레거시 API 재활성화로 대체하지 않는다.
5. ConfigKey·UI·capability
대상 ConfigKey:
DisasterRecoveryClusterService.DisasterRecoveryServiceEnabledEnables DR Site and DR Plan services. Legacy DR cluster APIs remain unavailable. Management server restart required after change.현재 UI 경로는
ui/src/config/router.js→section/disasterRecovery.js→infra/drSite,infra/drPlan이다. 레거시infra/disasterRecovery.js파일은 남아 있지만 활성 DR section에서는 가져오지 않는다.listApispermission 기준에서도 레거시 메뉴/액션이 나타나지 않아야 한다. 캐시된 권한/직접 URL 진입도 검증한다.ManagementServerImpl의disasterRecoveryEnabledcapability는 신규 DR 서비스의 설정값 의미로 유지하고 레거시 지원 신호로 쓰지 않는다.UserVmManagerImpl.checkDisasterRecoveryIfVmCanBeStarted/Destroyed()는 이번 수정에서 제거하지 않는다. 기존 데이터 보호용 검사이며 레거시 API 활성화가 아니다. 비보호 VM 영향이 없는지 회귀한다.6. 신규 readiness 및 qemu 경계
DrPlanReadinessValidator.validateForExecution()의 source/worker/data plane/target placement/disk size 검증을 유지한다. 전역 enable에 성공해도 실행 불가 Plan은 기존 blocking reason으로 차단한다.DrPlanTargetPlacementResolver.resolve(),validateTargetReadiness(),validateForRelease()에 RBD-only 조건을 추가하지 않는다.7. 변경 파일과 테스트
구체적 테스트:
validateDrServiceEnableDoesNotRequireStorage: 실제validateConfigurationValue()호출; 설정/Global scope/Boolean 타입 fixture를 구성하고 true 성공 및storagePoolDao.listAll()never 검증.getCommands(): false이면 기존처럼 신규 목록 비어 있음; true이면 신규 expected class set 포함, 레거시 class set 전부 제외. RBD 유무와 무관하게 동일.LEGACY_DR_CLUSTER_DEPRECATED로 거절되고 persist/파일 쓰기/mirror 호출이 없다. 최소 create/setup/enable/VM start/snapshot/delete/clear를 부작용 mock으로 검증하고 나머지 진입점은 목록 기반 커버리지로 확인한다.8. 구현·검증 실행안
위 명령은 의존 artifact가 준비된 환경의 대상 모듈 검증안이다. 구현 시 실제 profile/기존 fixture를 확인하고 부족한 의존 모듈만 준비한다. 테스트 편의를 위해 전체 빌드를 자동 실행하지 않는다. UI 소스가 변경된 경우 해당 lint/단위 테스트를 추가한다.
실제 환경은 별도 승인된 절차로 검증한다:
9. 범위·완료 판정