Database Watchers
A Watcher collects performance data from the targets you give it. When a target has public network access
disabled, the watcher reaches it over a managed private endpoint, which you declare as a
SharedPrivateLink. This page covers how ASO completes that private endpoint, and what to expect while it
does.
How a shared private link becomes usable
Creating a SharedPrivateLink asks Azure to open a private endpoint connection on the resource the link
points at. That connection starts out Pending: Azure creates it from a Microsoft-owned subscription rather
than yours, so no role assignment of yours can approve it. Until somebody approves it, the watcher cannot
collect from the target.
Azure reports nothing about that connection on the link itself - status on the SharedPrivateLink is never
populated - so ASO reads the connection on the target resource, which is the only place its state appears.
The link’s Ready condition follows what it finds there:
| Connection state | Ready condition |
|---|---|
| Not opened yet | False, waiting for Azure to open it |
Pending |
False, and ASO approves it if it can (see below) |
Approved |
True |
Rejected, Disconnected |
False, reporting the decision and leaving it alone |
A link that stays False is telling you the private endpoint behind it carries no traffic yet. Check the
condition message with kubectl describe for the reason.
When ASO approves the connection for you
ASO approves the connection only when the link names its target as a Kubernetes resource:
apiVersion: databasewatcher.azure.com/v20241001preview
kind: SharedPrivateLink
metadata:
name: aso-sample-spl
namespace: default
spec:
owner:
name: aso-sample-watcher
groupId: sqlServer
requestMessage: Please approve the connection from the database watcher
# Naming the target as a Kubernetes resource, rather than by armId, is what lets ASO approve
# the private endpoint connection this link opens on it
privateLinkResourceReference:
group: sql.azure.com
kind: Server
name: aso-sample-server
That reference is what supplies the API version the connection is read and written with - the link’s own
databasewatcher API version is not valid for Microsoft.Sql or Microsoft.Kusto - and it means ASO is
completing a handshake on a resource you already manage with it.
A link that names its target by armId instead keeps the behaviour it has always had. With no API version
its connections cannot even be read, so ASO reports nothing about them and the link goes Ready on its own
provisioning alone. Approve those connections yourself, in the portal or with az.
These refusals apply only to a connection ASO would have to approve. An Approved connection makes the link
Ready whatever they say, because readiness is a fact about the connection rather than a decision. While a
connection is Pending, ASO declines to approve it and holds the link False with the reason, when:
- The target is managed by a different operator. Operators sharing a cluster have their own credentials and policies, and none of that is visible from the link.
- The target asks for a different credential. Approving writes to the target with the link’s credential,
so anything short of an identical
serviceoperator.azure.com/credential-fromis refused. - Either resource’s reconcile policy forbids modification. The policy suppresses the approval, not the reporting, so the link still tells you the connection is pending.
- Two connections on the target are named after the link. A link name is unique only under its own watcher, so ASO refuses to guess which of them to approve. Approve the right one on the target yourself.
Permissions
Approving a private endpoint connection needs a role granting
Microsoft.Sql/servers/privateEndpointConnections/write on the target - Owner and Contributor both do,
Reader does not - which the credential that created the link does not necessarily hold. When ASO is
refused, the link reports that approval is required and that its credential cannot give it: approve the
connection yourself, or grant the operator the role. A credential that cannot even read the target’s
connections leaves the link the readiness it had before, since ASO then has nothing to report.
Starting the watcher
ARM creates every watcher stopped, and refuses to start one that has no target yet, so ASO starts a watcher
when the first Target under it is reconciled. Set autoStart to false to keep it out of that:
apiVersion: databasewatcher.azure.com/v20241001preview
kind: Watcher
metadata:
name: aso-sample-watcher
namespace: default
spec:
operatorSpec:
autoStart: false
ASO then never starts the watcher, so one you stop yourself stays stopped - collection costs while a watcher runs, and there are targets you may want provisioned before they are watched. Left unset, the next reconcile of any target starts a stopped watcher again. A start already under way is followed to its end either way.
Restarting a watcher after approval
A watcher that is already running when a connection is approved must be restarted before it uses that connection. ASO does not restart one for you, because stopping a watcher interrupts collection for every target on it. Nothing sequences a watcher’s start against a link’s approval either, so this can happen on first creation as well. If a target reports no data over a private endpoint you know to be approved, stop and start its watcher.