diff --git a/Anvil/Tools/DRBD.pm b/Anvil/Tools/DRBD.pm
index 76dc739f..cb175545 100644
--- a/Anvil/Tools/DRBD.pm
+++ b/Anvil/Tools/DRBD.pm
@@ -24,6 +24,7 @@ my $THIS_FILE = "DRBD.pm";
# get_next_resource
# get_status
# manage_resource
+# parse_resource
# reload_defaults
# remove_backing_lv
# resource_uuid
@@ -2361,6 +2362,253 @@ sub manage_resource
return($return_code);
}
+
+=head2 parse_resource
+
+This takes the XML from a specific DRBD resource and parses it.
+
+Parameters;
+
+=head3 xml (required)
+
+This is the XML to parse, generally as stored in the C<< scan_drbd_resources >> -> C<< scan_drbd_resource_xml >>.
+
+=cut
+sub parse_resource
+{
+ my $self = shift;
+ my $parameter = shift;
+ my $anvil = $self->parent;
+ my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3;
+ $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "DRBD->parse_resource()" }});
+
+ my $xml = defined $parameter->{xml} ? $parameter->{xml} : "";
+ $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
+ xml => $xml,
+ }});
+
+ if (not $xml)
+ {
+ $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "DRBD->parse_resource()", parameter => "xml" }});
+ return("!!error!!");
+ }
+
+ local $@;
+ my $dom = eval { XML::LibXML->load_xml(string => $xml); };
+ if ($@)
+ {
+ $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "error_0253", variables => {
+ xml => $xml,
+ error => $@,
+ }});
+ return(1);
+ }
+ else
+ {
+ # Successful parse!
+=cut
+
+
+
+ /dev/drbd_srv01-fs37_0
+ /dev/cs_vm-a01n01/srv01-fs37_0
+ internal
+
+
+ /dev/drbd_srv01-fs37_1
+ /dev/cs_vm-a01n01/srv01-fs37_1
+ internal
+
+ (null)
+
+
+
+ /dev/drbd_srv01-fs37_0
+ /dev/cs_vm-a01n02/srv01-fs37_0
+ internal
+
+
+ /dev/drbd_srv01-fs37_1
+ /dev/cs_vm-a01n02/srv01-fs37_1
+ internal
+
+ (null)
+
+
+
+ /dev/drbd_srv01-fs37_0
+ /dev/cs_vm-a01dr01/srv01-fs37_0
+ internal
+
+
+ /dev/drbd_srv01-fs37_1
+ /dev/cs_vm-a01dr01/srv01-fs37_1
+ internal
+
+ (null)
+
+
+ 10.101.10.1
+ 10.101.10.2
+
+
+
+
+ 10.201.10.1
+ 10.201.10.3
+
+
+
+
+ 10.201.10.2
+ 10.201.10.3
+
+
+
+
+=cut
+ foreach my $name ($dom->findnodes('/resource'))
+ {
+ my $resource = $name->{name};
+ $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { resource => $resource }});
+
+ foreach my $host ($name->findnodes('./host'))
+ {
+ my $this_host_name = $host->{name};
+ $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { this_host_name => $this_host_name }});
+
+ # Record the details under the hosts
+ foreach my $volume_vnr ($host->findnodes('./volume'))
+ {
+ my $volume = $volume_vnr->{vnr};
+ my $meta_disk = $volume_vnr->findvalue('./meta-disk');
+ $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
+ 's1:volume' => $volume,
+ 's2:meta_disk' => $meta_disk,
+ }});
+
+ my $host_uuid = $anvil->Get->host_uuid_from_name({host_name => $this_host_name});
+ $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { host_uuid => $host_uuid }});
+
+ $anvil->data->{new}{resource}{$resource}{host_name}{$this_host_name}{host_uuid} = $host_uuid;
+ $anvil->data->{new}{resource}{$resource}{host_uuid}{$host_uuid}{volume_number}{$volume}{device_path} = $volume_vnr->findvalue('./device');
+ $anvil->data->{new}{resource}{$resource}{host_uuid}{$host_uuid}{volume_number}{$volume}{backing_disk} = $volume_vnr->findvalue('./disk');
+ $anvil->data->{new}{resource}{$resource}{host_uuid}{$host_uuid}{volume_number}{$volume}{device_minor} = $volume_vnr->findvalue('./device/@minor');
+ $anvil->data->{new}{resource}{$resource}{host_uuid}{$host_uuid}{volume_number}{$volume}{meta_disk} = $meta_disk;
+ $anvil->data->{new}{resource}{$resource}{host_uuid}{$host_uuid}{volume_number}{$volume}{size} = 0;
+ $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
+ "s1:new::resource::${resource}::host_name::${this_host_name}::host_uuid" => $anvil->data->{new}{resource}{$resource}{host_name}{$this_host_name}{host_uuid},
+ "s2:new::resource::${resource}::host_uuid::${host_uuid}::volume_number::${volume}::device_path" => $anvil->data->{new}{resource}{$resource}{host_uuid}{$host_uuid}{volume_number}{$volume}{device_path},
+ "s3:new::resource::${resource}::host_uuid::${host_uuid}::volume_number::${volume}::backing_disk" => $anvil->data->{new}{resource}{$resource}{host_uuid}{$host_uuid}{volume_number}{$volume}{backing_disk},
+ "s4:new::resource::${resource}::host_uuid::${host_uuid}::volume_number::${volume}::device_minor" => $anvil->data->{new}{resource}{$resource}{host_uuid}{$host_uuid}{volume_number}{$volume}{device_minor},
+ "s5:new::resource::${resource}::host_uuid::${host_uuid}::volume_number::${volume}::meta_disk" => $anvil->data->{new}{resource}{$resource}{host_uuid}{$host_uuid}{volume_number}{$volume}{meta_disk},
+ }});
+ }
+ }
+ foreach my $connection ($name->findnodes('./connection'))
+ {
+ my $host1_name = "";
+ my $host1_ip_address = "";
+ my $host1_tcp_port = "";
+ my $host2_name = "";
+ my $host2_ip_address = "";
+ my $host2_tcp_port = "";
+ my $peer = "";
+ foreach my $host ($connection->findnodes('./host'))
+ {
+ my $this_host_name = $host->{name};
+ $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { this_host_name => $this_host_name }});
+ if (not $host1_name)
+ {
+ $host1_name = $this_host_name;
+ $host1_ip_address = $host->findvalue('./address');
+ $host1_tcp_port = $host->findvalue('./address/@port');
+ $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
+ host1_name => $host1_name,
+ host1_ip_address => $host1_ip_address,
+ host1_tcp_port => $host1_tcp_port,
+ }});
+ }
+ else
+ {
+ $host2_name = $this_host_name;
+ $host2_ip_address = $host->findvalue('./address');
+ $host2_tcp_port = $host->findvalue('./address/@port');
+ $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
+ host2_name => $host2_name,
+ host2_ip_address => $host2_ip_address,
+ host2_tcp_port => $host2_tcp_port,
+ }});
+
+ $anvil->data->{new}{resource}{$resource}{host1_to_host2}{$host1_name}{$host2_name}{host1_ip_address} = $host1_ip_address;
+ $anvil->data->{new}{resource}{$resource}{host1_to_host2}{$host1_name}{$host2_name}{host1_tcp_port} = $host1_tcp_port;
+ $anvil->data->{new}{resource}{$resource}{host1_to_host2}{$host1_name}{$host2_name}{host2_ip_address} = $host2_ip_address;
+ $anvil->data->{new}{resource}{$resource}{host1_to_host2}{$host1_name}{$host2_name}{host2_tcp_port} = $host2_tcp_port;
+ $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
+ "s1:new::resource::${resource}::host1_to_host2::${host1_name}::${host2_name}::host1_ip_address" => $anvil->data->{new}{resource}{$resource}{host1_to_host2}{$host1_name}{$host2_name}{host1_ip_address},
+ "s2:new::resource::${resource}::host1_to_host2::${host1_name}::${host2_name}::host1_tcp_port" => $anvil->data->{new}{resource}{$resource}{host1_to_host2}{$host1_name}{$host2_name}{host1_tcp_port},
+ "s3:new::resource::${resource}::host1_to_host2::${host1_name}::${host2_name}::host2_ip_address" => $anvil->data->{new}{resource}{$resource}{host1_to_host2}{$host1_name}{$host2_name}{host2_ip_address},
+ "s4:new::resource::${resource}::host1_to_host2::${host1_name}::${host2_name}::host2_tcp_port" => $anvil->data->{new}{resource}{$resource}{host1_to_host2}{$host1_name}{$host2_name}{host2_tcp_port},
+ }});
+
+ foreach my $proxy ($host->findnodes('./proxy'))
+ {
+ my $host_name = $proxy->{hostname};
+ $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { host_name => $host_name }});
+
+ # This should always be the target, but lets be safe/careful
+ next if $host_name ne $host2_name;
+
+ $anvil->data->{new}{resource}{$resource}{host1_to_host2}{$host1_name}{$host2_name}{host2_inside_ip_address} = $proxy->findvalue('./inside');
+ $anvil->data->{new}{resource}{$resource}{host1_to_host2}{$host1_name}{$host2_name}{host2_inside_tcp_port} = $proxy->findvalue('./inside/@port');
+ $anvil->data->{new}{resource}{$resource}{host1_to_host2}{$host1_name}{$host2_name}{host2_outside_ip_address} = $proxy->findvalue('./outside');
+ $anvil->data->{new}{resource}{$resource}{host1_to_host2}{$host1_name}{$host2_name}{host2_outside_tcp_port} = $proxy->findvalue('./outside/@port');
+ $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
+ "s1:new::resource::${resource}::host1_to_host2::${host1_name}::${host2_name}::host2_inside_ip_address" => $anvil->data->{new}{resource}{$resource}{host1_to_host2}{$host1_name}{$host2_name}{host2_inside_ip_address},
+ "s2:new::resource::${resource}::host1_to_host2::${host1_name}::${host2_name}::host2_inside_tcp_port" => $anvil->data->{new}{resource}{$resource}{host1_to_host2}{$host1_name}{$host2_name}{host2_inside_tcp_port},
+ "s3:new::resource::${resource}::host1_to_host2::${host1_name}::${host2_name}::host2_outside_ip_address" => $anvil->data->{new}{resource}{$resource}{host1_to_host2}{$host1_name}{$host2_name}{host2_outside_ip_address},
+ "s4:new::resource::${resource}::host1_to_host2::${host1_name}::${host2_name}::host2_outside_tcp_port" => $anvil->data->{new}{resource}{$resource}{host1_to_host2}{$host1_name}{$host2_name}{host2_outside_tcp_port},
+ }});
+
+ $anvil->data->{new}{resource}{$resource}{proxy}{$host_name}{inside}{ip_address} = $proxy->findvalue('./inside');
+ $anvil->data->{new}{resource}{$resource}{proxy}{$host_name}{inside}{tcp_port} = $proxy->findvalue('./inside/@port');
+ $anvil->data->{new}{resource}{$resource}{proxy}{$host_name}{outside}{ip_address} = $proxy->findvalue('./outside');
+ $anvil->data->{new}{resource}{$resource}{proxy}{$host_name}{outside}{tcp_port} = $proxy->findvalue('./outside/@port');
+ $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
+ "new::resource::${resource}::proxy::${host_name}::inside::ip_address" => $anvil->data->{new}{resource}{$resource}{proxy}{$host_name}{inside}{ip_address},
+ "new::resource::${resource}::proxy::${host_name}::inside::tcp_port" => $anvil->data->{new}{resource}{$resource}{proxy}{$host_name}{inside}{tcp_port},
+ "new::resource::${resource}::proxy::${host_name}::outside::ip_address" => $anvil->data->{new}{resource}{$resource}{proxy}{$host_name}{outside}{ip_address},
+ "new::resource::${resource}::proxy::${host_name}::outside::tcp_port" => $anvil->data->{new}{resource}{$resource}{proxy}{$host_name}{outside}{tcp_port},
+ }});
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return(0);
+}
+
+
=head2 reload_defaults
This switches DRBD back to running using the values in the config files. Specifically, it calls C<< drbdadm adjust all >>.
diff --git a/Anvil/Tools/Get.pm b/Anvil/Tools/Get.pm
index 4df0a8fe..2fddbbda 100644
--- a/Anvil/Tools/Get.pm
+++ b/Anvil/Tools/Get.pm
@@ -643,7 +643,7 @@ WHERE
# How many cores?
if ((not $anvil->data->{anvil_resources}{$anvil_uuid}{cpu}{cores}) or
- ($scan_hardware_cpu_cores < $anvil->data->{anvil_resources}{$anvil_uuid}{cpu}{cores}))
+ ($scan_hardware_cpu_cores < $anvil->data->{anvil_resources}{$anvil_uuid}{cpu}{cores}))
{
$anvil->data->{anvil_resources}{$anvil_uuid}{cpu}{cores} = $scan_hardware_cpu_cores;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
@@ -651,15 +651,25 @@ WHERE
}});
}
if ((not $anvil->data->{anvil_resources}{$anvil_uuid}{cpu}{threads}) or
- ($scan_hardware_cpu_threads < $anvil->data->{anvil_resources}{$anvil_uuid}{cpu}{threads}))
+ ($scan_hardware_cpu_threads < $anvil->data->{anvil_resources}{$anvil_uuid}{cpu}{threads}))
{
$anvil->data->{anvil_resources}{$anvil_uuid}{cpu}{threads} = $scan_hardware_cpu_threads;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"anvil_resources::${anvil_uuid}::cpu::threads" => $anvil->data->{anvil_resources}{$anvil_uuid}{cpu}{threads},
}});
}
+
+ # If there are less threads than cores, set the cores to be equal to threads.
+ if ($anvil->data->{anvil_resources}{$anvil_uuid}{cpu}{threads} < $anvil->data->{anvil_resources}{$anvil_uuid}{cpu}{cores})
+ {
+ $anvil->data->{anvil_resources}{$anvil_uuid}{cpu}{threads} = $anvil->data->{anvil_resources}{$anvil_uuid}{cpu}{cores};
+ $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
+ "anvil_resources::${anvil_uuid}::cpu::threads" => $anvil->data->{anvil_resources}{$anvil_uuid}{cpu}{threads},
+ }});
+ }
+
if ((not $anvil->data->{anvil_resources}{$anvil_uuid}{ram}{available}) or
- ($scan_hardware_ram_total < $anvil->data->{anvil_resources}{$anvil_uuid}{ram}{hardware}))
+ ($scan_hardware_ram_total < $anvil->data->{anvil_resources}{$anvil_uuid}{ram}{hardware}))
{
$anvil->data->{anvil_resources}{$anvil_uuid}{ram}{available} = $scan_hardware_ram_total;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
@@ -2114,9 +2124,9 @@ sub server_from_switch
server_string => $server_string,
}});
- if ((not $server_string) && ($anvil->data->{switches}{'anvil'}))
+ if ((not $server_string) && ($anvil->data->{switches}{'server'}))
{
- $server_string = $anvil->data->{switches}{'anvil'};
+ $server_string = $anvil->data->{switches}{'server'};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { server_string => $server_string }});
}
if (not $server_string)
@@ -2125,10 +2135,16 @@ sub server_from_switch
return("!!error!!", "");
}
+ $anvil->Database->get_anvils({debug => $debug});
$anvil->Database->get_servers({debug => $debug});
$anvil->data->{switches}{server_name} = "" if not exists $anvil->data->{switches}{server_name};
$anvil->data->{switches}{server_uuid} = "" if not exists $anvil->data->{switches}{server_uuid};
- if (exists $anvil->data->{servers}{server_uuid}{$server_string}{server_name})
+ $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
+ server_string => $server_string,
+ "switches::server_name" => $anvil->data->{switches}{server_name},
+ "switches::server_uuid" => $anvil->data->{switches}{server_uuid},
+ }});
+ if (exists $anvil->data->{servers}{server_uuid}{$server_string})
{
# Found it by UUID.
$anvil->data->{switches}{server_name} = $anvil->data->{anvils}{server_uuid}{$server_string}{server_name};
@@ -2138,14 +2154,33 @@ sub server_from_switch
"switches::server_uuid" => $anvil->data->{switches}{server_uuid},
}});
}
- elsif (exists $anvil->data->{anvils}{server_uuid}{$server_string})
+ else
{
- $anvil->data->{switches}{server_name} = $server_string;
- $anvil->data->{switches}{server_uuid} = $anvil->data->{anvils}{server_uuid}{$server_string}{server_uuid};
- $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
- "switches::server_name" => $anvil->data->{switches}{server_name},
- "switches::server_uuid" => $anvil->data->{switches}{server_uuid},
- }});
+ # If we have an anvil_uuid, see if the server exists there.
+ foreach my $this_anvil_name (sort {$a cmp $b} keys %{$anvil->data->{anvils}{anvil_name}})
+ {
+ my $this_anvil_uuid = $anvil->data->{anvils}{anvil_name}{$this_anvil_name}{anvil_uuid};
+ if (($anvil_uuid) && ($anvil_uuid ne $this_anvil_uuid))
+ {
+ next;
+ }
+ foreach my $this_server_name (sort {$a cmp $b} keys %{$anvil->data->{servers}{anvil_uuid}{$this_anvil_uuid}{server_name}})
+ {
+ my $this_server_uuid = $anvil->data->{servers}{anvil_uuid}{$this_anvil_uuid}{server_name}{$this_server_name}{server_uuid};
+ if (($server_string eq $this_server_name) or
+ ($server_string eq $this_server_uuid))
+ {
+ # Found it
+ $anvil->data->{switches}{server_name} = $this_server_name;
+ $anvil->data->{switches}{server_uuid} = $this_server_uuid;
+ $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
+ "switches::server_name" => $anvil->data->{switches}{server_name},
+ "switches::server_uuid" => $anvil->data->{switches}{server_uuid},
+ }});
+ last;
+ }
+ }
+ }
}
return($anvil->data->{switches}{server_name}, $anvil->data->{switches}{server_uuid});
diff --git a/Anvil/Tools/Server.pm b/Anvil/Tools/Server.pm
index d3b169a7..7efc0176 100644
--- a/Anvil/Tools/Server.pm
+++ b/Anvil/Tools/Server.pm
@@ -1385,7 +1385,7 @@ sub parse_definition
my $server = defined $parameter->{server} ? $parameter->{server} : "";
my $source = defined $parameter->{source} ? $parameter->{source} : "";
my $definition = defined $parameter->{definition} ? $parameter->{definition} : "";
- my $host = defined $parameter->{host} ? $parameter->{host} : $anvil->Get->short_host_name;
+ my $host = defined $parameter->{host} ? $parameter->{host} : "";
my $target = $anvil->Get->short_host_name();
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
anvil_uuid => $anvil_uuid,
@@ -1395,6 +1395,12 @@ sub parse_definition
host => $host,
}});
+ if (not $target)
+ {
+ $target = $anvil->Get->short_host_name;
+ $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { target => $target }});
+ }
+
if (not $server)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Server->parse_definition()", parameter => "server" }});
@@ -1805,6 +1811,16 @@ sub parse_definition
"server::${target}::${server}::${source}::device::${device}::target::${device_target}::type" => $anvil->data->{server}{$target}{$server}{$source}{device}{$device}{target}{$device_target}{type},
}});
+ if (($boot_order) && ($boot_order =~ /^\d+$/))
+ {
+ $anvil->data->{server}{$target}{$server}{$source}{boot_order}{$boot_order}{device_target} = $device_target;
+ $anvil->data->{server}{$target}{$server}{$source}{boot_order}{$boot_order}{device_type} = $device;
+ $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
+ "server::${target}::${server}::${source}::boot_order::${boot_order}::device_target" => $anvil->data->{server}{$target}{$server}{$source}{boot_order}{$boot_order}{device_target},
+ "server::${target}::${server}::${source}::boot_order::${boot_order}::device_type" => $anvil->data->{server}{$target}{$server}{$source}{boot_order}{$boot_order}{device_type},
+ }});
+ }
+
# Record type-specific data
if ($device eq "disk")
{
diff --git a/man/Makefile.am b/man/Makefile.am
index d614bf43..401676d5 100644
--- a/man/Makefile.am
+++ b/man/Makefile.am
@@ -19,6 +19,7 @@ dist_man8_MANS = \
anvil-manage-files.8 \
anvil-manage-keys.1 \
anvil-manage-server.8 \
+ anvil-manage-server-storage.8 \
anvil-manage-storage-groups.8 \
scancore.8 \
striker-initialize-host.8
diff --git a/man/anvil-manage-server-storage.8 b/man/anvil-manage-server-storage.8
new file mode 100644
index 00000000..e69de29b
diff --git a/scancore-agents/scan-drbd/scan-drbd b/scancore-agents/scan-drbd/scan-drbd
index 8307ba6c..69cdb8e6 100755
--- a/scancore-agents/scan-drbd/scan-drbd
+++ b/scancore-agents/scan-drbd/scan-drbd
@@ -914,6 +914,16 @@ sub process_volumes
"s4:old_scan_drbd_volume_size" => $old_scan_drbd_volume_size." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $old_scan_drbd_volume_size}).")",
}});
+ # If the $new_scan_drbd_volume_size is '0', the device is down. Don't update it so we can
+ # recall the last known size.
+ if ($new_scan_drbd_volume_size == 0)
+ {
+ $new_scan_drbd_volume_size = $old_scan_drbd_volume_size;
+ $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
+ new_scan_drbd_volume_size => $new_scan_drbd_volume_size." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $new_scan_drbd_volume_size}).")",
+ }});
+ }
+
my $update = 0;
if ($new_scan_drbd_volume_device_path ne $old_scan_drbd_volume_device_path)
{
diff --git a/tools/Makefile.am b/tools/Makefile.am
index e0e2b7ea..96f7b2e1 100644
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
@@ -26,6 +26,7 @@ dist_sbin_SCRIPTS = \
anvil-manage-keys \
anvil-manage-power \
anvil-manage-server \
+ anvil-manage-server-storage \
anvil-manage-storage-groups \
anvil-migrate-server \
anvil-network-profiler \
@@ -76,4 +77,3 @@ sharedir = ${datarootdir}/anvil
dist_share_DATA = striker-auto-initialize-all.example
-# -rwxr-xr-x. 1 digimer digimer 34K Feb 1 2020 tool-fio-tester
diff --git a/tools/anvil-daemon b/tools/anvil-daemon
index 9b20a131..bcd15b75 100755
--- a/tools/anvil-daemon
+++ b/tools/anvil-daemon
@@ -766,7 +766,7 @@ sub check_db_in_use_states
my ($anvil) = @_;
# We only reap db_in_use entries for us.
- $anvil->System->pids();
+ $anvil->System->pids({debug => 2});
my $query = "
SELECT
state_uuid,
diff --git a/tools/anvil-manage-server-storage b/tools/anvil-manage-server-storage
new file mode 100755
index 00000000..06eeaf66
--- /dev/null
+++ b/tools/anvil-manage-server-storage
@@ -0,0 +1,398 @@
+#!/usr/bin/perl
+#
+# This program will manage servers; Changing RAM, CPU cores, Growing virtual disks, adding virtual disks,
+# inserting and ejecting ISO images into virtual optical media.
+#
+# Exit codes;
+# 0 = Normal exit.
+# 1 = No database connection.
+#
+# TODO:
+#
+
+use strict;
+use warnings;
+use Anvil::Tools;
+require POSIX;
+use Term::Cap;
+use Data::Dumper;
+
+my $THIS_FILE = ($0 =~ /^.*\/(.*)$/)[0];
+my $running_directory = ($0 =~ /^(.*?)\/$THIS_FILE$/)[0];
+if (($running_directory =~ /^\./) && ($ENV{PWD}))
+{
+ $running_directory =~ s/^\./$ENV{PWD}/;
+}
+
+# Turn off buffering so that the pinwheel will display while waiting for the SSH call(s) to complete.
+$| = 1;
+
+my $anvil = Anvil::Tools->new();
+
+### TODO: Remove this before final release
+$anvil->Log->level({set => 2});
+$anvil->Log->secure({set => 1});
+##########################################
+
+# Read switches (target ([user@]host[:port]) and the file with the target's password.
+$anvil->Get->switches({list => [
+ "add",
+ "anvil",
+ "grow",
+ "server",
+ ], man => $THIS_FILE});
+$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => $anvil->data->{switches}});
+$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0115", variables => { program => $THIS_FILE }});
+
+# Connect to the database(s). If we have no connections, we'll proceed anyway as one of the 'run_once' tasks
+# is to setup the database server.
+$anvil->Database->connect();
+$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, secure => 0, key => "log_0132"});
+if (not $anvil->data->{sys}{database}{connections})
+{
+ # No databases, update the job, sleep for a bit and then exit. The daemon will pick it up and try
+ # again after we exit.
+ $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, priority => "err", key => "error_0305"});
+ sleep 10;
+ $anvil->nice_exit({exit_code => 1});
+}
+
+# If we don't have a job UUID, try to find one.
+if (not $anvil->data->{switches}{'job-uuid'})
+{
+ # Load the job data.
+ $anvil->data->{switches}{'job-uuid'} = $anvil->Job->get_job_uuid({program => $THIS_FILE});
+ $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "switches::job-uuid" => $anvil->data->{switches}{'job-uuid'} }});
+}
+
+$anvil->Database->get_hosts();
+$anvil->Database->get_anvils();
+$anvil->Database->get_servers();
+
+if ($anvil->data->{switches}{anvil})
+{
+ # Make sure they asked for a real anvil.
+ $anvil->Get->anvil_from_switch({string => $anvil->data->{switches}{anvil}});
+ $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
+ "switches::anvil_name" => $anvil->data->{switches}{anvil_name},
+ "switches::anvil_uuid" => $anvil->data->{switches}{anvil_uuid},
+ }});
+}
+
+if (not $anvil->data->{switches}{server})
+{
+ # Show the list of servers.
+ show_server_list($anvil);
+ print "\nPlease specify which server you want to modify using '--server '.\n\n";
+ $anvil->nice_exit({exit_code => 0});
+}
+manage_server($anvil);
+
+$anvil->nice_exit({exit_code => 0});
+
+
+#############################################################################################################
+# Functions #
+#############################################################################################################
+
+sub manage_server
+{
+ my ($anvil) = @_;
+
+ $anvil->Get->server_from_switch({
+ debug => 2,
+ string => $anvil->data->{switches}{server},
+ anvil_uuid => $anvil->data->{switches}{anvil_uuid},
+ });
+ $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
+ "switches::server_name" => $anvil->data->{switches}{server_name},
+ "switches::server_uuid" => $anvil->data->{switches}{server_uuid},
+ }});
+
+ if (not $anvil->data->{switches}{server_uuid})
+ {
+ show_server_list($anvil);
+ if ($anvil->data->{switches}{anvil_uuid})
+ {
+ # Not found on the requested Anvil! node.
+ print "\nThe server: [".$anvil->data->{switches}{server}."] was not found on the Anvil! node: [".$anvil->data->{switches}{anvil_name}."]. Valid servers are above.\n\n";
+ }
+ else
+ {
+ # Not found at all.
+ print "\nThe server: [".$anvil->data->{switches}{server}."] was not found. Valid servers are above.\n\n";
+ }
+ $anvil->nice_exit({exit_code => 1});
+ }
+
+ print "Working with the server: [".$anvil->data->{switches}{server_name}."], UUID: [".$anvil->data->{switches}{server_uuid}."]\n";
+ my $short_host_name = $anvil->Get->short_host_name;
+ my $server_name = $anvil->data->{switches}{server_name};
+ my $server_uuid = $anvil->data->{switches}{server_uuid};
+ my $server_definition = $anvil->data->{servers}{server_uuid}{$server_uuid}{server_definition_xml};
+ $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
+ 's1:short_host_name' => $short_host_name,
+ 's2:server_name' => $server_name,
+ 's3:server_uuid' => $server_uuid,
+ 's4:server_definition' => $server_definition,
+ }});
+
+ # Parse the definition.
+ $anvil->Server->parse_definition({
+ debug => 3,
+ host => $short_host_name,
+ server => $server_name,
+ source => "from_virsh",
+ definition => $server_definition,
+ });
+
+ #$anvil->data->{server}{$short_host_name}{$server_name}{from_virsh}{boot_order}
+ foreach my $device ("disk", "cdrom")
+ {
+ if ($device eq "disk")
+ {
+ print "\nDisk Drives:\n";
+ }
+ else
+ {
+ print "\nOptical Drives:\n";
+ }
+ $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { device => $device }});
+ next if $device ne "cdrom" && $device ne "disk";
+ foreach my $device_target (sort {$a cmp $b} keys %{$anvil->data->{server}{$short_host_name}{$server_name}{from_virsh}{device}{$device}{target}})
+ {
+ my $alias = $anvil->data->{server}{$short_host_name}{$server_name}{from_virsh}{device}{$device}{target}{$device_target}{alias};
+ my $boot_order = $anvil->data->{server}{$short_host_name}{$server_name}{from_virsh}{device}{$device}{target}{$device_target}{boot_order};
+ my $say_boot = $boot_order eq "99" ? "--" : sprintf("%02d", $boot_order);
+ my $type = $anvil->data->{server}{$short_host_name}{$server_name}{from_virsh}{device}{$device}{target}{$device_target}{type};
+ my $address_type = $anvil->data->{server}{$short_host_name}{$server_name}{from_virsh}{device}{$device}{target}{$device_target}{address}{type};
+ my $address_bus = $anvil->data->{server}{$short_host_name}{$server_name}{from_virsh}{device}{$device}{target}{$device_target}{address}{bus};
+ my $driver_name = $anvil->data->{server}{$short_host_name}{$server_name}{from_virsh}{device}{$device}{target}{$device_target}{driver}{name};
+ my $device_bus = $anvil->data->{server}{$short_host_name}{$server_name}{from_virsh}{device}{$device}{target}{$device_target}{device_bus};
+ my $driver_type = $anvil->data->{server}{$short_host_name}{$server_name}{from_virsh}{device}{$device}{target}{$device_target}{driver}{type};
+ $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
+ 's01:device_target' => $device_target,
+ 's02:alias' => $alias,
+ 's03:boot_order' => $boot_order,
+ 's04:say_boot' => $say_boot,
+ 's05:type' => $type,
+ 's06:address_type' => $address_type,
+ 's07:address_bus' => $address_bus,
+ 's08:driver_name' => $driver_name,
+ 's09:device_bus' => $device_bus,
+ 's10:driver_type' => $driver_type,
+ }});
+ if ($device eq "disk")
+ {
+ my $address_domain = $anvil->data->{server}{$short_host_name}{$server_name}{from_virsh}{device}{$device}{target}{$device_target}{address}{domain};
+ my $address_slot = $anvil->data->{server}{$short_host_name}{$server_name}{from_virsh}{device}{$device}{target}{$device_target}{address}{slot};
+ my $address_function = $anvil->data->{server}{$short_host_name}{$server_name}{from_virsh}{device}{$device}{target}{$device_target}{address}{function};
+ my $device_path = $anvil->data->{server}{$short_host_name}{$server_name}{from_virsh}{device}{$device}{target}{$device_target}{path};
+ my $driver_io = $anvil->data->{server}{$short_host_name}{$server_name}{from_virsh}{device}{$device}{target}{$device_target}{driver}{io};
+ my $driver_cache = $anvil->data->{server}{$short_host_name}{$server_name}{from_virsh}{device}{$device}{target}{$device_target}{driver}{cache};
+ $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
+ 's1:address_domain' => $address_domain,
+ 's2:address_slot' => $address_slot,
+ 's3:address_function' => $address_function,
+ 's4:device_path' => $device_path,
+ 's5:driver_io' => $driver_io,
+ 's6:driver_cache' => $driver_cache,
+ }});
+ print "- Target: [".$device_target."], boot: [".$say_boot."], path: [".$device_path."], cache: [".$driver_cache."], driver type: [".$driver_type."]\n";
+ }
+ else
+ {
+ my $address_controller = $anvil->data->{server}{$short_host_name}{$server_name}{from_virsh}{device}{$device}{target}{$device_target}{address}{controller};
+ my $address_unit = $anvil->data->{server}{$short_host_name}{$server_name}{from_virsh}{device}{$device}{target}{$device_target}{address}{unit};
+ my $address_target = $anvil->data->{server}{$short_host_name}{$server_name}{from_virsh}{device}{$device}{target}{$device_target}{address}{target};
+ my $device_path = $anvil->data->{server}{$short_host_name}{$server_name}{from_virsh}{device}{$device}{target}{$device_target}{path};
+ $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
+ 's1:address_controller' => $address_controller,
+ 's2:address_unit' => $address_unit,
+ 's3:address_target' => $address_target,
+ 's4:device_path' => $device_path,
+ }});
+ print "- Target: [".$device_target."], boot: [".$say_boot."], ISO: [".$device_path."]\n";
+ }
+ }
+ }
+ print "\n";
+
+ my $drbd_resource = "";
+ foreach my $device_path (sort {$a cmp $b} keys %{$anvil->data->{server}{$short_host_name}{$server_name}{device}})
+ {
+ my $on_lv = $anvil->data->{server}{$short_host_name}{$server_name}{device}{$device_path}{on_lv};
+ $drbd_resource = $anvil->data->{server}{$short_host_name}{$server_name}{device}{$device_path}{resource};
+ my $device_target = $anvil->data->{server}{$short_host_name}{$server_name}{device}{$device_path}{target};
+ $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
+ 's1:device_path' => $device_path,
+ 's2:on_lv' => $on_lv,
+ 's3:drbd_resource' => $drbd_resource,
+ 's4:device_target' => $device_target,
+ }});
+ }
+ foreach my $drbd_resource (sort {$a cmp $b} keys %{$anvil->data->{server}{$short_host_name}{$server_name}{drbd}{resource}})
+ {
+ $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { drbd_resource => $drbd_resource }});
+ }
+
+ # Get the DRBD volume data
+ # Get the DRBD volume data
+ my $query = "
+SELECT
+ a.host_uuid,
+ b.scan_drbd_resource_xml,
+ c.scan_drbd_volume_number,
+ c.scan_drbd_volume_device_path,
+ c.scan_drbd_volume_device_minor,
+ c.scan_drbd_volume_size
+FROM
+ hosts a,
+ scan_drbd_resources b,
+ scan_drbd_volumes c
+WHERE
+ a.host_uuid = b.scan_drbd_resource_host_uuid
+AND
+ b.scan_drbd_resource_uuid = c.scan_drbd_volume_scan_drbd_resource_uuid
+AND
+ b.scan_drbd_resource_name = ".$anvil->Database->quote($drbd_resource)."
+;";
+ $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 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 => 2, list => {
+ results => $results,
+ count => $count,
+ }});
+ foreach my $row (@{$results})
+ {
+ my $host_uuid = $row->[0];
+ my $short_host_name = $anvil->data->{hosts}{host_uuid}{$host_uuid}{short_host_name};
+ my $host_type = $anvil->data->{hosts}{host_uuid}{$host_uuid}{host_type};
+ my $scan_drbd_volume_number = $row->[2];
+ $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
+ 's1:host_uuid' => $host_uuid,
+ 's2:host_type' => $host_type,
+ 's3:short_host_name' => $short_host_name,
+ 's4:scan_drbd_volume_number' => $scan_drbd_volume_number,
+ }});
+
+ $anvil->data->{drbd_resource}{$drbd_resource}{host_uuid}{$host_uuid}{volume_number}{$scan_drbd_volume_number}{device_path} = $row->[3];
+ $anvil->data->{drbd_resource}{$drbd_resource}{host_uuid}{$host_uuid}{volume_number}{$scan_drbd_volume_number}{device_minor} = $row->[4];
+ $anvil->data->{drbd_resource}{$drbd_resource}{host_uuid}{$host_uuid}{volume_number}{$scan_drbd_volume_number}{volume_size} = $row->[5];
+ $anvil->data->{drbd_resource}{$drbd_resource}{host_type}{$host_type}{short_host_name}{$short_host_name}{host_uuid} = $host_uuid;
+ $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
+ "s1:drbd_resource::${drbd_resource}::host_uuid::${host_uuid}::volume_number::${scan_drbd_volume_number}::device_path" => $anvil->data->{drbd_resource}{$drbd_resource}{host_uuid}{$host_uuid}{volume_number}{$scan_drbd_volume_number}{device_path},
+ "s2:drbd_resource::${drbd_resource}::host_uuid::${host_uuid}::volume_number::${scan_drbd_volume_number}::device_minor" => $anvil->data->{drbd_resource}{$drbd_resource}{host_uuid}{$host_uuid}{volume_number}{$scan_drbd_volume_number}{device_minor},
+ "s3:drbd_resource::${drbd_resource}::host_uuid::${host_uuid}::volume_number::${scan_drbd_volume_number}::volume_size" => $anvil->data->{drbd_resource}{$drbd_resource}{host_uuid}{$host_uuid}{volume_number}{$scan_drbd_volume_number}{volume_size},
+ "s4:drbd_resource::${drbd_resource}::host_type::${host_type}::short_host_name::${short_host_name}::host_uuid" => $anvil->data->{drbd_resource}{$drbd_resource}{host_type}{$host_type}{short_host_name}{$short_host_name}{host_uuid},
+ }});
+
+ if (not exists $anvil->data->{drbd_resource}{$drbd_resource}{xml})
+ {
+ $anvil->data->{drbd_resource}{$drbd_resource}{xml} = $row->[1];
+ $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
+ "drbd_resource::${drbd_resource}::xml" => $anvil->data->{drbd_resource}{$drbd_resource}{xml},
+ }});
+ $anvil->DRBD->parse_resource({
+ debug => 2,
+ xml => $anvil->data->{drbd_resource}{$drbd_resource}{xml},
+ });
+ }
+ }
+
+ print "Sub-Nodes:\n";
+ show_volume($anvil, $drbd_resource, "node");
+
+ my $dr_count = keys %{$anvil->data->{drbd_resource}{$drbd_resource}{host_type}{dr}{short_host_name}};
+ $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { dr_count => $dr_count }});
+ if ($dr_count)
+ {
+ print "DR Hosts:\n";
+ show_volume($anvil, $drbd_resource, "dr");
+ }
+
+ return(0);
+}
+
+sub show_volume
+{
+ my ($anvil, $drbd_resource, $host_type) = @_;
+
+ foreach my $short_host_name (sort {$a cmp $b} keys %{$anvil->data->{drbd_resource}{$drbd_resource}{host_type}{$host_type}{short_host_name}})
+ {
+ my $host_uuid = $anvil->data->{drbd_resource}{$drbd_resource}{host_type}{$host_type}{short_host_name}{$short_host_name}{host_uuid};
+ $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
+ 's1:short_host_name' => $short_host_name,
+ 's2:host_uuid' => $host_uuid,
+ }});
+ print " |- Name: [".$short_host_name."], UUID: [".$host_uuid."]\n";
+ foreach my $volume_number (sort {$a cmp $b} keys %{$anvil->data->{drbd_resource}{$drbd_resource}{host_uuid}{$host_uuid}{volume_number}})
+ {
+ my $device_path = $anvil->data->{drbd_resource}{$drbd_resource}{host_uuid}{$host_uuid}{volume_number}{$volume_number}{device_path};
+ my $device_minor = $anvil->data->{drbd_resource}{$drbd_resource}{host_uuid}{$host_uuid}{volume_number}{$volume_number}{device_minor};
+ my $volume_size = $anvil->data->{drbd_resource}{$drbd_resource}{host_uuid}{$host_uuid}{volume_number}{$volume_number}{volume_size};
+ my $backing_disk = $anvil->data->{new}{resource}{$drbd_resource}{host_uuid}{$host_uuid}{volume_number}{$volume_number}{backing_disk};
+ my $meta_disk = $anvil->data->{new}{resource}{$drbd_resource}{host_uuid}{$host_uuid}{volume_number}{$volume_number}{meta_disk};
+ $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
+ 's1:volume_number' => $volume_number,
+ 's2:device_path' => $device_path,
+ 's3:device_minor' => $device_minor,
+ 's4:volume_size' => $volume_size,
+ 's5:backing_disk' => $backing_disk,
+ 's6:meta_disk' => $meta_disk,
+ }});
+ print " ^- Volume: [".$volume_number."], backing device: [".$backing_disk."], DRBD minor: [".$device_minor."], size: [".$anvil->Convert->bytes_to_human_readable({'bytes' => $volume_size})."]\n";
+ }
+ }
+
+ return(0);
+}
+
+sub show_server_list
+{
+ my ($anvil) = @_;
+
+ # Loop through all Anvil! nodes, then all server in that Anvil!
+ foreach my $anvil_name (sort {$a cmp $b} keys %{$anvil->data->{anvils}{anvil_name}})
+ {
+ my $anvil_uuid = $anvil->data->{anvils}{anvil_name}{$anvil_name}{anvil_uuid};
+ my $anvil_description = $anvil->data->{anvils}{anvil_name}{$anvil_name}{anvil_description};
+ $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
+ anvil_name => $anvil_name,
+ anvil_uuid => $anvil_uuid,
+ anvil_description => $anvil_description,
+ }});
+ if (($anvil->data->{switches}{anvil_uuid}) && ($anvil->data->{switches}{anvil_uuid} ne $anvil_uuid))
+ {
+ next;
+ }
+ print "\nAnvil! Node: [".$anvil_name."], UUID: [".$anvil_uuid."] - Description: [".$anvil_description."]\n";
+
+ my $server_count = 0;
+ if (exists $anvil->data->{servers}{anvil_uuid}{$anvil_uuid}{server_name})
+ {
+ $server_count = keys %{$anvil->data->{servers}{anvil_uuid}{$anvil_uuid}{server_name}};
+ $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { server_count => $server_count }});
+ }
+ if (not $server_count)
+ {
+ print "- No servers on this node yet\n";
+ }
+ else
+ {
+ foreach my $server_name (sort {$a cmp $b} keys %{$anvil->data->{servers}{anvil_uuid}{$anvil_uuid}{server_name}})
+ {
+ my $server_uuid = $anvil->data->{servers}{anvil_uuid}{$anvil_uuid}{server_name}{$server_name}{server_uuid};
+ $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
+ server_name => $server_name,
+ server_uuid => $server_uuid,
+ }});
+ print "^- Server: [".$server_name."], UUID: [".$server_uuid."]\n";
+ }
+ }
+ }
+
+ return(0);
+}