diff --git a/tools/connectors/account.py b/tools/connectors/account.py index bbeb064419..91aac30e6e 100644 --- a/tools/connectors/account.py +++ b/tools/connectors/account.py @@ -23,8 +23,9 @@ class AccountOperationStart: failed: bool = False -def _matching_open_operation(names: list[str], *, profile_home: str | None) -> ConnectionOperation | None: - matches = [live.find_target(name, profile_home=profile_home) for name in names] +def _matching_open_operation(names: list[str], *, alias: str | None, + profile_home: str | None) -> ConnectionOperation | None: + matches = [live.find_target(name, alias=alias, profile_home=profile_home) for name in names] first = next((operation for operation in matches if operation is not None), None) if first is None: return None @@ -38,12 +39,14 @@ def find_or_start_operation( *, action: str, profile_home: str | None, + alias: str | None = None, ) -> AccountOperationStart: + """``alias`` names the one account of ``names[0]`` to connect; the caller passes one name with it.""" with _start_lock: - if operation := _matching_open_operation(names, profile_home=profile_home): + if operation := _matching_open_operation(names, alias=alias, profile_home=profile_home): return AccountOperationStart(operation=operation, started=False) operation = ConnectionOperation( - [Target(name, "connector", action) for name in names], + [Target(name, "connector", action, alias=alias) for name in names], session_key=f"account:{uuid.uuid4().hex}", ) started = AccountOperationStart(operation=operation, started=True) diff --git a/tools/connectors/live.py b/tools/connectors/live.py index cd6ff235bb..c90695c631 100644 --- a/tools/connectors/live.py +++ b/tools/connectors/live.py @@ -63,12 +63,16 @@ def get_by_op_id(op_id: str, *, profile_home: Optional[str] = None) -> Optional[ if key == profile_key and operation.op_id == op_id and not operation.settled), None) -def find_target(name: str, *, profile_home: Optional[str] = None) -> Optional[ConnectionOperation]: +def find_target(name: str, *, alias: Optional[str] = None, + profile_home: Optional[str] = None) -> Optional[ConnectionOperation]: + """The open operation connecting this account: the connector ``name`` and the same ``alias``, + so an open operation for one account is never reused for another account of the same app.""" profile_key = _profile_key(profile_home) with _lock: return next((operation for (key, _), operation in _open.items() if key == profile_key and not operation.settled - and (target := operation.target(name)) is not None and target.kind == "connector"), None) + and (target := operation.target(name)) is not None and target.kind == "connector" + and target.alias == alias), None) def close(operation: ConnectionOperation) -> None: diff --git a/tools/connectors/operation.py b/tools/connectors/operation.py index 3cd35b0ca2..c9caf4e757 100644 --- a/tools/connectors/operation.py +++ b/tools/connectors/operation.py @@ -41,6 +41,8 @@ class Target: extra: dict[str, Any] = field(default_factory=dict) # The install step an ``initiated`` catalog row is in (an ``InstallPhase`` id); drawn only then. phase: Optional[str] = None + # The name of the one hosted account this target connects or repairs; absent for the connector's default account. + alias: Optional[str] = None @property def resolved(self) -> bool: @@ -49,6 +51,8 @@ class Target: def snapshot(self, *, with_url: bool = True) -> dict[str, Any]: out: dict[str, Any] = {"name": self.name, "kind": self.kind, "action": self.action, "state": self.state.value, "resolved": self.resolved} + if self.alias: + out["alias"] = self.alias if self.phase and self.state == TargetState.initiated: out["phase"] = self.phase if self.detail: