line |
stmt |
code |
1
|
|
# Copyright 2021 SUSE LLC |
2
|
|
# SPDX-License-Identifier: GPL-2.0-or-later |
3
|
|
|
4
|
|
|
5
|
|
use Mojo::Base 'backend::virt', -signatures; |
6
|
1
|
use bmwqemu; |
|
1
|
|
|
1
|
|
7
|
1
|
use Mojo::File; |
|
1
|
|
|
1
|
|
8
|
1
|
use Cwd qw(abs_path); |
|
1
|
|
|
1
|
|
9
|
1
|
use File::Temp; |
|
1
|
|
|
1
|
|
10
|
1
|
use File::chdir; |
|
1
|
|
|
1
|
|
11
|
1
|
use IPC::Run; |
|
1
|
|
|
1
|
|
12
|
1
|
use Time::Seconds; |
|
1
|
|
|
1
|
|
13
|
1
|
|
|
1
|
|
|
1
|
|
14
|
|
my $self = $class->SUPER::new; |
15
|
10
|
my $vars = \%bmwqemu::vars; |
|
10
|
|
|
10
|
|
16
|
10
|
|
17
|
10
|
$self->{vagrant_cwd} = File::Temp->newdir(); |
18
|
|
$self->{up_timeout} = $vars->{VAGRANT_UP_TIMEOUT} // 300; |
19
|
10
|
$self->{provider} = $vars->{VAGRANT_PROVIDER} // die 'Need variable \'VAGRANT_PROVIDER\''; |
20
|
10
|
$self->{box_name} = $vars->{VAGRANT_BOX} // die 'Need variable \'VAGRANT_BOX\''; |
21
|
10
|
$self->{box_url} = $vars->{VAGRANT_BOX_URL}; |
22
|
10
|
|
23
|
10
|
if (substr($self->{box_name}, 0, 1) eq '/') { |
24
|
|
my $asset_dir = $vars->{VAGRANT_ASSETDIR} // die 'Need variable \'VAGRANT_ASSETDIR\' when using local vagrant boxes'; |
25
|
10
|
my $box_abs_path = undef; |
26
|
3
|
|
27
|
3
|
opendir(my $dh, $asset_dir) or die "Could not opendir $asset_dir: $!"; |
28
|
|
|
29
|
3
|
my $box_path = abs_path("$asset_dir$self->{box_name}"); |
30
|
|
die "File $box_path does not exist" unless (-e $box_path); |
31
|
2
|
$self->{box_name} = $box_path; |
32
|
2
|
} |
33
|
1
|
|
34
|
|
$self->{libvirt_pool_name} = undef; |
35
|
|
|
36
|
8
|
my $path = Mojo::File::path($self->{vagrant_cwd})->make_path(); |
37
|
|
$self->{vagrantfile} = $path->child("Vagrantfile"); |
38
|
8
|
bmwqemu::diag("Writing Vagrantfile to $self->{vagrantfile}"); |
39
|
8
|
|
40
|
8
|
my $vagrant_file_contents = <<END; |
41
|
|
Vagrant.configure("2") do |config| |
42
|
8
|
config.vm.box = "$self->{box_name}" |
43
|
|
END |
44
|
|
if (defined($self->{box_url})) { |
45
|
|
$vagrant_file_contents .= <<END; |
46
|
8
|
config.vm.box_url = "$self->{box_url}" |
47
|
1
|
END |
48
|
|
} |
49
|
|
$vagrant_file_contents .= <<END; |
50
|
|
config.vm.synced_folder ".", "/vagrant", disabled: true |
51
|
8
|
END |
52
|
|
|
53
|
|
|
54
|
|
if ($self->{provider} eq 'virtualbox') { |
55
|
|
$vagrant_file_contents .= <<END; |
56
|
8
|
config.vm.provider "virtualbox" do |v| |
57
|
3
|
v.memory = $vars->{QEMURAM} |
58
|
|
v.cpus = $vars->{QEMUCPUS} |
59
|
|
end |
60
|
|
END |
61
|
|
} elsif ($self->{provider} eq 'libvirt') { |
62
|
|
$self->{libvirt_storage_pool_path} = "$self->{vagrant_cwd}/pool"; |
63
|
|
mkdir $self->{libvirt_storage_pool_path}; |
64
|
4
|
$self->{libvirt_pool_name} = "vagrant" . int(rand(100000)); |
65
|
4
|
|
66
|
4
|
$vagrant_file_contents .= <<END; |
67
|
|
config.vm.provider :libvirt do |libvirt| |
68
|
4
|
libvirt.cpus = $vars->{QEMUCPUS} |
69
|
|
libvirt.memory = $vars->{QEMURAM} |
70
|
|
libvirt.storage_pool_name = "$self->{libvirt_pool_name}" |
71
|
|
end |
72
|
|
END |
73
|
|
} else { |
74
|
|
die "got an unknown vagrant provider $self->{provider}"; |
75
|
|
} |
76
|
1
|
|
77
|
|
$vagrant_file_contents .= <<END; |
78
|
|
end |
79
|
7
|
END |
80
|
|
|
81
|
|
$self->{vagrantfile}->spurt($vagrant_file_contents); |
82
|
|
|
83
|
7
|
return $self; |
84
|
|
} |
85
|
7
|
|
86
|
|
my ($retval, $stdin, $stdout, $stderr); |
87
|
|
|
88
|
31
|
my @vagrant_cmd = ("vagrant", $args->{cmd}); |
|
31
|
|
|
31
|
|
|
31
|
|
89
|
31
|
push(@vagrant_cmd, ("--machine-readable")) unless $args->{not_machine_readable}; |
90
|
|
push @vagrant_cmd, @{$args->{extra_args}} if defined $args->{extra_args}; |
91
|
31
|
my $timeout = $args->{timeout} // ONE_MINUTE; |
92
|
31
|
|
93
|
31
|
bmwqemu::diag("Invoking vagrant command: @vagrant_cmd"); |
|
17
|
|
94
|
31
|
{ |
95
|
|
local $CWD = $self->{vagrant_cwd}; |
96
|
31
|
my $handle = IPC::Run::start(\@vagrant_cmd, \$stdin, \$stdout, \$stderr, IPC::Run::timeout($timeout)); |
97
|
|
IPC::Run::finish($handle); |
98
|
31
|
$retval = $handle->full_result(0); |
|
31
|
|
99
|
31
|
} |
100
|
31
|
|
101
|
31
|
return {retval => $retval, stdout => $stdout, stderr => $stderr}; |
102
|
|
} |
103
|
|
|
104
|
31
|
my $vagrant_ssh_conf_res = $self->run_vagrant_command({cmd => "ssh-config", not_machine_readable => 1}); |
105
|
|
die "obtaining the ssh config failed!" unless $vagrant_ssh_conf_res->{retval} == 0; |
106
|
|
my $stdout = $vagrant_ssh_conf_res->{stdout}; |
107
|
5
|
my %con_creds = ( |
|
5
|
|
|
5
|
|
108
|
5
|
hostname => "localhost", |
109
|
5
|
username => "vagrant", |
110
|
5
|
password => "vagrant", |
111
|
5
|
port => 22 |
112
|
|
); |
113
|
|
|
114
|
|
if ($stdout =~ m/\w*HostName (.*)/) { |
115
|
|
$con_creds{hostname} = $1; |
116
|
|
} |
117
|
|
if ($stdout =~ m/\w*User (.*)/) { |
118
|
5
|
$con_creds{username} = $1; |
119
|
1
|
} |
120
|
|
if ($stdout =~ m/\w*Port (\d+)/) { |
121
|
5
|
$con_creds{port} = $1; |
122
|
1
|
} |
123
|
|
return %con_creds; |
124
|
5
|
} |
125
|
1
|
|
126
|
|
if (defined($self->{libvirt_pool_name})) { |
127
|
5
|
my ($stdout, $stderr, $virsh_res); |
128
|
|
|
129
|
|
my @virsh_cmd = ("virsh", "pool-create-as", "--target", $self->{libvirt_storage_pool_path}, "--name", $self->{libvirt_pool_name}, "--type", "dir"); |
130
|
5
|
my $handle = IPC::Run::start(\@virsh_cmd, \undef, \$stdout, \$stderr); |
|
5
|
|
|
5
|
|
131
|
5
|
IPC::Run::finish($handle); |
132
|
4
|
$virsh_res = $handle->full_result(0); |
133
|
|
|
134
|
4
|
# don't die in case that the storage pool already exists, but die if |
135
|
4
|
# there's a different error |
136
|
4
|
my $re = qr/pool '$self->{libvirt_pool_name}' already exists with uuid/; |
137
|
4
|
die "Create libvirt storage pool failed with exit code: $virsh_res\n, $stdout\n, $stderr\n" |
138
|
|
if (($virsh_res != 0) && !($stderr =~ m/$re/)); |
139
|
|
} |
140
|
|
|
141
|
4
|
my @prov = ("--provider", $self->{provider}); |
142
|
4
|
my $args = {cmd => "up", extra_args => \@prov, timeout => $self->{up_timeout}}; |
143
|
|
|
144
|
|
my $res = $self->run_vagrant_command($args); |
145
|
|
die "Failed to execute vagrant up, got:\n$res->{stdout}\n\n$res->{stderr}\n" |
146
|
4
|
unless $res->{retval} == 0; |
147
|
4
|
|
148
|
|
my %ssh_creds = $self->get_ssh_credentials(); |
149
|
4
|
my $ssh = $testapi::distri->add_console('vagrant-ssh', 'ssh-serial', \%ssh_creds); |
150
|
|
$ssh->backend($self); |
151
|
4
|
|
152
|
|
return {}; |
153
|
3
|
} |
154
|
3
|
|
155
|
3
|
my $res = $self->run_vagrant_command({cmd => "halt"}); |
156
|
|
if ($res->{retval} != 0) { |
157
|
3
|
bmwqemu::fctwarn("vagrant: failed to execute vagrant halt, got $res->{retval},\n$res->{stdout}\n$res->{stderr}"); |
158
|
|
} |
159
|
|
|
160
|
6
|
my @extra_args = ("-f"); |
|
6
|
|
|
6
|
|
161
|
6
|
my $destroy_res = $self->run_vagrant_command({cmd => "destroy", extra_args => \@extra_args}); |
162
|
6
|
if ($destroy_res->{retval} != 0) { |
163
|
1
|
bmwqemu::fctwarn("vagrant: failed to destroy the vagrant VM, got:\n$destroy_res->{stdout}\n$destroy_res->{stderr}"); |
164
|
|
} |
165
|
|
|
166
|
6
|
# ensure that the box is gone: |
167
|
6
|
my $extra_remove_args = ["remove", "-af", "--provider", $self->{provider}, $self->{box_name}]; |
168
|
6
|
my $box_remove_res = $self->run_vagrant_command({cmd => "box", extra_args => $extra_remove_args}); |
169
|
1
|
if ($box_remove_res->{retval} != 0) { |
170
|
|
bmwqemu::fctwarn("vagrant: failed to destroy the vagrant box $self->{box_name}, got:\n$box_remove_res->{stdout}\n$box_remove_res->{stderr}"); |
171
|
|
} |
172
|
|
|
173
|
6
|
if (defined($self->{libvirt_pool_name})) { |
174
|
6
|
my ($stdout, $stderr, $virsh_res); |
175
|
6
|
my @virsh_cmd = ("virsh", "pool-destroy", $self->{libvirt_pool_name}); |
176
|
1
|
my $handle = IPC::Run::start(\@virsh_cmd, \undef, \$stdout, \$stderr); |
177
|
|
IPC::Run::finish($handle); |
178
|
|
$virsh_res = $handle->full_result(0); |
179
|
6
|
|
180
|
5
|
if ($virsh_res != 0) { |
181
|
5
|
bmwqemu::fctwarn("vagrant: failed to destroy the libvirt storage pool $self->{libvirt_pool_name}, got $virsh_res\n$stdout\n$stderr"); |
182
|
5
|
} |
183
|
5
|
} |
184
|
5
|
} |
185
|
|
|
186
|
5
|
my @args = ('--', split(/ /, $cmd)); |
187
|
1
|
my $res = $self->run_vagrant_command({cmd => "ssh", not_machine_readable => 1, extra_args => \@args}); |
188
|
|
|
189
|
|
chomp $res->{stdout}; |
190
|
|
return $res->{stdout}; |
191
|
|
} |
192
|
1
|
|
|
1
|
|
|
1
|
|
|
1
|
|
193
|
1
|
|
194
|
1
|
my $res = $self->run_vagrant_command({cmd => "status", timeout => 5}); |
195
|
|
chomp($res->{stdout}); |
196
|
1
|
return $res->{stdout} =~ /default,state,(shutoff|not_created|poweroff)/; |
197
|
1
|
} |
198
|
|
|
199
|
|
|
200
|
1
|
|
|
1
|
|
201
|
|
1; |