Skip to content

PMM-14665 Skip nodes internal to a PMM deployment when adding a service - #5704

Open
ademidoff wants to merge 9 commits into
mainfrom
PMM-14665-skip-non-eligible-nodes-from-add-service
Open

PMM-14665 Skip nodes internal to a PMM deployment when adding a service#5704
ademidoff wants to merge 9 commits into
mainfrom
PMM-14665-skip-non-eligible-nodes-from-add-service

Conversation

@ademidoff

@ademidoff ademidoff commented Jul 27, 2026

Copy link
Copy Markdown
Member

Ticket number: PMM-14665

Feature build: Percona-Lab/pmm-submodules#4498

In an HA deployment the PostgreSQL cluster backing PMM's persistence layer runs pmm-client sidecars, so its pods were offered in the "Nodes" dropdown of Add Service as valid monitoring delegates. Those nodes are dedicated and must not take on any extra monitoring workloads.

PMM Server now accepts PMM_INTERNAL_NODE_NAME_PREFIXES (set by the pmm-ha Helm chart), reports the nodes it matches as is_pmm_internal_node on ListNodes/GetNode, and rejects requests which delegate monitoring of a remote address to an agent running on one of them.

Local addresses (empty, localhost, 127.0.0.1, ::1) stay allowed on those nodes: that is how the PostgreSQL operator's sidecar registers its own PostgreSQL and Patroni services on every pod start, so a blanket rejection would break the persistence layer's own monitoring. An airtight alternative is to key the check on the registering service account instead, which is deliberately deferred - see the ticket.

AddAzureDatabaseRequest gains pmm_agent_id, which the UI has always sent but the server discarded, placing Azure exporters on the PMM Server unconditionally.

PMM Server nodes stay eligible on purpose: until the Azure API accepts an agent, Azure monitoring cannot run anywhere else.

If this PR adds, removes or alters one or more API endpoints, please review and update the relevant API documentation as well:

  • API Docs updated

If this PR is related to other PRs, contributions, or ongoing work in this or other repositories, please reference them here:

Summary by CodeRabbit

  • New Features

    • Added support for selecting which PMM agent runs Azure Database monitoring agents.
    • Node listings now identify PMM infrastructure nodes.
    • Added configuration for internal node-name prefixes through an environment variable or CLI flag.
  • Bug Fixes

    • Prevented monitoring workloads from being assigned to internal PMM infrastructure nodes.
    • Added eligibility checks when selecting agents for Azure Database monitoring.

In an HA deployment the PostgreSQL cluster backing PMM's persistence layer runs
pmm-client sidecars, so its pods were offered in the Nodes dropdown as valid
monitoring delegates. Those Nodes are dedicated and must not take on extra
monitoring workloads.

PMM Server now accepts PMM_INTERNAL_NODE_NAME_PREFIXES, reports the Nodes it
matches as is_pmm_internal_node, and rejects requests which delegate monitoring
of a remote address to an Agent running on one of them. Local addresses remain
allowed, so those Nodes keep monitoring the services inside their own pod.

AddAzureDatabaseRequest gains pmm_agent_id, which the UI has always sent but the
server discarded, placing Azure exporters on the PMM Server unconditionally.
@ademidoff
ademidoff requested a review from a team as a code owner July 27, 2026 22:25
@ademidoff
ademidoff requested review from 4nte and JiriCtvrtka and removed request for a team July 27, 2026 22:25
@codecov

codecov Bot commented Jul 27, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 88.39286% with 13 lines in your changes missing coverage. Please review.
✅ Project coverage is 45.43%. Comparing base (31318c7) to head (6b7f14b).
⚠️ Report is 82 commits behind head on main.

Files with missing lines Patch % Lines
managed/cmd/pmm-managed/main.go 53.84% 6 Missing ⚠️
managed/services/management/service.go 89.09% 3 Missing and 3 partials ⚠️
managed/services/management/azure_database.go 88.88% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #5704      +/-   ##
==========================================
+ Coverage   43.59%   45.43%   +1.84%     
==========================================
  Files         415      418       +3     
  Lines       43134    43397     +263     
==========================================
+ Hits        18804    19718     +914     
+ Misses      22454    21732     -722     
- Partials     1876     1947      +71     
Flag Coverage Δ
admin 34.96% <ø> (+0.17%) ⬆️
agent 50.94% <ø> (+1.89%) ⬆️
managed 45.07% <88.39%> (+2.09%) ⬆️
vmproxy 72.22% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

`pmm-agent setup` registered the Node on every run, and a forced registration
makes PMM Server drop the Node together with every Service on it. That is
harmless for the database operators, whose sidecars re-add their own services on
each container start, but it would silently delete user-added services from a
long-lived PMM Client pod, which is what the pmm-ha Helm chart is about to
pre-provision as monitoring delegates.

Registration is now skipped when the Agent already holds an ID and is being set
up against the same PMM Server it is registered with. `--force` still registers
the Node again, and pointing an Agent at a different PMM Server registers it
there as before.
…gent

Skipping registration for an Agent which already holds an ID strands it whenever
PMM Server no longer knows that ID, e.g. after the server was reinstalled or
restored from a backup taken before the Agent was registered. pmm-agent then
loops on "No Agent with ID" while the Node monitors nothing.

`pmm-agent setup` now asks the server whether it still knows the Agent and
registers the Node again when it does not. Credentials the server rejects count
as an answer too: registering reports that with an actionable message, whereas
skipping it would fail silently later on.

An unreachable server is not an answer: a failed check keeps the registration, so
an Agent still starts while PMM Server has no leader elected yet.
@ademidoff
ademidoff marked this pull request as draft July 28, 2026 07:56
ademidoff and others added 2 commits July 28, 2026 11:04
Keeping this ticket to what it is about: reporting the Nodes of a PMM deployment's
own infrastructure as internal and refusing to delegate monitoring to them.

Making `pmm-agent setup` idempotent is what would let a pre-provisioned PMM Client
pod register once and keep its identity across restarts, but the chart can do that
with a one-time init container instead. The agent side is worth its own effort:
it changes pmm-agent CLI behaviour, it needs a release note, and the surrounding
questions - how an Agent recovers when PMM Server no longer knows it, and how an
orphaned Node is reclaimed - deserve their own design and review.
@ademidoff
ademidoff marked this pull request as ready for review July 30, 2026 07:40
@coderabbitai

coderabbitai Bot commented Aug 2, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

The change adds internal-node classification and eligibility checks to management services. It adds optional PMM agent selection for Azure Database resources and exposes both features through management API schemas and configuration.

Changes

Internal node management

Layer / File(s) Summary
API contracts
api/management/v1/azure.proto, api/management/v1/node.proto, api/management/v1/json/..., api/swagger/...
The API adds pmm_agent_id for Azure Database requests and is_pmm_internal_node to node responses.
Internal-node prefix configuration
managed/cmd/pmm-managed/main.go, managed/cmd/pmm-managed/main_test.go, managed/utils/envvars/*
PMM Managed parses comma-separated internal-node prefixes, passes them to ManagementService, and excludes the setting from generic environment parsing.
Eligibility checks and node reporting
managed/services/management/service.go, managed/services/management/node.go, managed/services/management/internal_node_test.go, managed/services/management/*_test.go
The service identifies internal nodes, extracts delegated targets, rejects remote monitoring on internal nodes, and reports internal-node status.
Azure agent assignment
managed/services/management/azure_database.go
Azure Database creation selects the requested agent or the PMM Server agent, validates eligibility, and assigns the selected agent to related resources.

Estimated code review effort: 4 (Complex) | ~45 minutes

Suggested reviewers: 4nte, jirictvrtka, maxkondr

Poem

A rabbit checks each node by name,
And keeps remote work from the frame.
Azure picks an agent just right,
While schemas mark the nodes in sight.
Prefixes guide the service way.
Hop, hop—tests confirm the play.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 28.57% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the primary change: preventing service delegation to nodes internal to a PMM deployment.
Description check ✅ Passed The description includes the required ticket, feature build, API documentation status, implementation details, and related work references.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch PMM-14665-skip-non-eligible-nodes-from-add-service

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@api/management/v1/azure.proto`:
- Around line 133-134: Add an optional protobuf validation rule to pmm_agent_id
requiring a minimum length of 1 while allowing it to remain empty, matching the
validation used by existing PMM agent request fields. Preserve the service-level
existence and eligibility checks, then run make gen to regenerate the affected
code.

In `@api/management/v1/json/v1.json`:
- Around line 807-809: Update the is_pmm_internal_node descriptions in ListNodes
at api/management/v1/json/v1.json:807-809 and GetNode at
api/management/v1/json/v1.json:1369-1371 to state that internal nodes must not
receive delegated monitoring for remote addresses, while preserving that
local-address monitoring is permitted.

In `@api/swagger/swagger.json`:
- Around line 27695-27698: Update the source .proto field corresponding to
pmm_agent_id so its description clearly states that it identifies the selected
PMM agent running Azure exporters, then regenerate api/swagger/swagger.json
using the project’s prescribed generation process; do not edit the generated
Swagger file directly.

In `@managed/services/management/azure_database.go`:
- Around line 199-207: Update the RequestStateUpdate call in the
AddAzureDatabase flow to pass the selected pmmAgentID rather than
models.PMMServerAgentID, ensuring custom agent assignments receive the refresh
notification. Preserve the existing state-update timing and error handling.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: a8b9758b-4ff3-494e-b793-5f47e80b23cf

📥 Commits

Reviewing files that changed from the base of the PR and between a50c452 and 6b7f14b.

⛔ Files ignored due to path filters (3)
  • api/descriptor.bin is excluded by !**/*.bin
  • api/management/v1/azure.pb.go is excluded by !**/*.pb.go
  • api/management/v1/node.pb.go is excluded by !**/*.pb.go
📒 Files selected for processing (24)
  • api/management/v1/azure.pb.validate.go
  • api/management/v1/azure.proto
  • api/management/v1/json/client/management_service/add_azure_database_responses.go
  • api/management/v1/json/client/management_service/get_node_responses.go
  • api/management/v1/json/client/management_service/list_nodes_responses.go
  • api/management/v1/json/v1.json
  • api/management/v1/node.pb.validate.go
  • api/management/v1/node.proto
  • api/swagger/swagger-dev.json
  • api/swagger/swagger.json
  • managed/cmd/pmm-managed/main.go
  • managed/cmd/pmm-managed/main_test.go
  • managed/services/management/add_service_exporter_timeout_test.go
  • managed/services/management/agent_test.go
  • managed/services/management/annotation_test.go
  • managed/services/management/azure_database.go
  • managed/services/management/internal_node_test.go
  • managed/services/management/node.go
  • managed/services/management/node_test.go
  • managed/services/management/rds_test.go
  • managed/services/management/service.go
  • managed/services/management/service_test.go
  • managed/utils/envvars/parser.go
  • managed/utils/envvars/parser_test.go

Comment thread api/management/v1/azure.proto
Comment on lines +807 to +809
"is_pmm_internal_node": {
"description": "True if this node belongs to the internal infrastructure of a PMM deployment\n(e.g. the HA persistence layer) and must not host user monitoring workloads.",
"type": "boolean",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Align both descriptions with the enforced eligibility rule.

The current text states that internal nodes must not host user monitoring workloads. The stated behavior permits local-address monitoring. Document the remote-address delegation restriction instead.

  • api/management/v1/json/v1.json#L807-L809: update the ListNodes description.
  • api/management/v1/json/v1.json#L1369-L1371: update the GetNode description.
📍 Affects 1 file
  • api/management/v1/json/v1.json#L807-L809 (this comment)
  • api/management/v1/json/v1.json#L1369-L1371
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@api/management/v1/json/v1.json` around lines 807 - 809, Update the
is_pmm_internal_node descriptions in ListNodes at
api/management/v1/json/v1.json:807-809 and GetNode at
api/management/v1/json/v1.json:1369-1371 to state that internal nodes must not
receive delegated monitoring for remote addresses, while preserving that
local-address monitoring is permitted.

Comment thread api/swagger/swagger.json
Comment on lines +27695 to +27698
"pmm_agent_id": {
"description": "The pmm-agent identifier which should run agents. Defaults to the PMM Server's own pmm-agent.",
"type": "string",
"x-order": 26

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Describe the selected exporter in pmm_agent_id.

pmm_agent_id selects the PMM agent that runs Azure exporters. The current description says “should run agents,” which can mislead API clients. Update the source .proto description, then regenerate this file.

As per path instructions, generated Swagger files must not be edited manually; update the source .proto and regenerate them.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@api/swagger/swagger.json` around lines 27695 - 27698, Update the source
.proto field corresponding to pmm_agent_id so its description clearly states
that it identifies the selected PMM agent running Azure exporters, then
regenerate api/swagger/swagger.json using the project’s prescribed generation
process; do not edit the generated Swagger file directly.

Source: Path instructions

Comment on lines +199 to +207
pmmAgentID := models.PMMServerAgentID
if req.GetPmmAgentId() != "" {
pmmAgentID = req.GetPmmAgentId()
}
err := s.checkNodeIsEligible(ctx, pmmAgentID, req.Address)
if err != nil {
return nil, err
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Fix stale-agent notification for custom Azure agent assignment.

pmmAgentID (lines 199-207) can now be any pmm-agent, and the exporters/QAN agent are correctly created under pmmAgentID (lines 273, 284, 315). Line 337 still calls s.state.RequestStateUpdate(ctx, models.PMMServerAgentID).

When req.PmmAgentId names an agent other than models.PMMServerAgentID, this notifies the wrong pmm-agent. The pmm-agent that owns the new exporters does not get the refresh signal, so it does not start monitoring the new resources promptly.

Change the state-update call to use the selected agent:

🐛 Proposed fix
-	s.state.RequestStateUpdate(ctx, models.PMMServerAgentID)
+	s.state.RequestStateUpdate(ctx, pmmAgentID)
 	return &managementv1.AddAzureDatabaseResponse{}, nil
 }

No test in this PR sets a non-default PmmAgentId on a non-internal Node for AddAzureDatabase and asserts RequestStateUpdate receives that agent, so this bug currently goes undetected. Do you want me to add that regression test alongside the fix?

#!/bin/bash
# Description: Confirm whether other Add* handlers notify the request's actual PmmAgentId (not a hardcoded constant).
rg -n -B5 'RequestStateUpdate\(ctx,' managed/services/management/*.go

Also applies to: 337-337

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@managed/services/management/azure_database.go` around lines 199 - 207, Update
the RequestStateUpdate call in the AddAzureDatabase flow to pass the selected
pmmAgentID rather than models.PMMServerAgentID, ensuring custom agent
assignments receive the refresh notification. Preserve the existing state-update
timing and error handling.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant