]> git.proxmox.com Git - pve-ha-manager.git/blob - PVE/HA/Sim/RTEnv.pm
implement online migration - first try
[pve-ha-manager.git] / PVE / HA / Sim / RTEnv.pm
1 package PVE::HA::Sim::RTEnv;
2
3 use strict;
4 use warnings;
5 use POSIX qw(strftime EINTR);
6 use Data::Dumper;
7 use JSON;
8 use IO::File;
9 use Fcntl qw(:DEFAULT :flock);
10
11 use PVE::HA::Tools;
12
13 use base qw(PVE::HA::Sim::Env);
14
15 sub new {
16 my ($this, $nodename, $hardware, $log_id) = @_;
17
18 my $class = ref($this) || $this;
19
20 my $self = $class->SUPER::new($nodename, $hardware, $log_id);
21
22 return $self;
23 }
24
25 sub get_time {
26 my ($self) = @_;
27
28 return time();
29 }
30
31 sub log {
32 my ($self, $level, $msg) = @_;
33
34 chomp $msg;
35
36 my $time = $self->get_time();
37
38 printf("%-5s %10s %12s: $msg\n", $level, strftime("%H:%M:%S", localtime($time)),
39 "$self->{nodename}/$self->{log_id}");
40 }
41
42 sub sleep {
43 my ($self, $delay) = @_;
44
45 CORE::sleep($delay);
46 }
47
48 sub sleep_until {
49 my ($self, $end_time) = @_;
50
51 for (;;) {
52 my $cur_time = time();
53
54 last if $cur_time >= $end_time;
55
56 $self->sleep(1);
57 }
58 }
59
60 sub loop_start_hook {
61 my ($self) = @_;
62
63 $self->{loop_start} = $self->get_time();
64 }
65
66 sub loop_end_hook {
67 my ($self) = @_;
68
69 my $delay = $self->get_time() - $self->{loop_start};
70
71 die "loop take too long ($delay seconds)\n" if $delay > 30;
72 }
73
74 sub exec_resource_agent {
75 my ($self, $sid, $cmd, @params) = @_;
76
77 my $hardware = $self->{hardware};
78
79 my $nodename = $self->{nodename};
80
81 my $sc = $hardware->read_service_config($nodename);
82
83 # fixme: return valid_exit code (instead of using die)
84 my $cd = $sc->{$sid};
85 die "no such service" if !$cd;
86
87 my $ss = $hardware->read_service_status($nodename);
88
89 if ($cmd eq 'started') {
90
91 # fixme: return valid_exit code
92 die "service '$sid' not on this node" if $cd->{node} ne $nodename;
93
94 if ($ss->{$sid}) {
95 $self->log("info", "service status $sid: running");
96 return 0;
97 }
98 $self->log("info", "starting service $sid");
99
100 $self->sleep(2);
101
102 $ss->{$sid} = 1;
103 $hardware->write_service_status($nodename, $ss);
104
105 $self->log("info", "service $sid started");
106
107 return 0;
108
109 } elsif ($cmd eq 'request_stop' || $cmd eq 'stopped') {
110
111 # fixme: return valid_exit code
112 die "service '$sid' not on this node" if $cd->{node} ne $nodename;
113
114 if (!$ss->{$sid}) {
115 $self->log("info", "service status $sid: stopped");
116 return 0;
117 }
118 $self->log("info", "stopping service $sid");
119
120 $self->sleep(2);
121
122 $ss->{$sid} = 0;
123 $hardware->write_service_status($nodename, $ss);
124
125 $self->log("info", "service $sid stopped");
126
127 return 0;
128
129 } elsif ($cmd eq 'migrate') {
130
131 my $target = $params[0];
132 die "migrate '$sid' failed - missing target\n" if !defined($target);
133
134 if ($cd->{node} eq $target) {
135 # already migrate
136 return 0;
137 } elsif ($cd->{node} eq $nodename) {
138
139 $self->log("info", "service $sid - start migrtaion to node '$target'");
140 $self->sleep(2);
141 $self->change_service_location($sid, $target);
142 $self->log("info", "service $sid - end migrtaion to node '$target'");
143
144 return 0;
145
146 } else {
147 die "migrate '$sid' failed - service is not on this node\n";
148 }
149
150
151 }
152
153 die "implement me (cmd '$cmd')";
154 }
155
156 1;