]> git.proxmox.com Git - pve-ha-manager.git/blame - src/PVE/HA/Resources/PVEVM.pm
Add timeout parameter for shutdown
[pve-ha-manager.git] / src / PVE / HA / Resources / PVEVM.pm
CommitLineData
21ce53c3
TL
1package PVE::HA::Resources::PVEVM;
2
3use strict;
4use warnings;
5
33783485
TL
6use PVE::HA::Tools;
7
a1c88626
WB
8BEGIN {
9 if (!$ENV{PVE_GENERATING_DOCS}) {
10 require PVE::QemuConfig;
11 import PVE::QemuConfig;
12 require PVE::QemuServer;
13 import PVE::QemuServer;
14 require PVE::API2::Qemu;
15 import PVE::API2::Qemu;
16 }
17}
21ce53c3
TL
18
19use base qw(PVE::HA::Resources);
20
21sub type {
22 return 'vm';
23}
24
25sub verify_name {
26 my ($class, $name) = @_;
27
28 die "invalid VMID\n" if $name !~ m/^[1-9][0-9]+$/;
29}
30
31sub options {
32 return {
33 state => { optional => 1 },
34 group => { optional => 1 },
35 comment => { optional => 1 },
36 max_restart => { optional => 1 },
37 max_relocate => { optional => 1 },
38 };
39}
40
41sub config_file {
42 my ($class, $vmid, $nodename) = @_;
43
94cedf0f 44 return PVE::QemuConfig->config_file($vmid, $nodename);
21ce53c3
TL
45}
46
47sub exists {
48 my ($class, $vmid, $noerr) = @_;
49
50 my $vmlist = PVE::Cluster::get_vmlist();
51
52 if(!defined($vmlist->{ids}->{$vmid})) {
53 die "resource 'vm:$vmid' does not exists in cluster\n" if !$noerr;
54 return undef;
55 } else {
56 return 1;
57 }
58}
59
60sub start {
61 my ($class, $haenv, $id) = @_;
62
63 my $nodename = $haenv->nodename();
64
65 my $params = {
66 node => $nodename,
67 vmid => $id
68 };
69
70 my $upid = PVE::API2::Qemu->vm_start($params);
33783485 71 PVE::HA::Tools::upid_wait($upid, $haenv);
21ce53c3
TL
72}
73
74sub shutdown {
e4ef317d 75 my ($class, $haenv, $id, $timeout) = @_;
21ce53c3
TL
76
77 my $nodename = $haenv->nodename();
e4ef317d 78 my $shutdown_timeout = $timeout // 60;
21ce53c3 79
e4ef317d 80 my $upid;
21ce53c3
TL
81 my $params = {
82 node => $nodename,
83 vmid => $id,
21ce53c3
TL
84 };
85
e4ef317d
FE
86 if ($shutdown_timeout) {
87 $params->{timeout} = $shutdown_timeout;
88 $params->{forceStop} = 1;
89 $upid = PVE::API2::Qemu->vm_shutdown($params);
90 } else {
91 $upid = PVE::API2::Qemu->vm_stop($params);
92 }
93
33783485 94 PVE::HA::Tools::upid_wait($upid, $haenv);
21ce53c3
TL
95}
96
21ce53c3
TL
97sub migrate {
98 my ($class, $haenv, $id, $target, $online) = @_;
99
100 my $nodename = $haenv->nodename();
101
102 my $params = {
103 node => $nodename,
104 vmid => $id,
6e8b0c22
TL
105 # bug #2241 forces is for local resource only, people can ensure that
106 # different host have the same hardware, so this can be fine, and qemu
107 # knows when not, so can only win here
108 force => 1,
21ce53c3
TL
109 target => $target,
110 online => $online,
111 };
112
113 # explicitly shutdown if $online isn't true (relocate)
0d5906f3 114 if (!$online && $class->check_running($haenv, $id)) {
21ce53c3
TL
115 $class->shutdown($haenv, $id);
116 }
117
ea28f873
TL
118 my $oldconfig = $class->config_file($id, $nodename);
119
21ce53c3 120 my $upid = PVE::API2::Qemu->migrate_vm($params);
33783485 121 PVE::HA::Tools::upid_wait($upid, $haenv);
ea28f873
TL
122
123 # check if vm really moved
124 return !(-f $oldconfig);
21ce53c3
TL
125}
126
127sub check_running {
0d5906f3 128 my ($class, $haenv, $vmid) = @_;
21ce53c3 129
0d5906f3
TL
130 my $nodename = $haenv->nodename();
131
bc2a9d18
TL
132 if (PVE::QemuServer::check_running($vmid, 1, $nodename)) {
133 # do not count VMs which are suspended for a backup job as running
134 my $conf = PVE::QemuConfig->load_config($vmid, $nodename);
135 if (defined($conf->{lock}) && $conf->{lock} eq 'backup') {
a9a49e32
TL
136 my $qmpstatus = eval {
137 PVE::QemuServer::vm_qmp_command($vmid, { execute => 'query-status' })
138 };
139 warn "$@\n" if $@;
140
141 return 0 if defined($qmpstatus) && $qmpstatus->{status} eq 'prelaunch';
bc2a9d18
TL
142 }
143
144 return 1;
145 } else {
146 return 0;
147 }
21ce53c3
TL
148}
149
5dd3ed86
TL
150sub remove_locks {
151 my ($self, $haenv, $id, $locks, $service_node) = @_;
152
153 $service_node = $service_node || $haenv->nodename();
154
155 my $conf = PVE::QemuConfig->load_config($id, $service_node);
156
157 return undef if !defined($conf->{lock});
158
159 foreach my $lock (@$locks) {
160 if ($conf->{lock} eq $lock) {
161 delete $conf->{lock};
162
163 my $cfspath = PVE::QemuConfig->cfs_config_path($id, $service_node);
164 PVE::Cluster::cfs_write_file($cfspath, $conf);
165
166 return $lock;
167 }
168 }
169
170 return undef;
171}
172
21ce53c3 1731;