[pve-devel] [PATCH ha-manager v2 2/6] factor out and unify sim_hardware_cmd

Thomas Lamprecht t.lamprecht at proxmox.com
Thu Jan 19 13:32:46 CET 2017


Most things done by sim_hardware_cmd are already abstracted and
available in both, the TestHardware and the RTHardware class.

Abstract out the CRM and LRM control to allow the unification of both
classes sim_hardware_cmd.

As in the last year mostly the regression test systems TestHardware
class saw new features use it as base.

We return now the current status out of the locked context, this
allows to update the simulators GUI out of the locked context.

This changes increases the power of the HA Simulator, but the new
possible actions must be still implemented in its GUI. This will be
done in future patches.

Signed-off-by: Thomas Lamprecht <t.lamprecht at proxmox.com>
---

changes since v1:
* pass the lock_fh to the crm and lrm control methods to allow the real time
  environment to unlock the lock after forking

 src/PVE/HA/Sim/Hardware.pm     | 147 ++++++++++++++++++++++++++++++++++++++
 src/PVE/HA/Sim/RTHardware.pm   |  95 ++++++++++---------------
 src/PVE/HA/Sim/TestHardware.pm | 158 +++++++----------------------------------
 3 files changed, 212 insertions(+), 188 deletions(-)

diff --git a/src/PVE/HA/Sim/Hardware.pm b/src/PVE/HA/Sim/Hardware.pm
index 96186de..298c3bb 100644
--- a/src/PVE/HA/Sim/Hardware.pm
+++ b/src/PVE/HA/Sim/Hardware.pm
@@ -498,10 +498,157 @@ sub get_node_info {
 # simulate hardware commands
 # power <node> <on|off>
 # network <node> <on|off>
+# reboot <node>
+# shutdown <node>
+# restart-lrm <node>
+# service <sid> <started|disabled|stopped>
+# service <sid> <migrate|relocate> <target>
+# service <sid> lock/unlock [lockname]
 
 sub sim_hardware_cmd {
     my ($self, $cmdstr, $logid) = @_;
 
+    my $code = sub {
+	my ($lock_fh) = @_;
+
+	my $cstatus = $self->read_hardware_status_nolock();
+
+	my ($cmd, $objid, $action, $target) = split(/\s+/, $cmdstr);
+
+	die "sim_hardware_cmd: no node or service for command specified"
+	    if !$objid;
+
+	my ($node, $sid, $d);
+
+	if ($cmd eq 'service') {
+	    $sid = PVE::HA::Tools::pve_verify_ha_resource_id($objid);
+	} else {
+	    $node = $objid;
+	    $d = $self->{nodes}->{$node} ||
+		die "sim_hardware_cmd: no such node '$node'\n";
+	}
+
+	$self->log('info', "execute $cmdstr", $logid);
+
+	if ($cmd eq 'power') {
+	    die "sim_hardware_cmd: unknown action '$action'\n"
+		if $action !~ m/^(on|off)$/;
+
+	    if ($cstatus->{$node}->{power} ne $action) {
+		if ($action eq 'on') {
+
+		    $d->{crm} = $self->crm_control('start', $d, $lock_fh) if !defined($d->{crm});
+		    $d->{lrm} = $self->lrm_control('start', $d, $lock_fh) if !defined($d->{lrm});
+		    $d->{lrm_restart} = undef;
+
+		} else {
+
+		    if ($d->{crm}) {
+			$d->{crm_env}->log('info', "killed by poweroff");
+			$self->crm_control('stop', $d, $lock_fh);
+			$d->{crm} = undef;
+		    }
+		    if ($d->{lrm}) {
+			$d->{lrm_env}->log('info', "killed by poweroff");
+			$self->lrm_control('stop', $d, $lock_fh);
+			$d->{lrm} = undef;
+			$d->{lrm_restart} = undef;
+		    }
+
+		    $self->watchdog_reset_nolock($node);
+		    $self->write_service_status($node, {});
+		}
+	    }
+
+	    $cstatus->{$node}->{power} = $action;
+	    $cstatus->{$node}->{network} = $action;
+	    $cstatus->{$node}->{shutdown} = undef;
+
+	    $self->write_hardware_status_nolock($cstatus);
+
+	} elsif ($cmd eq 'network') {
+	    die "sim_hardware_cmd: unknown network action '$action'"
+		if $action !~ m/^(on|off)$/;
+	    $cstatus->{$node}->{network} = $action;
+
+	    $self->write_hardware_status_nolock($cstatus);
+
+	} elsif ($cmd eq 'reboot' || $cmd eq 'shutdown') {
+	    $cstatus->{$node}->{shutdown} = $cmd;
+
+	    $self->write_hardware_status_nolock($cstatus);
+
+	    $self->lrm_control('shutdown', $d, $lock_fh) if defined($d->{lrm});
+	} elsif ($cmd eq 'restart-lrm') {
+	    if ($d->{lrm}) {
+		$d->{lrm_restart} = 1;
+		$self->lrm_control('shutdown', $d, $lock_fh);
+	    }
+	} elsif ($cmd eq 'crm') {
+
+	    if ($action eq 'stop') {
+		if ($d->{crm}) {
+		    $d->{crm_stop} = 1;
+		    $self->crm_control('shutdown', $d, $lock_fh);
+		}
+	    } elsif ($action eq 'start') {
+		$d->{crm} = $self->crm_control('start', $d, $lock_fh) if !defined($d->{crm});
+	    } else {
+		die "sim_hardware_cmd: unknown action '$action'";
+	    }
+
+	} elsif ($cmd eq 'service') {
+	    if ($action eq 'started' || $action eq 'disabled' || $action eq 'stopped') {
+
+		$self->set_service_state($sid, $action);
+
+	    } elsif ($action eq 'migrate' || $action eq 'relocate') {
+
+		die "sim_hardware_cmd: missing target node for '$action' command"
+		    if !$target;
+
+		$self->queue_crm_commands_nolock("$action $sid $target");
+
+	    } elsif ($action eq 'add') {
+
+		$self->add_service($sid, {state => 'started', node => $target});
+
+	    } elsif ($action eq 'delete') {
+
+		$self->delete_service($sid);
+
+	    } elsif ($action eq 'lock') {
+
+		$self->lock_service($sid, $target);
+
+	    } elsif ($action eq 'unlock') {
+
+		$self->unlock_service($sid, $target);
+
+	    } else {
+		die "sim_hardware_cmd: unknown service action '$action' " .
+		    "- not implemented\n"
+	    }
+	} else {
+	    die "sim_hardware_cmd: unknown command '$cmdstr'\n";
+	}
+
+	return $cstatus;
+    };
+
+    return $self->global_lock($code);
+}
+
+# for controlling the resource manager services
+sub crm_control {
+    my ($self, $action, $data, $lock_fh) = @_;
+
+    die "implement in subclass";
+}
+
+sub lrm_control {
+    my ($self, $action, $data, $lock_fh) = @_;
+
     die "implement in subclass";
 }
 
diff --git a/src/PVE/HA/Sim/RTHardware.pm b/src/PVE/HA/Sim/RTHardware.pm
index 145d73b..33debaa 100644
--- a/src/PVE/HA/Sim/RTHardware.pm
+++ b/src/PVE/HA/Sim/RTHardware.pm
@@ -178,75 +178,56 @@ sub fork_daemon {
     return $pid;
 }
 
+# for controlling the resource manager services (CRM and LRM)
+sub crm_control {
+    my ($self, $action, $data, $lock_fh) = @_;
+
+    if ($action eq 'start') {
+
+	return  $self->fork_daemon($lock_fh, 'crm', $data->{crm_env});
+
+    } elsif ($action eq 'stop') {
+
+	kill(9, $data->{crm});
+	while (waitpid($data->{crm}, 0) != $data->{crm}) {}
+
+    } else {
+	die "unknown CRM control action: '$action'\n";
+    }
+}
+
+sub lrm_control {
+    my ($self, $action, $data, $lock_fh) = @_;
+
+    if ($action eq 'start') {
+
+	return  $self->fork_daemon($lock_fh, 'lrm',  $data->{lrm_env});
+
+    } elsif ($action eq 'stop') {
+
+	kill(9, $data->{lrm});
+	while (waitpid($data->{lrm}, 0) != $data->{lrm}) {}
+
+    } else {
+	die "unknown LRM control action: '$action'\n";
+    }
+
+}
+
 # simulate hardware commands
-# power <node> <on|off>
-# network <node> <on|off>
-
 sub sim_hardware_cmd {
     my ($self, $cmdstr, $logid) = @_;
 
-    my $cstatus;
-
-    # note: do not fork when we own the lock!
-    my $code = sub {
-	my ($lockfh) = @_;
-
-	$cstatus = $self->read_hardware_status_nolock();
-
-	my ($cmd, $node, $action) = split(/\s+/, $cmdstr);
-
-	die "sim_hardware_cmd: no node specified" if !$node;
-	die "sim_hardware_cmd: unknown action '$action'" if $action !~ m/^(on|off)$/;
-
-	my $d = $self->{nodes}->{$node};
-	die "sim_hardware_cmd: no such node '$node'\n" if !$d;
-
-	$self->log('info', "execute $cmdstr", $logid);
-	
-	if ($cmd eq 'power') {
-	    if ($cstatus->{$node}->{power} ne $action) {
-		if ($action eq 'on') {
-		    $d->{crm} = $self->fork_daemon($lockfh, 'crm', $d->{crm_env}) if !$d->{crm};
-		    $d->{lrm} = $self->fork_daemon($lockfh, 'lrm', $d->{lrm_env}) if !$d->{lrm};
-		} else {
-		    if ($d->{crm}) {
-			$self->log('info', "crm on node '$node' killed by poweroff");
-			kill(9, $d->{crm});
-			$d->{crm} = undef;
-		    }
-		    if ($d->{lrm}) {
-			$self->log('info', "lrm on node '$node' killed by poweroff");
-			kill(9, $d->{lrm});
-			$d->{lrm} = undef;
-		    }
-		    $self->watchdog_reset_nolock($node);
-		    $self->write_service_status($node, {});
-		}
-	    }
-
-	    $cstatus->{$node}->{power} = $action;
-	    $cstatus->{$node}->{network} = $action;
-
-	} elsif ($cmd eq 'network') {
-	    $cstatus->{$node}->{network} = $action;
-	} else {
-	    die "sim_hardware_cmd: unknown command '$cmd'\n";
-	}
-
-	$self->write_hardware_status_nolock($cstatus);
-    };
-
-    my $res = $self->global_lock($code);
+    my $cstatus = $self->SUPER::sim_hardware_cmd($cmdstr, $logid);
 
     # update GUI outside lock
-
     foreach my $node (keys %$cstatus) {
 	my $d = $self->{nodes}->{$node};
 	$d->{network_btn}->set_active($cstatus->{$node}->{network} eq 'on');
 	$d->{power_btn}->set_active($cstatus->{$node}->{power} eq 'on');
     }
 
-    return $res;
+    return $cstatus;
 }
 
 sub cleanup {
diff --git a/src/PVE/HA/Sim/TestHardware.pm b/src/PVE/HA/Sim/TestHardware.pm
index 50aef0c..57531c5 100644
--- a/src/PVE/HA/Sim/TestHardware.pm
+++ b/src/PVE/HA/Sim/TestHardware.pm
@@ -81,138 +81,34 @@ sub log {
     $self->{logfh}->flush();
 }
 
-# simulate hardware commands
-# power <node> <on|off>
-# network <node> <on|off>
-# reboot <node>
-# shutdown <node>
-# restart-lrm <node>
-# service <sid> <started|disabled|stopped>
-# service <sid> <migrate|relocate> <target>
-# service <sid> lock/unlock [lockname]
+# for controlling the resource manager services (CRM and LRM)
+sub crm_control {
+    my ($self, $action, $data, $lock_fh) = @_;
+
+    if ($action eq 'start') {
+	return PVE::HA::CRM->new($data->{crm_env});
+    } elsif ($action eq 'stop') {
+	# nothing todo sim_hardware_cmd sets us to undef, thats enough
+    } elsif ($action eq 'shutdown') {
+	$data->{crm}->shutdown_request();
+    } else {
+	die "unknown CRM control action: '$action'\n";
+    }
+}
+
+sub lrm_control {
+    my ($self, $action, $data, $lock_fh) = @_;
+
+    if ($action eq 'start') {
+	return PVE::HA::LRM->new($data->{lrm_env});
+    } elsif ($action eq 'stop') {
+	# nothing todo sim_hardware_cmd sets us to undef, thats enough
+    } elsif ($action eq 'shutdown') {
+	$data->{lrm}->shutdown_request();
+    } else {
+	die "unknown LRM control action: '$action'\n";
+    }
 
-sub sim_hardware_cmd {
-    my ($self, $cmdstr, $logid) = @_;
-
-    my $code = sub {
-
-	my $cstatus = $self->read_hardware_status_nolock();
-
-	my ($cmd, $objid, $action, $target) = split(/\s+/, $cmdstr);
-
-	die "sim_hardware_cmd: no node or service for command specified"
-	    if !$objid;
-
-	my ($node, $sid, $d);
-
-	if ($cmd eq 'service') {
-	    $sid = PVE::HA::Tools::pve_verify_ha_resource_id($objid);
-	} else {
-	    $node = $objid;
-	    $d = $self->{nodes}->{$node} ||
-		die "sim_hardware_cmd: no such node '$node'\n";
-	}
-
-	$self->log('info', "execute $cmdstr", $logid);
-	
-	if ($cmd eq 'power') {
-	    die "sim_hardware_cmd: unknown action '$action'" if $action !~ m/^(on|off)$/;
-	    if ($cstatus->{$node}->{power} ne $action) {
-		if ($action eq 'on') {
-		    $d->{crm} = PVE::HA::CRM->new($d->{crm_env}) if !$d->{crm};
-		    $d->{lrm} = PVE::HA::LRM->new($d->{lrm_env}) if !$d->{lrm};
-		    $d->{lrm_restart} = undef;
-		} else {
-		    if ($d->{crm}) {
-			$d->{crm_env}->log('info', "killed by poweroff");
-			$d->{crm} = undef;
-		    }
-		    if ($d->{lrm}) {
-			$d->{lrm_env}->log('info', "killed by poweroff");
-			$d->{lrm} = undef;
-			$d->{lrm_restart} = undef;
-		    }
-		    $self->watchdog_reset_nolock($node);
-		    $self->write_service_status($node, {});
-		}
-	    }
-
-	    $cstatus->{$node}->{power} = $action;
-	    $cstatus->{$node}->{network} = $action;
-	    $cstatus->{$node}->{shutdown} = undef;
-
-	    $self->write_hardware_status_nolock($cstatus);
-
-	} elsif ($cmd eq 'network') {
-	    die "sim_hardware_cmd: unknown network action '$action'"
-		if $action !~ m/^(on|off)$/;
-	    $cstatus->{$node}->{network} = $action;
-
-	    $self->write_hardware_status_nolock($cstatus);
-
-	} elsif ($cmd eq 'reboot' || $cmd eq 'shutdown') {
-	    $cstatus->{$node}->{shutdown} = $cmd;
-
-	    $self->write_hardware_status_nolock($cstatus);
-
-	    $d->{lrm}->shutdown_request() if $d->{lrm};
-	} elsif ($cmd eq 'restart-lrm') {
-	    if ($d->{lrm}) {
-		$d->{lrm_restart} = 1;
-		$d->{lrm}->shutdown_request();
-	    }
-	} elsif ($cmd eq 'crm') {
-
-	    if ($action eq 'stop') {
-		if ($d->{crm}) {
-		    $d->{crm_stop} = 1;
-		    $d->{crm}->shutdown_request();
-		}
-	    } elsif ($action eq 'start') {
-		$d->{crm} = PVE::HA::CRM->new($d->{crm_env}) if !$d->{crm};
-	    } else {
-		die "sim_hardware_cmd: unknown action '$action'";
-	    }
-
-	} elsif ($cmd eq 'service') {
-	    if ($action eq 'started' || $action eq 'disabled' || $action eq 'stopped') {
-
-		$self->set_service_state($sid, $action);
-
-	    } elsif ($action eq 'migrate' || $action eq 'relocate') {
-
-		die "sim_hardware_cmd: missing target node for '$action' command"
-		    if !$target;
-
-		$self->queue_crm_commands_nolock("$action $sid $target");
-
-	    } elsif ($action eq 'add') {
-
-		$self->add_service($sid, {state => 'started', node => $target});
-
-	    } elsif ($action eq 'delete') {
-
-		$self->delete_service($sid);
-
-	    } elsif ($action eq 'lock') {
-
-		$self->lock_service($sid, $target);
-
-	    } elsif ($action eq 'unlock') {
-
-		$self->unlock_service($sid, $target);
-
-	    } else {
-		die "sim_hardware_cmd: unknown service action '$action' " .
-		    "- not implemented\n"
-	    }
-	} else {
-	    die "sim_hardware_cmd: unknown command '$cmdstr'\n";
-	}
-
-    };
-
-    return $self->global_lock($code);
 }
 
 sub run {
-- 
2.1.4





More information about the pve-devel mailing list