-
Notifications
You must be signed in to change notification settings - Fork 227
PMM-15227 Remove stale HA replicas from Inventory #5738
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
0c3d3e9
15aa2c5
b82c657
0c04e87
1a1a3c5
d52d51a
c62e178
b2cbb72
eb6abb1
433b524
ac9e496
dafc590
82eefa4
a31b548
4b09b46
56a34df
dcaf91e
18a6c9b
4168236
326f45e
b7b543e
25e9b85
79324be
940d5d6
a8e4a51
0a3f7b4
799bfdb
34de666
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -427,6 +427,49 @@ func FindPMMAgentsRunningOnNode(q *reform.Querier, nodeID string) ([]*Agent, err | |
| return res, nil | ||
| } | ||
|
|
||
| // FindAgentsOnNode returns Agents attached to or running on the Node: node-level exporters, the | ||
| // pmm-agents themselves, and external exporters in pull mode. | ||
| func FindAgentsOnNode(q *reform.Querier, nodeID string) ([]*Agent, error) { | ||
| structs, err := q.SelectAllFrom(AgentTable, "WHERE runs_on_node_id = $1 OR node_id = $1 ORDER BY agent_id", nodeID) | ||
| if err != nil { | ||
| return nil, fmt.Errorf("failed to select Agents on Node %q: %w", nodeID, err) | ||
| } | ||
|
|
||
| res := make([]*Agent, len(structs)) | ||
| for i, str := range structs { | ||
| decryptedAgent := DecryptAgent(*str.(*Agent)) //nolint:forcetypeassert | ||
| res[i] = &decryptedAgent | ||
| } | ||
|
|
||
| return res, nil | ||
| } | ||
|
|
||
| // FindAgentsByPMMAgentIDs returns Agents started by any of the given pmm-agents. | ||
| func FindAgentsByPMMAgentIDs(q *reform.Querier, pmmAgentIDs []string) ([]*Agent, error) { | ||
| if len(pmmAgentIDs) == 0 { | ||
| return []*Agent{}, nil | ||
| } | ||
|
|
||
| p := strings.Join(q.Placeholders(1, len(pmmAgentIDs)), ", ") | ||
| tail := fmt.Sprintf("WHERE pmm_agent_id IN (%s) ORDER BY agent_id", p) | ||
| args := make([]any, len(pmmAgentIDs)) | ||
| for i, id := range pmmAgentIDs { | ||
| args[i] = id | ||
| } | ||
| structs, err := q.SelectAllFrom(AgentTable, tail, args...) | ||
| if err != nil { | ||
| return nil, fmt.Errorf("failed to select Agents started by pmm-agents: %w", err) | ||
| } | ||
|
|
||
| res := make([]*Agent, len(structs)) | ||
| for i, str := range structs { | ||
| decryptedAgent := DecryptAgent(*str.(*Agent)) //nolint:forcetypeassert | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. DecryptAgent/EncryptAgent uses heavy algos - I would recommend checking for Querier's context for cancellation first before running these operations - maybe there is no results receiver anymore |
||
| res[i] = &decryptedAgent | ||
| } | ||
|
|
||
| return res, nil | ||
| } | ||
|
|
||
|
Comment on lines
+448
to
+472
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. very similar to the prev on: |
||
| // FindPMMAgentsForService gets pmm-agents for service. | ||
| func FindPMMAgentsForService(q *reform.Querier, serviceID string) ([]*Agent, error) { | ||
| _, err := q.SelectOneFrom(ServiceTable, "WHERE service_id = $1", serviceID) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1297,6 +1297,8 @@ func SetupDB(ctx context.Context, sqlDB *sql.DB, params SetupDBParams) (*reform. | |
| return nil, err | ||
| } | ||
|
|
||
| removeStaleHANodes(ctx, db, params) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I doubt about the place where it should be running. I think that HA Leader is a good candidate for this. |
||
|
|
||
| return db, nil | ||
| } | ||
|
|
||
|
|
@@ -1517,6 +1519,44 @@ func migrateDB(db *reform.DB, params SetupDBParams) error { | |
| }) | ||
| } | ||
|
|
||
| // removeStaleHANodes drops the Inventory Nodes of HA replicas that were scaled away. Those rows are | ||
| // cosmetic, so this runs outside the migration transaction and only logs failures: tidying them up | ||
| // must never keep a replica from starting. | ||
| func removeStaleHANodes(ctx context.Context, db *reform.DB, params SetupDBParams) { | ||
| if params.HANodeID == "" || params.SetupFixtures == SkipFixtures { | ||
| return | ||
| } | ||
|
|
||
| l := logrus.WithFields(logrus.Fields{"component": "ha", "ha_node_id": params.HANodeID}) | ||
|
|
||
| nodes, err := StaleHANodes(db.WithContext(ctx), params.HANodeID, params.HAPeers) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. what does |
||
| if err != nil { | ||
| l.WithError(err).Warn("Failed to look for stale HA nodes.") | ||
| return | ||
| } | ||
|
|
||
| for _, node := range nodes { | ||
| nodeL := l.WithFields(logrus.Fields{"node_id": node.NodeID, "node_name": node.NodeName}) | ||
|
|
||
| // A transaction per Node: a failure rolls that Node back whole instead of leaving it | ||
| // half-removed, and leaves the Nodes this sweep hasn't reached yet alone. | ||
| err := db.InTransactionContext(ctx, nil, func(tx *reform.TX) error { | ||
| return RemoveStaleHANode(tx.Querier, node.NodeID) | ||
| }) | ||
| switch { | ||
| case err == nil: | ||
| nodeL.Info("Removed stale HA node, it is not a part of the cluster anymore.") | ||
| case errors.Is(err, reform.ErrNoRows), status.Code(err) == codes.NotFound: | ||
| nodeL.WithError(err).Info("Stale HA node was already removed by another replica.") | ||
| case errors.Is(err, context.Canceled), errors.Is(err, context.DeadlineExceeded): | ||
| nodeL.WithError(err).Warn("Startup was cancelled, stopping the removal of stale HA nodes.") | ||
| return | ||
| default: | ||
| nodeL.WithError(err).Warn("Failed to remove a stale HA node, keeping it.") | ||
| } | ||
| } | ||
| } | ||
|
|
||
| type agentConfig struct { | ||
| ID string `yaml:"id"` | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the same is achieved by