File Coverage

blib/lib/StorageDisplay/Data/Libvirt.pm
Criterion Covered Total %
statement 56 59 94.9
branch 3 6 50.0
condition 4 6 66.6
subroutine 15 15 100.0
pod 0 7 0.0
total 78 93 83.8


line stmt bran cond sub pod time code
1             #
2             # This file is part of StorageDisplay
3             #
4             # This software is copyright (c) 2014-2023 by Vincent Danjean.
5             #
6             # This is free software; you can redistribute it and/or modify it under
7             # the same terms as the Perl 5 programming language system itself.
8             #
9 9     9   70 use strict;
  9         24  
  9         430  
10 9     9   67 use warnings;
  9         21  
  9         1055  
11              
12             package StorageDisplay::Data::Libvirt;
13             # ABSTRACT: Handle Libvirt data for StorageDisplay
14              
15             our $VERSION = '2.06'; # VERSION
16              
17 9     9   72 use Moose;
  9         42  
  9         112  
18 9     9   83771 use namespace::sweep;
  9         23  
  9         129  
19             extends 'StorageDisplay::Data::Elem';
20              
21             with (
22             'StorageDisplay::Role::Style::IsSubGraph',
23             'StorageDisplay::Role::Style::Grey',
24             );
25              
26             around BUILDARGS => sub {
27             my $orig = shift;
28             my $class = shift;
29             my $st = shift;
30              
31             #$st->get_infos
32             $st->log('Creating libvirt virtual machines');
33              
34             my $info = $st->get_info('libvirt');
35              
36             return $class->$orig(
37             'ignore_name' => 1,
38             'consume' => [],
39             'st' => $st,
40             'vms' => [ sort { $b cmp $a } keys %{$info} ],
41             @_
42             );
43             };
44              
45             sub BUILD {
46 7     7 0 12133 my $self=shift;
47 7         60 my $args=shift;
48 7         25 my $st = $args->{st};
49              
50 7         19 foreach my $vm (@{$args->{'vms'}}) {
  7         30  
51 35         160 my $d = $self->newChild('Libvirt::VM', $st, $vm);
52             }
53              
54 7         35 return $self;
55             };
56              
57             sub dname {
58 7     7 0 27 my $self=shift;
59 7         47 return 'Libvirt Virtual Machines';
60             }
61              
62             sub dotLabel {
63 14     14 0 36 my $self = shift;
64 14         53 return 'Libvirt Virtual Machines';
65             }
66              
67             1;
68              
69             ##################################################################
70             package StorageDisplay::Data::Libvirt::VM;
71              
72 9     9   4354 use Moose;
  9         26  
  9         81  
73 9     9   81729 use namespace::sweep;
  9         27  
  9         91  
74             extends 'StorageDisplay::Data::Elem';
75              
76             with (
77             'StorageDisplay::Role::Style::IsSubGraph',
78             'StorageDisplay::Role::Style::SubInternal',
79             );
80              
81             has 'vmname' => (
82             is => 'ro',
83             isa => 'Str',
84             required => 1,
85             );
86              
87             has 'state' => (
88             is => 'ro',
89             isa => 'Maybe[Str]',
90             required => 1,
91             );
92              
93             has 'hostname' => (
94             is => 'rw',
95             isa => 'Str',
96             required => 0,
97             predicate => 'has_hostname',
98             );
99              
100             around BUILDARGS => sub {
101             my $orig = shift;
102             my $class = shift;
103             my $st = shift;
104             my $vm = shift;
105              
106             my $vminfo = $st->get_info('libvirt', $vm) // {};
107              
108             $st->log({level=>1}, $vm);
109              
110             return $class->$orig(
111             'name' => $vm,
112             'vmname' => $vm,
113             'consume' => [],
114             'st' => $st,
115             'vm-info' => $vminfo,
116             'state' => $vminfo->{state},
117             @_
118             );
119             };
120              
121             sub BUILD {
122 35     35 0 74079 my $self=shift;
123 35         85 my $args=shift;
124 35   100     272 my $blocks=$args->{'vm-info'}->{'blocks'} // {};
125              
126 35   50     242 my $ga_disks=$args->{'vm-info'}->{ga}->{disks} // {};
127              
128 35 50       182 if (exists($args->{'vm-info'}->{ga}->{hostname})) {
129 0         0 $self->hostname($args->{'vm-info'}->{ga}->{hostname});
130             }
131              
132 35         132 foreach my $disk (sort keys %{$blocks}) {
  35         206  
133             $self->newChild(
134             'Libvirt::VM::Block',
135             $self, $args->{'st'}, $disk, $blocks->{$disk},
136 58   50     571 $ga_disks->{$blocks->{$disk}->{'target'}} // {});
137             }
138 35         204 return $self;
139             };
140              
141             around 'dotStyleNode' => sub {
142             my $orig = shift;
143             my $self = shift;
144             my @text = $self->$orig(@_);
145              
146             if ($self->state // '' eq 'running') {
147             my $color = $self->statecolor('used');
148             push @text, "fillcolor=$color";
149             }
150              
151             return @text;
152             };
153              
154             sub dotLabel {
155 70     70 0 139 my $self = shift;
156 70         3211 my @label = ($self->vmname);
157 70 50       3335 if ($self->has_hostname) {
158 0         0 push @label, "hostname: ".$self->hostname;
159             } else {
160             #push @label, "No QEMU Guest Agent running";
161             }
162 70         344 return @label;
163             }
164              
165             1;
166              
167             ##################################################################
168             package StorageDisplay::Data::Libvirt::VM::Block;
169              
170 9     9   6972 use Moose;
  9         24  
  9         59  
171 9     9   80742 use namespace::sweep;
  9         23  
  9         595  
172             extends 'StorageDisplay::Data::Elem';
173              
174             with (
175             'StorageDisplay::Role::HasBlock',
176             'StorageDisplay::Role::Style::Grey',
177             'StorageDisplay::Role::Style::WithSize' => {
178             -excludes => 'dotStyle',
179             },
180             );
181              
182             has 'target' => (
183             is => 'ro',
184             isa => 'Str',
185             required => 1,
186             );
187              
188             has 'mountpoint' => (
189             is => 'ro',
190             isa => 'Str',
191             required => 0,
192             predicate => 'has_mountpoint',
193             );
194              
195             has 'type' => (
196             is => 'ro',
197             isa => 'Str',
198             required => 1,
199             );
200              
201             has 'vm' => (
202             is => 'ro',
203             isa => 'StorageDisplay::Data::Libvirt::VM',
204             required => 1,
205             );
206              
207             has 'hostdevice' => (
208             is => 'rw',
209             isa => 'Str',
210             required => 0,
211             predicate => 'has_hostdevice',
212             );
213              
214             around BUILDARGS => sub {
215             my $orig = shift;
216             my $class = shift;
217             my $vm = shift;
218             my $st = shift;
219             my $bname = shift;
220             my $binfo = shift;
221             my $gainfo = shift;
222              
223             my $block = $st->block($bname);
224              
225             my @optional_infos;
226              
227             my $consumename=$bname;
228             my $size = 0;
229             if ($binfo->{'type'} eq 'file') {
230             my $fileinfo = $st->get_info('files')->{$bname};
231             my $mountpoint = $fileinfo->{'mountpoint'};
232             if (defined($mountpoint)) {
233             push @optional_infos, 'mountpoint' => $mountpoint;
234             $consumename = $st->fs_mountpoint_blockname($mountpoint);
235             } else {
236             $consumename=undef;
237             }
238             $size = $fileinfo->{'size'} // $size;
239             } elsif ($binfo->{'type'} eq 'block') {
240             eval {
241             # unknown (deleted?) blocks are NoSystem block with no size method
242             $size = $block->size;
243             }
244             }
245             if (defined($consumename)) {
246             my $consumeblock = $st->block($consumename);
247             push @optional_infos, 'consume' => [$consumeblock];
248             #print STDERR$binfo->{'target'}, " consomme ", $consumename, "\n";
249             }
250             if (defined($size)) {
251             $block->size($size);
252             }
253              
254             if (exists($gainfo->{name})) {
255             push @optional_infos, 'hostdevice' => $gainfo->{name};
256             }
257              
258             return $class->$orig(
259             'name' => $binfo->{'target'},
260             'block' => $block,
261             'vm' => $vm,
262             'size' => $size,
263             @optional_infos,
264             'st' => $st,
265             'target' => $binfo->{'target'},
266             'type' => $binfo->{'type'},
267             @_
268             );
269             };
270              
271             around 'dotStyleNode' => sub {
272             my $orig = shift;
273             my $self = shift;
274             my @text = $self->$orig(@_);
275              
276             for my $i (1) { # just to be able to call 'last'
277             if ($self->size == 0) {
278             my $color = $self->statecolor('missing');
279             push @text, "fillcolor=$color";
280             } elsif ($self->type ne 'block') {
281             my $color = $self->statecolor('special');
282             if ($self->type eq 'file') {
283             if ($self->has_mountpoint) {
284             last;
285             }
286             }
287             push @text, "fillcolor=$color";
288             }
289             };
290              
291             return @text;
292             };
293              
294             sub BUILD {
295 58     58 0 145876 my $self=shift;
296 58         117 my $args=shift;
297              
298 58         184 return $self;
299             };
300              
301             sub dotLabel {
302 116     116 0 224 my $self = shift;
303 116         5009 my @label = ($self->block->dname);
304 116 50       5873 if ($self->has_hostdevice) {
305 0         0 push @label, '['.$self->hostdevice.']';
306             } else {
307 116         4484 push @label, '('.$self->target.')';
308             }
309 116         836 return @label;
310             }
311              
312             around 'sizeLabel' => sub {
313             my $orig = shift;
314             my $self = shift;
315             if ($self->size eq 0) {
316             return;
317             }
318             return $self->$orig(@_);
319             };
320              
321             around dotLinks => sub {
322             my $orig = shift;
323             my $self = shift;
324              
325             my @links = $self->$orig(@_);
326             my ($devname, $hostname);
327             if ($self->has_hostdevice) {
328             $devname = $self->hostdevice;
329             $devname =~ s,^/dev/,,;
330             $hostname = $self->vm->hostname;
331             } else {
332             $devname = '('.$self->target.')';
333             $hostname = $self->vm->vmname;
334             }
335             push @links, "// SOURCE LINK: ".$hostname." ".
336             $self->block->size." ".
337             $devname." ".$self->linkname;
338              
339             return @links;
340             };
341              
342             1;
343              
344             __END__
345              
346             =pod
347              
348             =encoding UTF-8
349              
350             =head1 NAME
351              
352             StorageDisplay::Data::Libvirt - Handle Libvirt data for StorageDisplay
353              
354             =head1 VERSION
355              
356             version 2.06
357              
358             =head1 AUTHOR
359              
360             Vincent Danjean <Vincent.Danjean@ens-lyon.org>
361              
362             =head1 COPYRIGHT AND LICENSE
363              
364             This software is copyright (c) 2014-2023 by Vincent Danjean.
365              
366             This is free software; you can redistribute it and/or modify it under
367             the same terms as the Perl 5 programming language system itself.
368              
369             =cut