Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions app/runtime/server/setup/prerequisites.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,9 @@ async def deploy(self, req: web.Request) -> web.Response:
"message": "Key Vault already configured",
})

if not await self._register_keyvault_provider(steps):
return _fail(steps)

if not await self._ensure_rg(prereq_rg, location, steps):
return _fail(steps)

Expand Down Expand Up @@ -133,6 +136,9 @@ async def ensure_keyvault_ready(

prereq_rg = _DEFAULT_PREREQ_RG

if not await self._register_keyvault_provider(steps):
return steps

if not await self._ensure_rg(prereq_rg, location, steps):
return steps

Expand All @@ -144,6 +150,19 @@ async def ensure_keyvault_ready(
await self._wait_for_access(steps)
return steps

async def _register_keyvault_provider(self, steps: list[dict]) -> bool:
"""Register the Microsoft.KeyVault resource provider on the active subscription."""
ok, msg = await run_sync(
self._az.ok,
"provider", "register", "--namespace", "Microsoft.KeyVault", "--wait",
)
steps.append({
"step": "provider_registration",
"status": "ok" if ok else "failed",
"detail": "Microsoft.KeyVault registered" if ok else (msg or "Unknown error"),
})
return ok

def _link_existing_keyvault(self) -> None:
"""Ensure the existing Key Vault resource is registered on the current deployment."""
if not self._deploy_store:
Expand Down
41 changes: 38 additions & 3 deletions app/runtime/tests/test_prerequisites.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"""Tests for PrerequisitesRoutes._link_existing_keyvault."""
"""Tests for PrerequisitesRoutes helpers."""

from __future__ import annotations

Expand All @@ -7,15 +7,17 @@

from app.runtime.config.settings import cfg
from app.runtime.server.setup.prerequisites import PrerequisitesRoutes
from app.runtime.state.deploy_state import DeployStateStore, DeploymentRecord
from app.runtime.state.deploy_state import DeploymentRecord, DeployStateStore
from app.runtime.state.infra_config import InfraConfigStore
from app.runtime.util.result import Result


def _make_routes(
tmp_path: Path,
deploy_store: DeployStateStore | None = None,
az: MagicMock | None = None,
) -> PrerequisitesRoutes:
az = MagicMock()
az = az or MagicMock()
store = InfraConfigStore(path=tmp_path / "infra.json")
return PrerequisitesRoutes(az, store, deploy_store=deploy_store)

Expand Down Expand Up @@ -75,3 +77,36 @@ def test_noop_without_kv_name(self, tmp_path: Path) -> None:

updated = ds.get("cccc3333")
assert len(updated.resources) == 0


class TestRegisterKeyvaultProvider:
async def test_success_appends_ok_step(self, tmp_path: Path) -> None:
az = MagicMock()
az.ok.return_value = Result.ok("Registered")
routes = _make_routes(tmp_path, az=az)

steps: list[dict] = []
result = await routes._register_keyvault_provider(steps)

assert result is True
assert len(steps) == 1
assert steps[0]["step"] == "provider_registration"
assert steps[0]["status"] == "ok"
assert "Microsoft.KeyVault" in steps[0]["detail"]
az.ok.assert_called_once_with(
"provider", "register", "--namespace", "Microsoft.KeyVault", "--wait",
)

async def test_failure_appends_failed_step(self, tmp_path: Path) -> None:
az = MagicMock()
az.ok.return_value = Result.fail("Subscription not found")
routes = _make_routes(tmp_path, az=az)

steps: list[dict] = []
result = await routes._register_keyvault_provider(steps)

assert result is False
assert len(steps) == 1
assert steps[0]["step"] == "provider_registration"
assert steps[0]["status"] == "failed"
assert "Subscription not found" in steps[0]["detail"]