Permalink
Browse files

Translate block device arrayrefs to hashrefs

Restructure the output of `lsblk --json` to convert arrayrefs of block
device hashrefs to hashrefs of block device hashrefs, indexed by the
block device name, to avoid an error with array processing raised by
ELK:

> <haxmeister> the error I see is "elastic search has limited support for arrays"

Because devices usually have at least one level of sub-devices (logical
partitions), and can have even more (e.g. encrypted devices), this needs
to be done recursively, here implemented with an iterative breadth-first
search over the whole tree.

This restructuring does require that each device hashref has a "name"
member with a unique value to form the index of the transformed hashref.
It should print a warning if this is not the case or the data is in any
other way formed in an unexpected way.

None of this may be needed if we end up writing our own parser over
`/sys/devices/.../block` per GitHub issue #47, but it was fun to write
anyway.

This should hopefully resolve GitHub issue #46.
  • Loading branch information...
Tom Ryder
Tom Ryder committed Mar 2, 2018
1 parent 857db52 commit b4a4f167b2f7f1287e8ad6ff9194238fe65f85b0
Showing with 80 additions and 2 deletions.
  1. +80 −2 lib/Funtoo/Report.pm
@@ -409,8 +409,86 @@ sub get_filesystem_info{
my $json_from_lsblk =
`lsblk --json -o NAME,FSTYPE,SIZE,MOUNTPOINT,PARTTYPE,RM,HOTPLUG,TRAN`;
my $data = decode_json($json_from_lsblk);
my %hash = %$data;
return \%hash;
# we need to recursively transform the arrayref-of-hashref structures in
# this output into hashrefs-of-hashrefs, indexed by the 'name' of each item
# start a stack of references to objects to transform
my @stack;
# dispatch table of reference type to transformation method
my %disp = (
# pass hashes through unscathed, enqueuing all their values
HASH => sub {
my $obj = shift;
for my $value (values %{ $obj }) {
push @stack, \$value;
}
return $obj;
},
# convert an arrayref of hashrefs in-place into a hashref by the "name"
# member of each hashref, and enqueue all the original items
ARRAY => sub {
my $obj = shift;
# start replacement hash
my %rep;
# iterate over the list items
for my $item (@{ $obj }) {
# ensure we can actually translate this item, warn and skip it
# if we can't
eval {
my $type = ref $item
or die;
$type eq 'HASH'
or die;
exists $item->{name}
or die;
not exists $rep{$item->{name}}
or die;
# item passes muster, put it into the replacement hash
$rep{$item->{name}} = $item;
push @stack, \$item;
} or warn "Failed arrayref item conversion\n";
}
# return a reference to the replacement hash, not the original
# arrayref; we discard that
return \%rep;
},
);
# start with the root node on the stack
push @stack, \$data;
# iterative walk through the tree
while (@stack) {
# pop a reference off the stack
my $ref = pop @stack;
# get the object it points to
my $obj = ${ $ref };
# skip any object that is not itself a reference
my $type = ref $obj
or next;
# skip any object for which we don't have a handler defined
exists $disp{$type}
or next;
# repoint the reference to the outcome of this type's dispatch method
${ $ref } = $disp{$type}->($obj);
}
return $data;
}
##
## fetching active profiles

0 comments on commit b4a4f16

Please sign in to comment.