all lists on lists.proxmox.com
 help / color / mirror / Atom feed
From: Daniel Kral <d.kral@proxmox.com>
To: pve-devel@lists.proxmox.com
Subject: [pve-devel] [PATCH ha-manager 6/9] config, manager: factor out resource motion info logic
Date: Mon, 15 Dec 2025 16:52:16 +0100	[thread overview]
Message-ID: <20251215155334.476984-7-d.kral@proxmox.com> (raw)
In-Reply-To: <20251215155334.476984-1-d.kral@proxmox.com>

The logic in execute_migration(...) and get_resource_motion_info(...) to
gather dependent and blocking HA resources is equivalent and should also
be the same for consistency, so factor them out as a separate helper.

The PVE::HA::Helpers package is introduced since there does not exist a
package for shared logic between packages, which cannot depend on each
other (e.g. Manager and Config, LRM and CRM, etc.) and PVE::HA::Tools is
not the right place for these.

Signed-off-by: Daniel Kral <d.kral@proxmox.com>
---
 debian/pve-ha-manager.install |  1 +
 src/PVE/HA/Config.pm          | 31 ++++-----------------
 src/PVE/HA/Helpers.pm         | 52 +++++++++++++++++++++++++++++++++++
 src/PVE/HA/Makefile           |  1 +
 src/PVE/HA/Manager.pm         | 45 +++++++++++++-----------------
 5 files changed, 78 insertions(+), 52 deletions(-)
 create mode 100644 src/PVE/HA/Helpers.pm

diff --git a/debian/pve-ha-manager.install b/debian/pve-ha-manager.install
index bdb1feeb..6ee0ee5d 100644
--- a/debian/pve-ha-manager.install
+++ b/debian/pve-ha-manager.install
@@ -27,6 +27,7 @@
 /usr/share/perl5/PVE/HA/FenceConfig.pm
 /usr/share/perl5/PVE/HA/Groups.pm
 /usr/share/perl5/PVE/HA/HashTools.pm
+/usr/share/perl5/PVE/HA/Helpers.pm
 /usr/share/perl5/PVE/HA/LRM.pm
 /usr/share/perl5/PVE/HA/Manager.pm
 /usr/share/perl5/PVE/HA/NodeStatus.pm
diff --git a/src/PVE/HA/Config.pm b/src/PVE/HA/Config.pm
index 1199b0d4..f8c5965e 100644
--- a/src/PVE/HA/Config.pm
+++ b/src/PVE/HA/Config.pm
@@ -8,9 +8,9 @@ use JSON;
 use PVE::Cluster qw(cfs_register_file cfs_read_file cfs_write_file cfs_lock_file);
 
 use PVE::HA::Groups;
+use PVE::HA::Helpers;
 use PVE::HA::Resources;
 use PVE::HA::Rules;
-use PVE::HA::Rules::ResourceAffinity qw(get_affinitive_resources);
 use PVE::HA::Tools;
 
 my $manager_status_filename = "ha/manager_status";
@@ -391,34 +391,13 @@ sub get_resource_motion_info {
         my $manager_status = read_manager_status();
         my $ss = $manager_status->{service_status};
         my $ns = $manager_status->{node_status};
+        # get_resource_motion_info expects a hashset of all nodes with status 'online'
+        my $online_nodes = { map { $ns->{$_} eq 'online' ? ($_ => 1) : () } keys %$ns };
 
         my $compiled_rules = read_and_compile_rules_config();
-        my $resource_affinity = $compiled_rules->{'resource-affinity'};
-        my ($together, $separate) = get_affinitive_resources($resource_affinity, $sid);
 
-        for my $csid (sort keys %$together) {
-            next if !defined($ss->{$csid});
-            next if $ss->{$csid}->{state} eq 'ignored';
-
-            push @$dependent_resources, $csid;
-        }
-
-        for my $node (keys %$ns) {
-            next if $ns->{$node} ne 'online';
-
-            for my $csid (sort keys %$separate) {
-                next if !defined($ss->{$csid});
-                next if $ss->{$csid}->{state} eq 'ignored';
-                next if $ss->{$csid}->{node} && $ss->{$csid}->{node} ne $node;
-                next if $ss->{$csid}->{target} && $ss->{$csid}->{target} ne $node;
-
-                push $blocking_resources_by_node->{$node}->@*,
-                    {
-                        sid => $csid,
-                        cause => 'resource-affinity',
-                    };
-            }
-        }
+        ($dependent_resources, $blocking_resources_by_node) =
+            PVE::HA::Helpers::get_resource_motion_info($ss, $sid, $online_nodes, $compiled_rules);
     }
 
     return ($dependent_resources, $blocking_resources_by_node);
diff --git a/src/PVE/HA/Helpers.pm b/src/PVE/HA/Helpers.pm
new file mode 100644
index 00000000..09300cd4
--- /dev/null
+++ b/src/PVE/HA/Helpers.pm
@@ -0,0 +1,52 @@
+package PVE::HA::Helpers;
+
+use v5.36;
+
+use PVE::HA::Rules::ResourceAffinity qw(get_affinitive_resources);
+
+=head3 get_resource_motion_info
+
+Gathers which other HA resources in C<$ss> put a node placement dependency or
+node placement restriction on C<$sid> according to the compiled rules in
+C<$compiled_rules> and the online nodes in C<$online_nodes>.
+
+Returns a list of two elements, where the first element is a list of HA resource
+ids which are dependent on the node placement of C<$sid>, and the second element
+is a hash of nodes blocked for C<$sid>, where each entry value is a list of the
+causes that make the node unavailable to C<$sid>.
+
+=cut
+
+sub get_resource_motion_info($ss, $sid, $online_nodes, $compiled_rules) {
+    my $dependent_resources = [];
+    my $blocking_resources_by_node = {};
+
+    my $resource_affinity = $compiled_rules->{'resource-affinity'};
+    my ($together, $separate) = get_affinitive_resources($resource_affinity, $sid);
+
+    for my $csid (sort keys %$together) {
+        next if !defined($ss->{$csid});
+        next if $ss->{$csid}->{state} eq 'ignored';
+
+        push @$dependent_resources, $csid;
+    }
+
+    for my $node (keys %$online_nodes) {
+        for my $csid (sort keys %$separate) {
+            next if !defined($ss->{$csid});
+            next if $ss->{$csid}->{state} eq 'ignored';
+            next if $ss->{$csid}->{node} && $ss->{$csid}->{node} ne $node;
+            next if $ss->{$csid}->{target} && $ss->{$csid}->{target} ne $node;
+
+            push $blocking_resources_by_node->{$node}->@*,
+                {
+                    sid => $csid,
+                    cause => 'resource-affinity',
+                };
+        }
+    }
+
+    return ($dependent_resources, $blocking_resources_by_node);
+}
+
+1;
diff --git a/src/PVE/HA/Makefile b/src/PVE/HA/Makefile
index 1aeb976b..57871b29 100644
--- a/src/PVE/HA/Makefile
+++ b/src/PVE/HA/Makefile
@@ -2,6 +2,7 @@ SIM_SOURCES=CRM.pm \
 	    Env.pm \
 	    Groups.pm \
 	    HashTools.pm \
+	    Helpers.pm \
 	    Rules.pm \
 	    Resources.pm \
 	    LRM.pm \
diff --git a/src/PVE/HA/Manager.pm b/src/PVE/HA/Manager.pm
index 74e898f9..470df92c 100644
--- a/src/PVE/HA/Manager.pm
+++ b/src/PVE/HA/Manager.pm
@@ -8,11 +8,12 @@ use Digest::MD5 qw(md5_base64);
 use PVE::Tools;
 
 use PVE::HA::Groups;
+use PVE::HA::Helpers;
 use PVE::HA::NodeStatus;
 use PVE::HA::Rules;
 use PVE::HA::Rules::NodeAffinity qw(get_node_affinity);
 use PVE::HA::Rules::ResourceAffinity
-    qw(get_affinitive_resources get_resource_affinity apply_positive_resource_affinity apply_negative_resource_affinity);
+    qw(get_resource_affinity apply_positive_resource_affinity apply_negative_resource_affinity);
 use PVE::HA::Tools ':exit_codes';
 use PVE::HA::Usage::Basic;
 
@@ -388,43 +389,35 @@ sub read_lrm_status {
 sub execute_migration {
     my ($self, $cmd, $task, $sid, $target) = @_;
 
-    my ($haenv, $ss) = $self->@{qw(haenv ss)};
+    my ($haenv, $ss, $ns, $compiled_rules) = $self->@{qw(haenv ss ns compiled_rules)};
+    my $online_nodes = { map { $_ => 1 } $self->{ns}->list_online_nodes()->@* };
 
-    my $resource_affinity = $self->{compiled_rules}->{'resource-affinity'};
-    my ($together, $separate) = get_affinitive_resources($resource_affinity, $sid);
+    my ($dependent_resources, $blocking_resources_by_node) =
+        PVE::HA::Helpers::get_resource_motion_info($ss, $sid, $online_nodes, $compiled_rules);
 
-    my $blocked_from_migration;
-    for my $csid (sort keys %$separate) {
-        next if !defined($ss->{$csid});
-        next if $ss->{$csid}->{state} eq 'ignored';
-        next if $ss->{$csid}->{node} && $ss->{$csid}->{node} ne $target;
-        next if $ss->{$csid}->{target} && $ss->{$csid}->{target} ne $target;
+    if (my $blocking_resources = $blocking_resources_by_node->{$target}) {
+        for my $blocking_resource (@$blocking_resources) {
+            my $err_msg = "unknown migration blocker reason";
+            my ($csid, $cause) = $blocking_resource->@{qw(sid cause)};
 
-        $haenv->log(
-            'err',
-            "crm command '$cmd' error - service '$csid' on node '$target' in"
-                . " negative affinity with service '$sid'",
-        );
+            if ($cause eq 'resource-affinity') {
+                $err_msg = "service '$csid' on node '$target' in negative"
+                    . " affinity with service '$sid'";
+            }
 
-        $blocked_from_migration = 1;
+            $haenv->log('err', "crm command '$cmd' error - $err_msg");
+        }
+
+        return; # do not queue migration if there are blockers
     }
 
-    return if $blocked_from_migration;
-
     $haenv->log('info', "got crm command: $cmd");
     $ss->{$sid}->{cmd} = [$task, $target];
 
-    my $resources_to_migrate = [];
-    for my $csid (sort keys %$together) {
-        next if !defined($ss->{$csid});
-        next if $ss->{$csid}->{state} eq 'ignored';
+    for my $csid (@$dependent_resources) {
         next if $ss->{$csid}->{node} && $ss->{$csid}->{node} eq $target;
         next if $ss->{$csid}->{target} && $ss->{$csid}->{target} eq $target;
 
-        push @$resources_to_migrate, $csid;
-    }
-
-    for my $csid (@$resources_to_migrate) {
         $haenv->log(
             'info',
             "crm command '$cmd' - $task service '$csid' to node '$target'"
-- 
2.47.3



_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel


  parent reply	other threads:[~2025-12-15 15:54 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-12-15 15:52 [pve-devel] [PATCH-SERIES container/ha-manager/manager/qemu-server 00/12] HA node affinity blockers (#1497) Daniel Kral
2025-12-15 15:52 ` [pve-devel] [PATCH ha-manager 1/9] ha: put source files on individual new lines Daniel Kral
2025-12-15 15:52 ` [pve-devel] [PATCH ha-manager 2/9] d/pve-ha-manager.install: remove duplicate Config.pm Daniel Kral
2025-12-15 15:52 ` [pve-devel] [PATCH ha-manager 3/9] config: group and sort use statements Daniel Kral
2025-12-15 15:52 ` [pve-devel] [PATCH ha-manager 4/9] manager: " Daniel Kral
2025-12-15 15:52 ` [pve-devel] [PATCH ha-manager 5/9] manager: report all reasons when resources are blocked from migration Daniel Kral
2025-12-15 15:52 ` Daniel Kral [this message]
2025-12-15 15:52 ` [pve-devel] [PATCH ha-manager 7/9] tests: add test cases for migrating resources with node affinity rules Daniel Kral
2025-12-15 15:52 ` [pve-devel] [PATCH ha-manager 8/9] handle strict node affinity rules in manual migrations Daniel Kral
2025-12-15 15:52 ` [pve-devel] [PATCH ha-manager 9/9] handle node affinity rules with failback " Daniel Kral
2025-12-15 15:52 ` [pve-devel] [PATCH qemu-server 1/1] api: migration preconditions: add node affinity as blocking cause Daniel Kral
2025-12-15 15:52 ` [pve-devel] [PATCH container " Daniel Kral
2025-12-15 15:52 ` [pve-devel] [PATCH manager 1/1] ui: migrate: display precondition messages for ha node affinity Daniel Kral

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20251215155334.476984-7-d.kral@proxmox.com \
    --to=d.kral@proxmox.com \
    --cc=pve-devel@lists.proxmox.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal