package Net::Appliance::Frontpanel::CacheBuilderRole; use Moose::Role; with 'Net::Appliance::Frontpanel::Helper::Logger'; use XML::LibXML; use XML::LibXSLT; use File::Temp; has 'xslt_parser' => ( is => 'ro', isa => 'XML::LibXSLT', default => sub { XML::LibXSLT->new() }, lazy => 1, ); has 'xml_parser' => ( is => 'ro', isa => 'XML::LibXML', default => sub { XML::LibXML->new() }, lazy => 1, ); has 'hardware_classes' => ( is => 'ro', isa => 'XML::LibXML::Element', lazy_build => 1, ); sub _build_hardware_classes { my $self = shift; my $parser = $self->xml_parser; my $classes = XML::LibXML::Element->new('classes'); my $p = $parser->parse_file( $self->config->xml_loc('port.xml') ); $classes->appendChild( $_ ) for $p->findnodes('//port-image'); my $m = $parser->parse_file( $self->config->xml_loc('module.xml') ); $classes->appendChild( $_ ) for $m->findnodes('//module'); my $c = $parser->parse_file( $self->config->xml_loc('chassis.xml') ); $classes->appendChild( $_ ) for $c->findnodes('//chassis'); return $classes; } sub transform_and_write_out { my ($self, %args) = @_; my $stylesheet = $self->xslt_parser->parse_stylesheet_file($args{xslt}); my $results = $stylesheet->transform( $self->xml_parser->parse_file($args{xml}) ); $stylesheet->output_file($results, $args{out}); } # munge the name - should be in SNMP::Info ? # this is Cisco-specific. sub munge_port_name { my ($self, $name) = @_; if ($name =~ m{^(?:Te|Gi|Fa)\D*(\d+/\d+(?:/\d+)?)}) { my $num = $1; $name = ( $name =~ m/^Fa/ ? "FastEthernet$num" : $name =~ m/^Gi/ ? "GigabitEthernet$num" : $name =~ m/^Te/ ? "TenGigabitEthernet$num" : $name ); } return $name; } sub build_tree { my ($self, $id, $tree, $seen, %modules) = @_; ++$seen->{$id}; my $mod = $modules{$id}{module}; return if $mod->{class} !~ m/(port|chassis|stack|container|module)/; $self->logger->debug("ITEM pos:[$mod->{pos}] parent:[$mod->{parent}] " ."description[$mod->{description}] name[$mod->{name}] type[$mod->{type}] class[$mod->{class}]"); $mod->{name} = $self->munge_port_name($mod->{name}); my $e = XML::LibXML::Element->new($mod->{class}); $e->setAttribute('type', $mod->{type}); $e->setAttribute('name', $mod->{name}); $tree->appendChild($e); foreach my $kidtype ( keys %{$modules{$id}{children}} ) { foreach my $kid ( @{$modules{$id}{children}{$kidtype}} ) { next if !defined $kid; $self->build_tree($kid, $e, $seen, %modules); } } } sub get_modules { my ($self, $ip) = @_; my %modules; foreach my $mod (@{$self->config->device_modules($ip)}) { $modules{$mod->{index}}{module} = $mod; if ($mod->{parent}) { if ($mod->{pos}) { ${$modules{$mod->{parent}}{children}{$mod->{class}}}[$mod->{pos}] = $mod->{index}; } else { push(@{$modules{$mod->{parent}}{children}{$mod->{class}}}, $mod->{index}); } } else { push(@{$modules{root}}, $mod->{index}); } } return %modules; } # dump device spec as evaluable perl sub make_device_cache { my ($self, $ip) = @_; my %modules = $self->get_modules($ip); my $device = XML::LibXML::Element->new('device'); my $seen = {}; foreach my $id (sort {$a cmp $b} keys %modules) { next if $seen->{$id}; next if !defined $modules{$id}; next if $id eq 'root'; $self->build_tree($id, $device, $seen, %modules); } my $doc = XML::LibXML::Document->new(); my $root = XML::LibXML::Element->new('root'); $doc->setDocumentElement($root); # insert device description XML generated from device_module DB table $root->appendChild($device); # insert module and chassis classes as loaded from shipped XML files $root->appendChild($self->hardware_classes); $doc = $self->xslt_parser->parse_stylesheet_file($self->config->xml_loc('macro.xsl'))->transform($doc); $doc = $self->xslt_parser->parse_stylesheet_file($self->config->xml_loc('entity.xsl'))->transform($doc); # ============================================================================ my $tempdoc = File::Temp->new; $doc->toFile( $tempdoc->filename ); $self->transform_and_write_out( xml => $tempdoc->filename, xslt => $self->config->xml_loc('device-spec2perl.xsl'), out => $self->config->spec_file($ip), ); $tempdoc->DESTROY; } # dump current port-image elements as evaluable perl sub make_ports_cache { my $self = shift; $self->transform_and_write_out( xml => $self->config->xml_loc('port.xml'), xslt => $self->config->xml_loc('port-image2perl.xsl'), out => $self->config->data_loc( $self->config->port_db_file ), ); } sub make_cache_all { my $self = shift; $self->make_ports_cache; $self->make_device_cache($_) for @{$self->config->devices_list}; } no Moose::Role; 1; __END__