You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
460 lines
22 KiB
460 lines
22 KiB
#!/usr/bin/perl |
|
# |
|
# This is the master daemon that manages all periodically run processes on Striker dashboards and Anvil! |
|
# nodes. |
|
# |
|
use strict; |
|
use warnings; |
|
use Anvil::Tools; |
|
|
|
# Turn off buffering so that the pinwheel will display while waiting for the SSH call(s) to complete. |
|
$| = 1; |
|
|
|
my $THIS_FILE = ($0 =~ /^.*\/(.*)$/)[0]; |
|
my $running_directory = ($0 =~ /^(.*?)\/$THIS_FILE$/)[0]; |
|
if (($running_directory =~ /^\./) && ($ENV{PWD})) |
|
{ |
|
$running_directory =~ s/^\./$ENV{PWD}/; |
|
} |
|
|
|
my $anvil = Anvil::Tools->new(); |
|
$anvil->Log->level({set => 2}); |
|
|
|
$anvil->Storage->read_config({file => "/etc/anvil/anvil.conf"}); |
|
my $connections = $anvil->Database->connect({ |
|
sql_file => $anvil->data->{sys}{database}{schema}, |
|
test_table => "network_interfaces", |
|
}); |
|
|
|
print $THIS_FILE." ".__LINE__."; connections: [".$connections."]\n"; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, key => "log_0132", variables => { connections => $connections }}); |
|
if (not $connections) |
|
{ |
|
# No databases, exit. |
|
print $anvil->Words->string({key => "error_0003"}); |
|
$anvil->nice_exit({exit_code => 2}); |
|
} |
|
|
|
report_network($anvil); |
|
|
|
$anvil->nice_exit({exit_code => 0}); |
|
|
|
############################################################################################################# |
|
# Functions # |
|
############################################################################################################# |
|
|
|
# This reports the current network interface states, tracked by the MAC address. |
|
sub report_network |
|
{ |
|
my ($anvil) = @_; |
|
|
|
# Run 'ip addr' to see what IPs are in use. The results will be stored in: |
|
$anvil->System->get_ips(); |
|
|
|
# We'll read through '/sys/class/net' looking for network interfaces. |
|
# * 'sys::network::interface::<iface_name>::ip' - If an IP address is set |
|
# * 'sys::network::interface::<iface_name>::subnet' - If an IP is set |
|
my $directory = "/sys/class/net"; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { directory => $directory }}); |
|
|
|
local(*DIRECTORY); |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0018", variables => { directory => $directory }}); |
|
opendir(DIRECTORY, $directory); |
|
while(my $file = readdir(DIRECTORY)) |
|
{ |
|
next if $file eq "."; |
|
next if $file eq ".."; |
|
next if $file eq "lo"; |
|
next if $file =~ /virbr\d/; |
|
my $full_path = "$directory/$file"; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { full_path => $full_path }}); |
|
if (-d $full_path) |
|
{ |
|
# Pull out the data I want. Note that some of these don't exist with virtio-net interfaces. |
|
my $interface = $file; |
|
my $mac_address = -e $full_path."/address" ? $anvil->Storage->read_file({file => $full_path."/address"}) : ""; |
|
my $link_state = -e $full_path."/carrier" ? $anvil->Storage->read_file({file => $full_path."/carrier"}) : 0; |
|
my $mtu = -e $full_path."/mtu" ? $anvil->Storage->read_file({file => $full_path."/mtu"}) : 0; |
|
my $duplex = -e $full_path."/duplex" ? $anvil->Storage->read_file({file => $full_path."/duplex"}) : "unknown"; # full or half? |
|
my $operational = -e $full_path."/operstate" ? $anvil->Storage->read_file({file => $full_path."/operstate"}) : "unknown"; # up or down |
|
my $speed = $link_state ? $anvil->Storage->read_file({file => $full_path."/speed", debug => 2}) : 0; # Mbps (ie: 1000 = Gbps), gives a very high number for unplugged link |
|
my $media = "unknown"; |
|
my $type = "interface"; |
|
|
|
# These are variables that will be needed if this is a bond interface. |
|
my $ip_address = ""; |
|
my $subnet_mask = ""; |
|
my $bond_mode = ""; |
|
my $primary_slave = ""; |
|
my $primary_reselect = ""; |
|
my $active_slave = ""; |
|
my $mii_polling_interval = ""; |
|
my $up_delay = ""; |
|
my $down_delay = ""; |
|
|
|
if (exists $anvil->data->{sys}{network}{interface}{$interface}) |
|
{ |
|
$ip_address = $anvil->data->{sys}{network}{interface}{$interface}{ip} ? $anvil->data->{sys}{network}{interface}{$interface}{ip} : ""; |
|
$subnet_mask = $anvil->data->{sys}{network}{interface}{$interface}{subnet} ? $anvil->data->{sys}{network}{interface}{$interface}{subnet} : ""; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
ip_address => $ip_address, |
|
subnet_mask => $subnet_mask, |
|
}}); |
|
} |
|
|
|
# If this interface is already a bond slave, the real mac address will be in a |
|
# sub-directory. |
|
my $mac_bond_file = $directory."/".$file."/bonding_slave/perm_hwaddr"; |
|
if (-e $mac_bond_file) |
|
{ |
|
# It's a slave. |
|
$mac_address = $anvil->Storage->read_file({file => $mac_bond_file}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { mac_address => $mac_address }}); |
|
} |
|
|
|
# If this is a virtual interface, set some fake values that don't actually exist on |
|
# the system for the sake of a cleaner display. |
|
if ($mac_address =~ /^52:54:00/) |
|
{ |
|
### Set some fake values. |
|
# Speed is "as fast as possible", so we'll record 100 Gbps, but that is really kind of arbitrary. |
|
$speed = 100000 if not $speed; |
|
$duplex = "full" if not $duplex; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
speed => $speed, |
|
duplex => $duplex, |
|
}}); |
|
} |
|
# If the state is 'down', set the speed to '0'. |
|
if (not $link_state) |
|
{ |
|
$speed = 0; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { speed => $speed }}); |
|
} |
|
|
|
# Is this a bond interface? |
|
if (-e "/proc/net/bonding/".$interface) |
|
{ |
|
# Yup, we'll neet to dig into the bond proc files to get the proper slaved |
|
# interface MAC addresses. |
|
$type = "bond"; |
|
|
|
# Read the bond mode. |
|
$bond_mode = $anvil->Storage->read_file({file => "/sys/devices/virtual/net/".$interface."/bonding/mode"}); |
|
$bond_mode =~ s/\s.*//; |
|
$primary_slave = $anvil->Storage->read_file({file => "/sys/devices/virtual/net/".$interface."/bonding/primary"}); |
|
$primary_reselect = $anvil->Storage->read_file({file => "/sys/devices/virtual/net/".$interface."/bonding/primary_reselect"}); |
|
$primary_reselect =~ s/\s.*//; |
|
$active_slave = $anvil->Storage->read_file({file => "/sys/devices/virtual/net/".$interface."/bonding/active_slave"}); |
|
$mii_polling_interval = $anvil->Storage->read_file({file => "/sys/devices/virtual/net/".$interface."/bonding/miimon"}); |
|
$up_delay = $anvil->Storage->read_file({file => "/sys/devices/virtual/net/".$interface."/bonding/updelay"}); |
|
$down_delay = $anvil->Storage->read_file({file => "/sys/devices/virtual/net/".$interface."/bonding/downdelay"}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
active_slave => $active_slave, |
|
bond_mode => $bond_mode, |
|
mii_polling_interval => $mii_polling_interval, |
|
primary_reselect => $primary_reselect, |
|
primary_slave => $primary_slave, |
|
type => $type, |
|
}}); |
|
} |
|
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
active_slave => $active_slave, |
|
bond_mode => $bond_mode, |
|
down_delay => $down_delay, |
|
duplex => $duplex, |
|
interface => $interface, |
|
mac_address => $mac_address, |
|
mii_polling_interval => $mii_polling_interval, |
|
mtu => $mtu, |
|
operational => $operational, |
|
primary_reselect => $primary_reselect, |
|
primary_slave => $primary_slave, |
|
speed => $speed, |
|
subnet_mask => $subnet_mask, |
|
type => $type, |
|
up_delay => $up_delay, |
|
}}); |
|
|
|
# If the MAC address starts with '52:54:00', we've got a virtio NIC. |
|
if ((not defined $speed) or ($speed eq "")) |
|
{ |
|
die $THIS_FILE." ".__LINE__."; No speed for: [".$full_path."/speed]\n"; |
|
} |
|
if ($speed =~ /\D/) |
|
{ |
|
die $THIS_FILE." ".__LINE__."; Speed: [$speed] isn't numeric for: [".$full_path."/speed]\n"; |
|
} |
|
if ($speed > 100000) |
|
{ |
|
# NOTE: This is probably 0 now... Though someday >100 Gbps will be reasonable |
|
# and we'll need to change this. |
|
$speed = 0; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { speed => $speed }}); |
|
} |
|
|
|
# Find the media, if possible. |
|
my $shell_call = $anvil->data->{path}{exe}{ethtool}." $interface"; |
|
my $ethtool = $anvil->System->call({shell_call => $shell_call}); |
|
foreach my $line (split/\n/, $ethtool) |
|
{ |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { line => $line }}); |
|
if ($line =~ /Supported ports: \[ (.*?) \]/i) |
|
{ |
|
$media = lc($1); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { media => $media }}); |
|
last; |
|
} |
|
} |
|
|
|
# Log |
|
$anvil->data->{network}{interfaces}{by_name}{$interface} = { |
|
active_slave => $active_slave, |
|
bond_mode => $bond_mode, |
|
down_delay => $down_delay, |
|
duplex => $duplex, |
|
ip_address => $ip_address, |
|
link_state => $link_state, |
|
mac_address => $mac_address, |
|
media => $media, |
|
mii_polling_interval => $mii_polling_interval, |
|
mtu => $mtu, |
|
operational => $operational, |
|
primary_reselect => $primary_reselect, |
|
primary_slave => $primary_slave, |
|
speed => $speed, |
|
subnet_mask => $subnet_mask, |
|
type => $type, |
|
up_delay => $up_delay, |
|
}; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
"network::interfaces::by_name::${interface}::active_slave" => $anvil->data->{network}{interfaces}{by_name}{$interface}{active_slave}, |
|
"network::interfaces::by_name::${interface}::bond_mode" => $anvil->data->{network}{interfaces}{by_name}{$interface}{bond_mode}, |
|
"network::interfaces::by_name::${interface}::down_delay" => $anvil->data->{network}{interfaces}{by_name}{$interface}{down_delay}, |
|
"network::interfaces::by_name::${interface}::duplex" => $anvil->data->{network}{interfaces}{by_name}{$interface}{duplex}, |
|
"network::interfaces::by_name::${interface}::ip_address" => $anvil->data->{network}{interfaces}{by_name}{$interface}{ip_address}, |
|
"network::interfaces::by_name::${interface}::link_state" => $anvil->data->{network}{interfaces}{by_name}{$interface}{link_state}, |
|
"network::interfaces::by_name::${interface}::mac_address" => $anvil->data->{network}{interfaces}{by_name}{$interface}{mac_address}, |
|
"network::interfaces::by_name::${interface}::media" => $anvil->data->{network}{interfaces}{by_name}{$interface}{media}, |
|
"network::interfaces::by_name::${interface}::mii_polling_interval" => $anvil->data->{network}{interfaces}{by_name}{$interface}{mii_polling_interval}, |
|
"network::interfaces::by_name::${interface}::mtu" => $anvil->data->{network}{interfaces}{by_name}{$interface}{mtu}, |
|
"network::interfaces::by_name::${interface}::operational" => $anvil->data->{network}{interfaces}{by_name}{$interface}{operational}, |
|
"network::interfaces::by_name::${interface}::primary_reselect" => $anvil->data->{network}{interfaces}{by_name}{$interface}{primary_reselect}, |
|
"network::interfaces::by_name::${interface}::primary_slave" => $anvil->data->{network}{interfaces}{by_name}{$interface}{primary_slave}, |
|
"network::interfaces::by_name::${interface}::speed" => $anvil->data->{network}{interfaces}{by_name}{$interface}{speed}, |
|
"network::interfaces::by_name::${interface}::subnet_mask" => $anvil->data->{network}{interfaces}{by_name}{$interface}{subnet_mask}, |
|
"network::interfaces::by_name::${interface}::type" => $anvil->data->{network}{interfaces}{by_name}{$interface}{type}, |
|
"network::interfaces::by_name::${interface}::up_delay" => $anvil->data->{network}{interfaces}{by_name}{$interface}{up_delay}, |
|
}}); |
|
} |
|
} |
|
closedir(DIRECTORY); |
|
|
|
foreach my $interface (sort {$a cmp $b} keys %{$anvil->data->{network}{interfaces}{by_name}}) |
|
{ |
|
my $active_slave = $anvil->data->{network}{interfaces}{by_name}{$interface}{active_slave}; |
|
my $bond_mode = $anvil->data->{network}{interfaces}{by_name}{$interface}{bond_mode}; |
|
my $down_delay = $anvil->data->{network}{interfaces}{by_name}{$interface}{down_delay}; |
|
my $duplex = $anvil->data->{network}{interfaces}{by_name}{$interface}{duplex}; |
|
my $ip_address = $anvil->data->{network}{interfaces}{by_name}{$interface}{ip_address}; |
|
my $link_state = $anvil->data->{network}{interfaces}{by_name}{$interface}{link_state}; |
|
my $mac_address = $anvil->data->{network}{interfaces}{by_name}{$interface}{mac_address}; |
|
my $media = $anvil->data->{network}{interfaces}{by_name}{$interface}{media}; |
|
my $mii_polling_interval = $anvil->data->{network}{interfaces}{by_name}{$interface}{mii_polling_interval}; |
|
my $mtu = $anvil->data->{network}{interfaces}{by_name}{$interface}{mtu}; |
|
my $operational = $anvil->data->{network}{interfaces}{by_name}{$interface}{operational}; |
|
my $primary_reselect = $anvil->data->{network}{interfaces}{by_name}{$interface}{primary_reselect}; |
|
my $primary_slave = $anvil->data->{network}{interfaces}{by_name}{$interface}{primary_slave}; |
|
my $speed = $anvil->data->{network}{interfaces}{by_name}{$interface}{speed}; |
|
my $subnet_mask = $anvil->data->{network}{interfaces}{by_name}{$interface}{subnet_mask}; |
|
my $type = $anvil->data->{network}{interfaces}{by_name}{$interface}{type}; |
|
my $up_delay = $anvil->data->{network}{interfaces}{by_name}{$interface}{up_delay}; |
|
my $default_gateway = $anvil->data->{sys}{network}{interface}{$interface}{default_gateway}; |
|
my $gateway = $anvil->data->{sys}{network}{interface}{$interface}{gateway}; |
|
my $dns = $anvil->data->{sys}{network}{interface}{$interface}{dns}; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
active_slave => $active_slave, |
|
bond_mode => $bond_mode, |
|
default_gateway => $default_gateway, |
|
down_delay => $down_delay, |
|
dns => $dns, |
|
duplex => $duplex, |
|
gateway => $gateway, |
|
interface => $interface, |
|
ip_address => $ip_address, |
|
link_state => $link_state, |
|
mac_address => $mac_address, |
|
media => $media, |
|
mii_polling_interval => $mii_polling_interval, |
|
mtu => $mtu, |
|
operational => $operational, |
|
primary_reselect => $primary_reselect, |
|
primary_slave => $primary_slave, |
|
speed => $speed, |
|
subnet_mask => $subnet_mask, |
|
type => $type, |
|
up_delay => $up_delay, |
|
}}); |
|
|
|
if ($type eq "interface") |
|
{ |
|
my $network_interface_uuid = $anvil->Database->insert_or_update_network_interfaces({ |
|
file => $THIS_FILE, |
|
line => __LINE__, |
|
network_interface_name => $interface, |
|
network_interface_duplex => $duplex, |
|
network_interface_link_state => $link_state, |
|
network_interface_operational => $operational, |
|
network_interface_mac_address => $mac_address, |
|
network_interface_medium => $media, |
|
network_interface_mtu => $mtu, |
|
network_interface_speed => $speed, |
|
}); |
|
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network_interface_uuid => $network_interface_uuid }}); |
|
if (($network_interface_uuid) && ($ip_address)) |
|
{ |
|
my $ip_address_uuid = $anvil->Database->insert_or_update_ip_addresses({ |
|
debug => 2, |
|
ip_address_on_type => $type, |
|
ip_address_on_uuid => $network_interface_uuid, |
|
ip_address_address => $ip_address, |
|
ip_address_subnet_mask => $subnet_mask, |
|
ip_address_gateway => $gateway, |
|
ip_address_default_gateway => $default_gateway, |
|
ip_address_dns => $dns, |
|
}); |
|
} |
|
} |
|
elsif ($type eq "bond") |
|
{ |
|
my $bond_uuid = $anvil->Database->insert_or_update_bonds({ |
|
file => $THIS_FILE, |
|
line => __LINE__, |
|
bond_name => $interface, |
|
bond_mode => $bond_mode, |
|
bond_mtu => $mtu, |
|
bond_link_state => $link_state, |
|
bond_operational => $operational, |
|
bond_mac_address => $mac_address, |
|
bond_primary_slave => $primary_slave, |
|
bond_primary_reselect => $primary_reselect, |
|
bond_active_slave => $active_slave, |
|
bond_mii_polling_interval => $mii_polling_interval, |
|
bond_up_delay => $up_delay, |
|
bond_down_delay => $down_delay, |
|
}); |
|
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { bond_uuid => $bond_uuid }}); |
|
if (($bond_uuid) && ($ip_address)) |
|
{ |
|
my $ip_address_uuid = $anvil->Database->insert_or_update_ip_addresses({ |
|
debug => 2, |
|
ip_address_on_type => $type, |
|
ip_address_on_uuid => $bond_uuid, |
|
ip_address_address => $ip_address, |
|
ip_address_subnet_mask => $subnet_mask, |
|
ip_address_gateway => $gateway, |
|
ip_address_default_gateway => $default_gateway, |
|
ip_address_dns => $dns, |
|
}); |
|
} |
|
} |
|
} |
|
|
|
# Write out the XML file and JSON file. |
|
my $order = 1; |
|
my $network_xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"; |
|
$network_xml .= "<network>\n"; |
|
my $network_json = "{\"networks\":[\n"; |
|
my $query = " |
|
SELECT |
|
network_interface_mac_address, |
|
network_interface_name, |
|
network_interface_speed, |
|
network_interface_mtu, |
|
network_interface_link_state, |
|
network_interface_operational, |
|
network_interface_duplex, |
|
network_interface_medium, |
|
network_interface_bond_uuid, |
|
network_interface_bridge_uuid |
|
FROM |
|
network_interfaces |
|
WHERE |
|
network_interface_host_uuid = ".$anvil->data->{sys}{use_db_fh}->quote($anvil->Get->host_uuid)." |
|
ORDER BY |
|
modified_date DESC |
|
;"; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, key => "log_0124", variables => { query => $query }}); |
|
my $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__}); |
|
my $count = @{$results}; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { |
|
results => $results, |
|
count => $count, |
|
}}); |
|
foreach my $row (@{$results}) |
|
{ |
|
my $network_interface_mac_address = $row->[0]; |
|
my $network_interface_name = $row->[1]; |
|
my $network_interface_speed = $row->[2]; |
|
my $network_interface_mtu = defined $row->[3] ? $row->[3] : ""; |
|
my $network_interface_link_state = $row->[4]; |
|
my $network_interface_operational = $row->[5]; |
|
my $network_interface_duplex = $row->[6]; |
|
my $network_interface_medium = defined $row->[7] ? $row->[7] : ""; |
|
my $network_interface_bond_uuid = defined $row->[8] ? $row->[8] : ""; |
|
my $network_interface_bridge_uuid = defined $row->[9] ? $row->[9] : ""; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { |
|
network_interface_mac_address => $network_interface_mac_address, |
|
network_interface_name => $network_interface_name, |
|
network_interface_speed => $network_interface_speed, |
|
network_interface_mtu => $network_interface_mtu, |
|
network_interface_link_state => $network_interface_link_state, |
|
network_interface_operational => $network_interface_operational, |
|
network_interface_duplex => $network_interface_duplex, |
|
network_interface_medium => $network_interface_medium, |
|
network_interface_bond_uuid => $network_interface_bond_uuid, |
|
network_interface_bridge_uuid => $network_interface_bridge_uuid, |
|
order => $order, |
|
}}); |
|
$network_json .= " { \"name\":\"$network_interface_name\", \"mac\":\"$network_interface_mac_address\", \"link\":\"$network_interface_link_state\", \"speed\":\"$network_interface_speed\", \"mtu\":\"$network_interface_mtu\", \"duplex\":\"$network_interface_duplex\", \"state\":\"$network_interface_operational\", \"media\":\"$network_interface_medium\", \"bond\":\"$network_interface_bond_uuid\", \"bridge\":\"$network_interface_bridge_uuid\", \"order\":\"$order\" },\n"; |
|
$network_xml .= " <interface name=\"$network_interface_name\" mac=\"$network_interface_mac_address\" link=\"$network_interface_link_state\" speed=\"$network_interface_speed\" mtu=\"$network_interface_mtu\" duplex=\"$network_interface_duplex\" state=\"$network_interface_operational\" media=\"$network_interface_medium\" bond=\"$network_interface_bond_uuid\" bridge=\"$network_interface_bridge_uuid\" order=\"$order\" />\n"; |
|
$order++; |
|
} |
|
|
|
$network_json =~ s/,$//s; |
|
$network_json .= "]}\n"; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { network_json => $network_json }}); |
|
|
|
$network_xml .= "</network>\n"; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { network_xml => $network_xml }}); |
|
|
|
### TODO: Set the 'status/network.json' name into 'anvil.conf' |
|
# Write the JSON file. |
|
my $output_json = $anvil->data->{path}{directories}{html}."/status/network.json"; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { output_xml => $output_json }}); |
|
$anvil->Storage->write_file({ |
|
file => $output_json, |
|
body => $network_json, |
|
overwrite => 1, |
|
mode => "0644", |
|
user => "apache", |
|
group => "apache" |
|
}); |
|
|
|
# Write the XML file. |
|
my $output_xml = $anvil->data->{path}{directories}{html}."/status/network.xml"; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { output_xml => $output_xml }}); |
|
$anvil->Storage->write_file({ |
|
file => $output_xml, |
|
body => $network_xml, |
|
overwrite => 1, |
|
mode => "0644", |
|
user => "apache", |
|
group => "apache" |
|
}); |
|
|
|
return(0); |
|
}
|
|
|