line |
stmt |
code |
1
|
|
# Copyright 2016-2020 SUSE LLC |
2
|
|
# SPDX-License-Identifier: GPL-2.0-or-later |
3
|
|
|
4
|
|
# this backend uses a KVM connector speaking VNC and external tools |
5
|
|
# for serial line and power cycling |
6
|
|
|
7
|
|
|
8
|
|
use Mojo::Base 'backend::baseclass', -signatures; |
9
|
1
|
use autodie ':all'; |
|
1
|
|
|
1
|
|
10
|
1
|
use bmwqemu; |
|
1
|
|
|
1
|
|
11
|
1
|
use IPC::Run (); |
|
1
|
|
|
1
|
|
12
|
1
|
require IPC::System::Simple; |
|
1
|
|
|
1
|
|
13
|
|
use File::Basename 'basename'; |
14
|
1
|
use Mojo::IOLoop::ReadWriteProcess::Session 'session'; |
|
1
|
|
|
1
|
|
15
|
1
|
|
|
1
|
|
|
1
|
|
16
|
|
# required for the tests to access our HTTP port |
17
|
2
|
defined $bmwqemu::vars{WORKER_HOSTNAME} or die 'Need variable WORKER_HOSTNAME'; |
|
2
|
|
|
2
|
|
18
|
|
return $class->SUPER::new; |
19
|
2
|
} |
20
|
1
|
|
21
|
|
my $dir = $bmwqemu::vars{GENERAL_HW_CMD_DIR} or die 'Need variable GENERAL_HW_CMD_DIR'; |
22
|
|
die 'GENERAL_HW_CMD_DIR is not pointing to a directory' unless -d $dir; |
23
|
12
|
|
|
12
|
|
|
12
|
|
|
12
|
|
24
|
12
|
my %GENERAL_HW_ARG_VARIABLES_BY_CMD = ( |
25
|
12
|
'GENERAL_HW_FLASH_CMD' => 'GENERAL_HW_FLASH_ARGS', |
26
|
|
'GENERAL_HW_SOL_CMD' => 'GENERAL_HW_SOL_ARGS', |
27
|
11
|
'GENERAL_HW_INPUT_CMD' => 'GENERAL_HW_INPUT_ARGS', |
28
|
|
'GENERAL_HW_POWERON_CMD' => 'GENERAL_HW_POWERON_ARGS', |
29
|
|
'GENERAL_HW_POWEROFF_CMD' => 'GENERAL_HW_POWEROFF_ARGS', |
30
|
|
'GENERAL_HW_IMAGE_CMD' => 'GENERAL_HW_IMAGE_ARGS', |
31
|
|
); |
32
|
|
my $args = $bmwqemu::vars{$GENERAL_HW_ARG_VARIABLES_BY_CMD{$cmd}} if $bmwqemu::vars{$GENERAL_HW_ARG_VARIABLES_BY_CMD{$cmd}}; |
33
|
|
|
34
|
|
$cmd = $bmwqemu::vars{$cmd} or die "Need test variable '$cmd'"; |
35
|
11
|
$cmd = "$dir/" . basename($cmd); |
36
|
|
$cmd .= " $args" if $args; |
37
|
11
|
return $cmd; |
38
|
11
|
} |
39
|
11
|
|
40
|
11
|
my @full_cmd = split / /, $self->get_cmd($cmd); |
41
|
|
|
42
|
|
push @full_cmd, @extra_args; |
43
|
11
|
|
|
11
|
|
|
11
|
|
|
11
|
|
|
11
|
|
44
|
11
|
my ($stdin, $stdout, $stderr, $ret); |
45
|
|
|
46
|
10
|
{ |
47
|
|
# Do not let the SIGCHLD handler of Mojo::IOLoop::ReadWriteProcess::Session steal the exit code from IPC::Run |
48
|
10
|
local $SIG{CHLD}; |
49
|
|
eval { $ret = IPC::Run::run(\@full_cmd, \$stdin, \$stdout, \$stderr) }; |
50
|
|
die "Unable to run command '@full_cmd' (deduced from test variable $cmd): $@\n" if $@; |
51
|
|
} |
52
|
10
|
chomp $stdout; |
|
10
|
|
53
|
10
|
chomp $stderr; |
|
10
|
|
54
|
10
|
|
55
|
|
die "$cmd: stdout: $stdout, stderr: $stderr" unless $ret; |
56
|
9
|
bmwqemu::diag("IPMI: stdout: $stdout, stderr: $stderr"); |
57
|
9
|
return $stdout; |
58
|
|
} |
59
|
9
|
|
60
|
9
|
$self->run_cmd('GENERAL_HW_POWEROFF_CMD'); |
61
|
9
|
return; |
62
|
|
} |
63
|
|
|
64
|
5
|
$self->poweroff_host; |
|
5
|
|
|
5
|
|
65
|
5
|
sleep(3); |
66
|
5
|
$self->run_cmd('GENERAL_HW_POWERON_CMD'); |
67
|
|
return; |
68
|
|
} |
69
|
2
|
|
|
2
|
|
|
2
|
|
70
|
2
|
if ($args->{action} eq 'on') { |
71
|
2
|
$self->run_cmd('GENERAL_HW_POWERON_CMD'); |
72
|
2
|
} elsif ($args->{action} eq 'off') { |
73
|
2
|
$self->run_cmd('GENERAL_HW_POWEROFF_CMD'); |
74
|
|
} else { |
75
|
|
$self->notimplemented; |
76
|
0
|
} |
|
0
|
|
|
0
|
|
|
0
|
|
77
|
0
|
} |
78
|
0
|
|
79
|
|
if ($self->{vnc}) { |
80
|
0
|
close($self->{vnc}->socket); |
81
|
|
sleep(1); |
82
|
0
|
} |
83
|
|
|
84
|
|
my $vnc = $testapi::distri->add_console( |
85
|
|
'sut', |
86
|
1
|
'vnc-base', |
|
1
|
|
|
1
|
|
87
|
1
|
{ |
88
|
0
|
hostname => $bmwqemu::vars{GENERAL_HW_VNC_IP} || die('Need variable GENERAL_HW_VNC_IP'), |
89
|
0
|
port => $bmwqemu::vars{GENERAL_HW_VNC_PORT} // 5900, |
90
|
|
password => $bmwqemu::vars{GENERAL_HW_VNC_PASSWORD}, |
91
|
|
depth => 16, |
92
|
|
connect_timeout => 50 |
93
|
|
}); |
94
|
|
$vnc->backend($self); |
95
|
|
$self->select_console({testapi_console => 'sut'}); |
96
|
|
|
97
|
|
return 1; |
98
|
|
} |
99
|
1
|
|
100
|
|
my @hdd_args; |
101
|
|
|
102
|
1
|
if ($bmwqemu::vars{HDD_1}) { |
103
|
1
|
my $numdisks = $bmwqemu::vars{NUMDISKS} // 1; |
104
|
|
for my $i (1 .. $numdisks) { |
105
|
1
|
# Pass path of HDD |
106
|
|
push @hdd_args, $bmwqemu::vars{"HDD_$i"} or die 'Need variable HDD_$i'; |
107
|
|
# Pass size of HDD |
108
|
3
|
my $size = $bmwqemu::vars{"HDDSIZEGB_$i"}; |
|
3
|
|
|
3
|
|
109
|
3
|
$size //= $bmwqemu::vars{HDDSIZEGB} // 10; |
110
|
|
push @hdd_args, $size . 'G'; |
111
|
3
|
} |
112
|
3
|
} |
113
|
3
|
return \@hdd_args; |
114
|
|
} |
115
|
4
|
|
116
|
|
|
117
|
4
|
my $input_cmd; |
118
|
4
|
$input_cmd = $self->get_cmd('GENERAL_HW_INPUT_CMD') if ($bmwqemu::vars{GENERAL_HW_INPUT_CMD}); |
119
|
4
|
my $vnc = $testapi::distri->add_console( |
120
|
|
'sut', |
121
|
|
'video-stream', |
122
|
3
|
{ |
123
|
|
url => $bmwqemu::vars{GENERAL_HW_VIDEO_STREAM_URL}, |
124
|
|
connect_timeout => 50, |
125
|
1
|
input_cmd => $input_cmd, |
|
1
|
|
|
1
|
|
126
|
|
edid => $bmwqemu::vars{GENERAL_HW_EDID}, |
127
|
1
|
}); |
128
|
1
|
$vnc->backend($self); |
129
|
|
$self->select_console({testapi_console => 'sut'}); |
130
|
|
|
131
|
|
return 1; |
132
|
|
} |
133
|
|
|
134
|
|
$self->truncate_serial_file; |
135
|
|
if ($bmwqemu::vars{GENERAL_HW_FLASH_CMD}) { |
136
|
|
# Append HDD infos to flash script |
137
|
1
|
my $hdd_args = $self->compute_hdd_args; |
138
|
1
|
|
139
|
1
|
$self->poweroff_host; # Ensure system is off, before flashing |
140
|
|
$self->run_cmd('GENERAL_HW_FLASH_CMD', @$hdd_args); |
141
|
1
|
} |
142
|
|
$self->restart_host; |
143
|
|
$self->relogin_vnc if ($bmwqemu::vars{GENERAL_HW_VNC_IP}); |
144
|
2
|
$self->reconnect_video_stream if ($bmwqemu::vars{GENERAL_HW_VIDEO_STREAM_URL}); |
|
2
|
|
|
2
|
|
145
|
2
|
$self->start_serial_grab if (($bmwqemu::vars{GENERAL_HW_VNC_IP} || $bmwqemu::vars{GENERAL_HW_SOL_CMD}) && !$bmwqemu::vars{GENERAL_HW_NO_SERIAL}); |
146
|
2
|
return {}; |
147
|
|
} |
148
|
2
|
|
149
|
|
$self->poweroff_host; |
150
|
2
|
$self->stop_serial_grab() if (($bmwqemu::vars{GENERAL_HW_VNC_IP} || $bmwqemu::vars{GENERAL_HW_SOL_CMD}) && !$bmwqemu::vars{GENERAL_HW_NO_SERIAL}); |
151
|
2
|
$self->disable_consoles; |
152
|
|
return {}; |
153
|
2
|
} |
154
|
2
|
|
155
|
2
|
return $self->check_ssh_serial($fh) || $self->SUPER::check_socket($fh, $write); |
156
|
2
|
} |
157
|
2
|
|
158
|
|
# serial grab |
159
|
|
|
160
|
1
|
$self->{serialpid} = fork(); |
|
1
|
|
|
1
|
|
161
|
1
|
return unless $self->{serialpid} == 0; |
162
|
1
|
setpgrp 0, 0; |
163
|
1
|
open(my $serial, '>', $self->{serialfile}); |
164
|
1
|
open(STDOUT, ">&", $serial); |
165
|
|
open(STDERR, ">&", $serial); |
166
|
|
exec($self->get_cmd('GENERAL_HW_SOL_CMD')); |
167
|
0
|
die "exec failed $!"; |
|
0
|
|
|
0
|
|
|
0
|
|
|
0
|
|
168
|
0
|
} |
169
|
|
|
170
|
|
return unless $self->{serialpid}; |
171
|
|
kill("-TERM", $self->{serialpid}); |
172
|
|
return waitpid($self->{serialpid}, 0); |
173
|
0
|
} |
|
0
|
|
|
0
|
|
174
|
0
|
|
175
|
0
|
# serial grab end |
176
|
0
|
|
177
|
0
|
my $name = $args->{name}; |
178
|
0
|
my $img_dir = $args->{dir}; |
179
|
0
|
my $hdd_num = $args->{hdd_num} - 1; |
180
|
0
|
die "extracting pflash vars not supported" if $args->{pflash_vars}; |
181
|
0
|
|
182
|
|
$self->run_cmd('GENERAL_HW_IMAGE_CMD', ($hdd_num, "$img_dir/$name")); |
183
|
|
} |
184
|
1
|
|
|
1
|
|
|
1
|
|
185
|
1
|
1; |