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.

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-from is 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.