* Moved the scan-drbd function 'gather_drbd_date' and moved it into DRBD->gather_date().

* Finished DRBD->get_next_resource() that returns the next available minor and the next free TCP port (with two free ports available after it).
* Created Storage->get_storage_group_details() that pulls together the LVM, storage group members and storage groups into one block of data.
* Made more progress on tools/anvil-provision-server. It now gets up to the point of creating LVs, creating DRBD resource files, loading them, creating metadata and up'ing the resource. It doesn't yet (successfully) force a new resource to primary.

Signed-off-by: Digimer <digimer@alteeve.ca>
main
Digimer 4 years ago
parent 162f4913b1
commit 056f8edf48
  1. 3
      Anvil/Tools.pm
  2. 515
      Anvil/Tools/DRBD.pm
  3. 2
      Anvil/Tools/Get.pm
  4. 2
      Anvil/Tools/Job.pm
  5. 2
      Anvil/Tools/Network.pm
  6. 115
      Anvil/Tools/Storage.pm
  7. 396
      scancore-agents/scan-drbd/scan-drbd
  8. 66
      share/words.xml
  9. 565
      tools/anvil-provision-server
  10. 2
      tools/test.pl

@ -1048,12 +1048,14 @@ sub _set_paths
anvil => "/etc/anvil", anvil => "/etc/anvil",
backups => "/root/anvil-backups", backups => "/root/anvil-backups",
'cgi-bin' => "/var/www/cgi-bin", 'cgi-bin' => "/var/www/cgi-bin",
drbd_resources => "/etc/drbd.d/",
fence_agents => "/usr/sbin", fence_agents => "/usr/sbin",
firewalld_services => "/usr/lib/firewalld/services", firewalld_services => "/usr/lib/firewalld/services",
firewalld_zones_etc => "/etc/firewalld/zones", # Changes when firewall-cmd ... --permanent is used. firewalld_zones_etc => "/etc/firewalld/zones", # Changes when firewall-cmd ... --permanent is used.
firewalld_zones => "/usr/lib/firewalld/zones", firewalld_zones => "/usr/lib/firewalld/zones",
html => "/var/www/html", html => "/var/www/html",
ifcfg => "/etc/sysconfig/network-scripts", ifcfg => "/etc/sysconfig/network-scripts",
resource_status => "/sys/kernel/debug/drbd/resources",
scan_agents => "/usr/sbin/scancore-agents", scan_agents => "/usr/sbin/scancore-agents",
shared => { shared => {
archives => "/mnt/shared/archives", archives => "/mnt/shared/archives",
@ -1135,6 +1137,7 @@ sub _set_paths
ls => "/usr/bin/ls", ls => "/usr/bin/ls",
lsblk => "/usr/bin/lsblk", lsblk => "/usr/bin/lsblk",
lvchange => "/usr/sbin/lvchange", lvchange => "/usr/sbin/lvchange",
lvcreate => "/usr/sbin/lvcreate",
lvs => "/usr/sbin/lvs", lvs => "/usr/sbin/lvs",
lvscan => "/usr/sbin/lvscan", lvscan => "/usr/sbin/lvscan",
mailx => "/usr/bin/mailx", mailx => "/usr/bin/mailx",

@ -15,6 +15,7 @@ my $THIS_FILE = "DRBD.pm";
### Methods; ### Methods;
# allow_two_primaries # allow_two_primaries
# gather_data
# get_devices # get_devices
# get_status # get_status
# manage_resource # manage_resource
@ -234,6 +235,384 @@ sub allow_two_primaries
return($return_code); return($return_code);
} }
=head2 gather_data
This calls C<< drbdadm >> to collect the configuration of the local system and parses it. This methid is designed for use by C<< scan_drbd >>, but is useful elsewhere. This is note-worthy as the data is stored under a C<< new::... >> hash.
On error, C<< 1 >> is returned. On success, C<< 0 >> is returned.
This method takes no parameters.
=cut
sub gather_data
{
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->gather_data()" }});
my ($drbd_xml, $return_code) = $anvil->System->call({shell_call => $anvil->data->{path}{exe}{drbdadm}." dump-xml"});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { drbd_xml => $drbd_xml, return_code => $return_code }});
if ($return_code)
{
# Failed to dump the XML.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_drbd_error_0002", variables => { return_code => $return_code }});
return(1);
}
else
{
local $@;
my $dom = eval { XML::LibXML->load_xml(string => $drbd_xml); };
if ($@)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_drbd_error_0003", variables => {
xml => $drbd_xml,
error => $@,
}});
return(1);
}
else
{
# Successful parse!
### TODO: Might be best to config these default values by calling/parsing
### 'drbdsetup show <resource> --show-defaults'.
$anvil->data->{new}{scan_drbd}{scan_drbd_common_xml} = $drbd_xml;
$anvil->data->{new}{scan_drbd}{scan_drbd_flush_disk} = 1;
$anvil->data->{new}{scan_drbd}{scan_drbd_flush_md} = 1;
$anvil->data->{new}{scan_drbd}{scan_drbd_timeout} = 6; # Default is '60', 6 seconds
$anvil->data->{new}{scan_drbd}{scan_drbd_total_sync_speed} = 0;
foreach my $name ($dom->findnodes('/config/common/section'))
{
my $section = $name->{name};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { section => $section }});
foreach my $option_name ($name->findnodes('./option'))
{
my $variable = $option_name->{name};
my $value = $option_name->{value};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
's1:variable' => $variable,
's2:value' => $value,
}});
if ($section eq "net")
{
if ($variable eq "timeout")
{
$value /= 10;
$anvil->data->{new}{scan_drbd}{scan_drbd_timeout} = ($value / 10);
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"new::scan_drbd::scan_drbd_timeout" => $anvil->data->{new}{scan_drbd}{scan_drbd_timeout},
}});
}
}
if ($section eq "disk")
{
if ($variable eq "disk-flushes")
{
$anvil->data->{new}{scan_drbd}{scan_drbd_flush_disk} = $value eq "no" ? 0 : 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"new::scan_drbd::scan_drbd_flush_disk" => $anvil->data->{new}{scan_drbd}{scan_drbd_flush_disk},
}});
}
if ($variable eq "md-flushes")
{
$anvil->data->{new}{scan_drbd}{scan_drbd_flush_md} = $value eq "no" ? 0 : 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"new::scan_drbd::scan_drbd_flush_md" => $anvil->data->{new}{scan_drbd}{scan_drbd_flush_md},
}});
}
}
}
}
foreach my $name ($dom->findnodes('/config/resource'))
{
my $resource = $name->{name};
my $conf_file = $name->{'conf-file-line'};
$conf_file =~ s/:\d+$//;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
's1:resource' => $resource,
's2:conf_file' => $conf_file,
}});
$anvil->data->{new}{resource}{$resource}{up} = 0;
$anvil->data->{new}{resource}{$resource}{xml} = $name->toString;
$anvil->data->{new}{resource}{$resource}{config_file} = $conf_file;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"new::resource::${resource}::xml" => $anvil->data->{new}{resource}{$resource}{xml},
"new::resource::${resource}::config_file" => $anvil->data->{new}{resource}{$resource}{config_file},
}});
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 }});
next if (($this_host_name ne $anvil->Get->host_name) && ($this_host_name ne $anvil->Get->short_host_name));
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,
}});
$anvil->data->{new}{resource}{$resource}{volume}{$volume}{device_path} = $volume_vnr->findvalue('./device');
$anvil->data->{new}{resource}{$resource}{volume}{$volume}{device_minor} = $volume_vnr->findvalue('./device/@minor');
$anvil->data->{new}{resource}{$resource}{volume}{$volume}{size} = 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"s1:new::resource::${resource}::volume::${volume}::device_path" => $anvil->data->{new}{resource}{$resource}{volume}{$volume}{device_path},
"s2:new::resource::${resource}::volume::${volume}::device_minor" => $anvil->data->{new}{resource}{$resource}{volume}{$volume}{device_minor},
}});
}
}
foreach my $connection ($name->findnodes('./connection'))
{
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 }});
next if (($this_host_name eq $anvil->Get->host_name) or ($this_host_name eq $anvil->Get->short_host_name));
$peer = $this_host_name;
$anvil->data->{new}{resource}{$resource}{peer}{$peer}{peer_ip_address} = $host->findvalue('./address');
$anvil->data->{new}{resource}{$resource}{peer}{$peer}{tcp_port} = $host->findvalue('./address/@port');;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"s1:new::resource::${resource}::peer::${peer}::peer_ip_address" => $anvil->data->{new}{resource}{$resource}{peer}{$peer}{peer_ip_address},
"s2:new::resource::${resource}::peer::${peer}::tcp_port" => $anvil->data->{new}{resource}{$resource}{peer}{$peer}{tcp_port},
}});
if (not exists $anvil->data->{new}{resource}{$resource}{peer}{$peer}{protocol})
{
$anvil->data->{new}{resource}{$resource}{peer}{$peer}{protocol} = "unknown";
$anvil->data->{new}{resource}{$resource}{peer}{$peer}{fencing} = "unknown";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"s1:new::resource::${resource}::peer::${peer}::protocol" => $anvil->data->{new}{resource}{$resource}{peer}{$peer}{protocol},
"s2:new::resource::${resource}::peer::${peer}::fencing" => $anvil->data->{new}{resource}{$resource}{peer}{$peer}{fencing},
}});
}
foreach my $volume (sort {$a cmp $b} keys %{$anvil->data->{new}{resource}{$resource}{volume}})
{
$anvil->data->{new}{resource}{$resource}{volume}{$volume}{peer}{$peer}{connection_state} = "disconnected";
$anvil->data->{new}{resource}{$resource}{volume}{$volume}{peer}{$peer}{local_disk_state} = "down";
$anvil->data->{new}{resource}{$resource}{volume}{$volume}{peer}{$peer}{peer_disk_state} = "unknown";
$anvil->data->{new}{resource}{$resource}{volume}{$volume}{peer}{$peer}{local_role} = "down";
$anvil->data->{new}{resource}{$resource}{volume}{$volume}{peer}{$peer}{peer_role} = "unknown";
$anvil->data->{new}{resource}{$resource}{volume}{$volume}{peer}{$peer}{out_of_sync_size} = -1;
$anvil->data->{new}{resource}{$resource}{volume}{$volume}{peer}{$peer}{replication_speed} = 0;
$anvil->data->{new}{resource}{$resource}{volume}{$volume}{peer}{$peer}{estimated_time_to_sync} = 0;
}
}
foreach my $name ($connection->findnodes('./section'))
{
my $section = $name->{name};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { section => $section }});
foreach my $option_name ($name->findnodes('./option'))
{
my $variable = $option_name->{name};
my $value = $option_name->{value};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
's1:variable' => $variable,
's2:value' => $value,
}});
if ($section eq "net")
{
if ($variable eq "protocol")
{
$anvil->data->{new}{resource}{$resource}{peer}{$peer}{protocol} = $value;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"new::resource::${resource}::peer::${peer}::protocol" => $anvil->data->{new}{resource}{$resource}{peer}{$peer}{protocol},
}});
}
if ($variable eq "fencing")
{
$anvil->data->{new}{resource}{$resource}{peer}{$peer}{fencing} = $value;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"new::resource::${resource}::peer::${peer}::fencing" => $anvil->data->{new}{resource}{$resource}{peer}{$peer}{fencing},
}});
}
}
}
}
}
}
}
}
# If DRBD is stopped, this directory won't exist.
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"path::directories::resource_status" => $anvil->data->{path}{directories}{resource_status},
}});
if (-d $anvil->data->{path}{directories}{resource_status})
{
local(*DIRECTORY);
opendir(DIRECTORY, $anvil->data->{path}{directories}{resource_status});
while(my $file = readdir(DIRECTORY))
{
next if $file eq ".";
next if $file eq "..";
my $full_path = $anvil->data->{path}{directories}{resource_status}."/".$file;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { full_path => $full_path }});
if (-d $full_path)
{
my $resource = $file;
$anvil->data->{new}{resource}{$resource}{up} = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"new::resource::${resource}::up" => $anvil->data->{new}{resource}{$resource}{up},
}});
}
}
closedir(DIRECTORY);
}
foreach my $resource (sort {$a cmp $b} keys %{$anvil->data->{new}{resource}})
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"new::resource::${resource}::up" => $anvil->data->{new}{resource}{$resource}{up},
}});
# If the resource isn't up, there's won't be a proc file to read.
next if not $anvil->data->{new}{resource}{$resource}{up};
foreach my $volume (sort {$a cmp $b} keys %{$anvil->data->{new}{resource}{$resource}{volume}})
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { volume => $volume }});
foreach my $peer (sort {$a cmp $b} keys %{$anvil->data->{new}{resource}{$resource}{volume}{$volume}{peer}})
{
my $proc_file = $anvil->data->{path}{directories}{resource_status}."/".$resource."/connections/".$peer."/".$volume."/proc_drbd";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { proc_file => $proc_file }});
my $file_body = $anvil->Storage->read_file({file => $proc_file});
my $progress = "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { file_body => $file_body }});
foreach my $line (split/\n/, $file_body)
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { line => $line }});
if ($line =~ /cs:(.*?) /)
{
$anvil->data->{new}{resource}{$resource}{volume}{$volume}{peer}{$peer}{connection_state} = lc($1);
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"new::resource::${resource}::volume::${volume}::peer::${peer}::connection_state" => $anvil->data->{new}{resource}{$resource}{volume}{$volume}{peer}{$peer}{connection_state},
}});
}
if ($line =~ /ro:(.*?)\/(.*?) /)
{
$anvil->data->{new}{resource}{$resource}{volume}{$volume}{peer}{$peer}{local_role} = lc($1);
$anvil->data->{new}{resource}{$resource}{volume}{$volume}{peer}{$peer}{peer_role} = lc($2);
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"new::resource::${resource}::volume::${volume}::peer::${peer}::local_role" => $anvil->data->{new}{resource}{$resource}{volume}{$volume}{peer}{$peer}{local_role},
"new::resource::${resource}::volume::${volume}::peer::${peer}::peer_role" => $anvil->data->{new}{resource}{$resource}{volume}{$volume}{peer}{$peer}{peer_role},
}});
# If the peer is secondary, read the device size.
if ($anvil->data->{new}{resource}{$resource}{volume}{$volume}{peer}{$peer}{peer_role} eq "secondary")
{
# Get the size of the DRBD device.
my ($size, $return_code) = $anvil->System->call({secure => 1, shell_call => $anvil->data->{path}{exe}{blockdev}." --getsize64 /dev/drbd".$anvil->data->{new}{resource}{$resource}{volume}{$volume}{device_minor}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
size => $size,
return_code => $return_code,
}});
if (not $return_code)
{
$anvil->data->{new}{resource}{$resource}{volume}{$volume}{size} = $size;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"new::resource::${resource}::volume::${volume}::size" => $anvil->data->{new}{resource}{$resource}{volume}{$volume}{size}." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{new}{resource}{$resource}{volume}{$volume}{size}}).")",
}});
}
}
}
if ($line =~ /ds:(.*?)\/(.*?) /)
{
$anvil->data->{new}{resource}{$resource}{volume}{$volume}{peer}{$peer}{local_disk_state} = lc($1);
$anvil->data->{new}{resource}{$resource}{volume}{$volume}{peer}{$peer}{peer_disk_state} = lc($2);
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"new::resource::${resource}::volume::${volume}::peer::${peer}::local_disk_state" => $anvil->data->{new}{resource}{$resource}{volume}{$volume}{peer}{$peer}{local_disk_state},
"new::resource::${resource}::volume::${volume}::peer::${peer}::peer_disk_state" => $anvil->data->{new}{resource}{$resource}{volume}{$volume}{peer}{$peer}{peer_disk_state},
}});
}
if ($line =~ /oos:(\d+)/)
{
$anvil->data->{new}{resource}{$resource}{volume}{$volume}{peer}{$peer}{out_of_sync_size} = $1 * 1024;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"new::resource::${resource}::volume::${volume}::peer::${peer}::out_of_sync_size" => $anvil->data->{new}{resource}{$resource}{volume}{$volume}{peer}{$peer}{out_of_sync_size}." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{new}{resource}{$resource}{volume}{$volume}{peer}{$peer}{out_of_sync_size}}).")",
}});
}
=cut
0: cs:Established ro:Secondary/Secondary ds:Inconsistent/Inconsistent C r-----
ns:0 nr:0 dw:0 dr:0 al:0 bm:0 lo:0 pe:[0;0] ua:0 ap:[0;0] ep:1 wo:1 oos:0
resync: used:0/61 hits:0 misses:0 starving:0 locked:0 changed:0
act_log: used:0/1237 hits:0 misses:0 starving:0 locked:0 changed:0
blocked on activity log: 0/0/0
0: cs:SyncTarget ro:Secondary/Primary ds:Inconsistent/UpToDate C r-----
ns:0 nr:648960 dw:648728 dr:0 al:0 bm:0 lo:4 pe:[0;1] ua:4 ap:[0;0] ep:1 wo:1 oos:20321476
[>....................] sync'ed: 3.2% (19844/20476)M
finish: 0:03:39 speed: 92,672 (92,936 -- 92,672) want: 2,880 K/sec
3% sector pos: 1298032/41940408
resync: used:1/61 hits:31926 misses:10 starving:0 locked:0 changed:5
act_log: used:0/1237 hits:0 misses:0 starving:0 locked:0 changed:0
blocked on activity log: 0/0/0
=cut
if ($line =~ /sync'ed:\s+(\d.*\%)/)
{
$progress .= $1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { progress => $progress }});
}
if ($line =~ /speed: (.*?) \(/)
{
$anvil->data->{new}{resource}{$resource}{volume}{$volume}{peer}{$peer}{replication_speed} = $1;
$anvil->data->{new}{resource}{$resource}{volume}{$volume}{peer}{$peer}{replication_speed} =~ s/,//g;
$anvil->data->{new}{resource}{$resource}{volume}{$volume}{peer}{$peer}{replication_speed} *= 1024;
$anvil->data->{new}{scan_drbd}{scan_drbd_total_sync_speed} += $anvil->data->{new}{resource}{$resource}{volume}{$volume}{peer}{$peer}{replication_speed};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"s1:new::resource::${resource}::volume::${volume}::peer::${peer}::replication_speed" => $anvil->data->{new}{resource}{$resource}{volume}{$volume}{peer}{$peer}{replication_speed}." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{new}{resource}{$resource}{volume}{$volume}{peer}{$peer}{replication_speed}}).")",
"s2:new::scan_drbd::scan_drbd_total_sync_speed" => $anvil->data->{new}{scan_drbd}{scan_drbd_total_sync_speed}." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{new}{scan_drbd}{scan_drbd_total_sync_speed}}).")",
}});
}
if ($line =~ /finish: (\d+):(\d+):(\d+) /)
{
my $hours = $1;
my $minutes = $2;
my $seconds = $3;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
's1:hours' => $hours,
's2:minutes' => $minutes,
's3:seconds' => $seconds,
}});
$anvil->data->{new}{resource}{$resource}{volume}{$volume}{peer}{$peer}{estimated_time_to_sync} = (($hours * 3600) + ($minutes * 60) + $seconds);
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"new::resource::${resource}::volume::${volume}::peer::${peer}::estimated_time_to_sync" => $anvil->data->{new}{resource}{$resource}{volume}{$volume}{peer}{$peer}{estimated_time_to_sync}." (".$anvil->Convert->time({'time' => $anvil->data->{new}{resource}{$resource}{volume}{$volume}{peer}{$peer}{estimated_time_to_sync}, long => 1, translate => 1}).")",
}});
}
}
}
}
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"new::scan_drbd::scan_drbd_total_sync_speed" => $anvil->data->{new}{scan_drbd}{scan_drbd_total_sync_speed}." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{new}{scan_drbd}{scan_drbd_total_sync_speed}}).")",
}});
return(0);
}
=head2 get_devices =head2 get_devices
This finds all of the configured '/dev/drbdX' devices and maps them to their resource names. This finds all of the configured '/dev/drbdX' devices and maps them to their resource names.
@ -571,8 +950,141 @@ sub get_next_resource
}}); }});
my $query = " my $query = "
SELECT
scan_drbd_resource_host_uuid,
scan_drbd_resource_name,
scan_drbd_resource_xml
FROM
scan_drbd_resources
WHERE
scan_drbd_resource_host_uuid = ".$anvil->Database->quote($node1_host_uuid)."
OR
scan_drbd_resource_host_uuid = ".$anvil->Database->quote($node2_host_uuid)." ";
if ($dr1_host_uuid)
{
$query .= "
OR
scan_drbd_resource_host_uuid = ".$anvil->Database->quote($dr1_host_uuid)." ";
}
$query .= "
ORDER BY
scan_drbd_resource_name ASC
;"; ;";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, 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 => $debug, list => {
results => $results,
count => $count,
}});
foreach my $row (@{$results})
{
my $scan_drbd_resource_host_uuid = $row->[0];
my $scan_drbd_resource_name = $row->[1];
my $scan_drbd_resource_xml = $row->[2];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
scan_drbd_resource_host_uuid => $scan_drbd_resource_host_uuid,
scan_drbd_resource_name => $scan_drbd_resource_name,
scan_drbd_resource_xml => $scan_drbd_resource_xml,
}});
next if $scan_drbd_resource_xml eq "DELETED";
local $@;
my $dom = eval { XML::LibXML->load_xml(string => $scan_drbd_resource_xml); };
if ($@)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "error_0111", variables => {
xml_body => $scan_drbd_resource_xml,
eval_error => $@,
}});
next;
}
# Successful parse!
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 $host_name = $host->{name};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { host_name => $host_name }});
foreach my $volume_vnr ($host->findnodes('./volume'))
{
my $volume = $volume_vnr->{vnr};
my $minor = $volume_vnr->findvalue('./device/@minor');
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
's1:host_name' => $host_name." \@ ".$resource."/".$volume,
's2:minor' => $minor,
}});
$anvil->data->{drbd}{used_resources}{minor}{$minor}{used} = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"drbd::used_resources::minor::${minor}::used" => $anvil->data->{drbd}{used_resources}{minor}{$minor}{used},
}});
}
}
foreach my $connection ($name->findnodes('./connection'))
{
foreach my $host ($connection->findnodes('./host'))
{
my $host_name = $host->{name};
my $tcp_port = $host->findvalue('./address/@port');
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
host_name => $host_name,
tcp_port => $tcp_port,
}});
$anvil->data->{drbd}{used_resources}{tcp_port}{$tcp_port}{used} = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"drbd::used_resources::tcp_port::${tcp_port}::used" => $anvil->data->{drbd}{used_resources}{tcp_port}{$tcp_port}{used},
}});
}
}
}
}
my $looking = 1;
$free_minor = 0;
while($looking)
{
if (exists $anvil->data->{drbd}{used_resources}{minor}{$free_minor})
{
$free_minor++;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { free_minor => $free_minor }});
}
else
{
$looking = 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { looking => $looking }});
}
}
$looking = 1;
$free_port = 7788;
while($looking)
{
if (exists $anvil->data->{drbd}{used_resources}{tcp_port}{$free_port})
{
$free_port += 3;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { free_port => $free_port }});
}
else
{
$looking = 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { looking => $looking }});
}
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
free_minor => $free_minor,
free_port => $free_port,
}});
return($free_minor, $free_port); return($free_minor, $free_port);
} }
@ -902,7 +1414,6 @@ sub manage_resource
} }
### TODO: Sanity check the resource name and task requested. ### TODO: Sanity check the resource name and task requested.
my $shell_call = $anvil->data->{path}{exe}{drbdadm}." ".$task." ".$resource; my $shell_call = $anvil->data->{path}{exe}{drbdadm}." ".$task." ".$resource;
my $output = ""; my $output = "";
my $return_code = 255; my $return_code = 255;
@ -993,7 +1504,7 @@ sub reload_defaults
return($return_code); return($return_code);
} }
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 0, level => 2, key => "log_0355"}); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 0, level => $debug, key => "log_0355"});
my $shell_call = $anvil->data->{path}{exe}{drbdadm}." adjust ".$resource; my $shell_call = $anvil->data->{path}{exe}{drbdadm}." adjust ".$resource;
my $output = ""; my $output = "";
if ($anvil->Network->is_local({host => $target})) if ($anvil->Network->is_local({host => $target}))

@ -1231,6 +1231,8 @@ sub host_name
This takes a host UUID and returns the host name (as recorded in the C<< hosts >> table). If the entry is not found, an empty string is returned. This takes a host UUID and returns the host name (as recorded in the C<< hosts >> table). If the entry is not found, an empty string is returned.
my $host_name = $anvil->Get->host_name_from_uuid({host_uuid => "8da3d2fe-783a-4619-abb5-8ccae58f7bd6"});
Parameters; Parameters;
=head3 host_uuid (required) =head3 host_uuid (required)

@ -371,7 +371,7 @@ AND
{ {
# Found it # Found it
$job_uuid = defined $results->[0]->[0] ? $results->[0]->[0] : ""; $job_uuid = defined $results->[0]->[0] ? $results->[0]->[0] : "";
$anvil->data->{jobs}{job_uuid} = $job_uuid; $anvil->data->{jobs}{'job-uuid'} = $job_uuid;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
job_uuid => $job_uuid, job_uuid => $job_uuid,
"jobs::job-uuid" => $anvil->data->{jobs}{'job-uuid'}, "jobs::job-uuid" => $anvil->data->{jobs}{'job-uuid'},

@ -750,6 +750,8 @@ sub find_matches
This uses the IP information for the local machine and a target host UUID, and returns an IP address that can be used to contact it. When multiple networks are shared, the BCN IP is used. If no match is found, an empty string is returned. This uses the IP information for the local machine and a target host UUID, and returns an IP address that can be used to contact it. When multiple networks are shared, the BCN IP is used. If no match is found, an empty string is returned.
my $target_ip = $anvil->Network->find_target_ip({host_uuid => "8da3d2fe-783a-4619-abb5-8ccae58f7bd6"});
Parameters; Parameters;
=head3 host_uuid (required) =head3 host_uuid (required)

@ -22,6 +22,7 @@ my $THIS_FILE = "Storage.pm";
# copy_file # copy_file
# find # find
# get_file_stats # get_file_stats
# get_storage_group_details
# make_directory # make_directory
# move_file # move_file
# parse_lsblk # parse_lsblk
@ -1454,6 +1455,120 @@ sub get_file_stats
} }
=head2 get_storage_group_details
This takes a C<< storage_group_uuid >> and loads information about members into the following hash;
storage_groups::storage_group_uuid::<storage_group_uuid>::storage_group_name
storage_groups::storage_group_uuid::<storage_group_uuid>::host_uuid::<host_uuid>::vg_internal_uuid
storage_groups::storage_group_uuid::<storage_group_uuid>::host_uuid::<host_uuid>::vg_name
storage_groups::storage_group_uuid::<storage_group_uuid>::host_uuid::<host_uuid>::vg_size
storage_groups::storage_group_uuid::<storage_group_uuid>::host_uuid::<host_uuid>::vg_free
On success, C<< 0 >> is returned. On failure, C<< !!error!! >> is returned.
Parameters;
=head3 storage_group_uuid (required)
This is the specific C<< storage_groups >> -> C<< storage_group_uuid >> that we're loading data about.
=cut
sub get_storage_group_details
{
my $self = shift;
my $parameter = shift;
my $anvil = $self->parent;
my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3;
my $test = defined $parameter->{test} ? $parameter->{test} : 0;
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "Storage->get_storage_group_details()" }});
my $storage_group_uuid = defined $parameter->{storage_group_uuid} ? $parameter->{storage_group_uuid} : "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
storage_group_uuid => $storage_group_uuid,
}});
if (not $storage_group_uuid)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Storage->get_storage_group_details()", parameter => "storage_group_uuid" }});
return('!!error!!');
}
my $query = "
SELECT
a.storage_group_name,
b.storage_group_member_vg_uuid,
c.scan_lvm_vg_name,
c.scan_lvm_vg_size,
c.scan_lvm_vg_free,
c.scan_lvm_vg_extent_size,
c.scan_lvm_vg_host_uuid
FROM
storage_groups a,
storage_group_members b,
scan_lvm_vgs c
WHERE
a.storage_group_uuid = b.storage_group_member_storage_group_uuid
AND
b.storage_group_member_vg_uuid = c.scan_lvm_vg_internal_uuid
AND
a.storage_group_uuid = ".$anvil->Database->quote($storage_group_uuid)."
;";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, 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 => $debug, list => {
results => $results,
count => $count,
}});
if (not $count)
{
# Group not found.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "error_0199", variables => { storage_group_uuid => $storage_group_uuid }});
return('!!error!!');
}
foreach my $row (@{$results})
{
my $storage_group_name = $row->[0];
my $vg_internal_uuid = $row->[1];
my $vg_name = $row->[2];
my $vg_size = $row->[3];
my $vg_free = $row->[4];
my $vg_extent_size = $row->[5];
my $host_uuid = $row->[6];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
storage_group_name => $storage_group_name,
vg_internal_uuid => $count,
vg_name => $vg_name,
vg_size => $vg_size." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $vg_size}).")",
vg_free => $vg_free." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $vg_free}).")",
vg_extent_size => $vg_extent_size." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $vg_extent_size}).")",
host_uuid => $host_uuid,
}});
$anvil->data->{storage_groups}{storage_group_uuid}{$storage_group_uuid}{storage_group_name} = $storage_group_name;
$anvil->data->{storage_groups}{storage_group_uuid}{$storage_group_uuid}{host_uuid}{$host_uuid}{vg_internal_uuid} = $vg_internal_uuid;
$anvil->data->{storage_groups}{storage_group_uuid}{$storage_group_uuid}{host_uuid}{$host_uuid}{vg_name} = $vg_name;
$anvil->data->{storage_groups}{storage_group_uuid}{$storage_group_uuid}{host_uuid}{$host_uuid}{vg_size} = $vg_size;
$anvil->data->{storage_groups}{storage_group_uuid}{$storage_group_uuid}{host_uuid}{$host_uuid}{vg_free} = $vg_free;
$anvil->data->{storage_groups}{storage_group_uuid}{$storage_group_uuid}{host_uuid}{$host_uuid}{vg_extent_size} = $vg_extent_size;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"storage_groups::storage_group_uuid::${storage_group_uuid}::storage_group_name" => $anvil->data->{storage_groups}{storage_group_uuid}{$storage_group_uuid}{storage_group_name},
"storage_groups::storage_group_uuid::${storage_group_uuid}::host_uuid::${host_uuid}::vg_internal_uuid" => $anvil->data->{storage_groups}{storage_group_uuid}{$storage_group_uuid}{host_uuid}{$host_uuid}{vg_internal_uuid},
"storage_groups::storage_group_uuid::${storage_group_uuid}::host_uuid::${host_uuid}::vg_name" => $anvil->data->{storage_groups}{storage_group_uuid}{$storage_group_uuid}{host_uuid}{$host_uuid}{vg_name},
"storage_groups::storage_group_uuid::${storage_group_uuid}::host_uuid::${host_uuid}::vg_size" => $anvil->data->{storage_groups}{storage_group_uuid}{$storage_group_uuid}{host_uuid}{$host_uuid}{vg_size}." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{storage_groups}{storage_group_uuid}{$storage_group_uuid}{host_uuid}{$host_uuid}{vg_size}}).")",
"storage_groups::storage_group_uuid::${storage_group_uuid}::host_uuid::${host_uuid}::vg_free" => $anvil->data->{storage_groups}{storage_group_uuid}{$storage_group_uuid}{host_uuid}{$host_uuid}{vg_free}." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{storage_groups}{storage_group_uuid}{$storage_group_uuid}{host_uuid}{$host_uuid}{vg_free}}).")",
"storage_groups::storage_group_uuid::${storage_group_uuid}::host_uuid::${host_uuid}::vg_extent_size" => $anvil->data->{storage_groups}{storage_group_uuid}{$storage_group_uuid}{host_uuid}{$host_uuid}{vg_free}." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{storage_groups}{storage_group_uuid}{$storage_group_uuid}{host_uuid}{$host_uuid}{vg_extent_size}}).")",
}});
}
return(0);
}
=head2 make_directory =head2 make_directory
This creates a directory (and any parent directories). This creates a directory (and any parent directories).

@ -40,12 +40,8 @@ my $anvil = Anvil::Tools->new({log_level => 2, log_secure => 1});
$anvil->Log->level({set => 2}); $anvil->Log->level({set => 2});
$anvil->Log->secure({set => 1}); $anvil->Log->secure({set => 1});
$anvil->data->{'scan-drbd'} = { $anvil->data->{'scan-drbd'}{alert_sort} = 2;
resource_status => "/sys/kernel/debug/drbd/resources", $anvil->data->{'scan-drbd'}{queries} = [];
config_directory => "/etc/drbd.d",
alert_sort => 2,
queries => [],
};
# Make sure we're running as 'root' # Make sure we're running as 'root'
# $< == real UID, $> == effective UID # $< == real UID, $> == effective UID
@ -92,7 +88,7 @@ if ($anvil->data->{switches}{purge})
$anvil->nice_exit({exit_code => 0}); $anvil->nice_exit({exit_code => 0});
} }
if (not gather_data($anvil)) if ($anvil->DRBD->gather_data())
{ {
# DRBD not found or configured. # DRBD not found or configured.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, key => "scan_drbd_error_0001"}); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, key => "scan_drbd_error_0001"});
@ -1092,392 +1088,6 @@ WHERE
return(0); return(0);
} }
sub gather_data
{
my ($anvil) = @_;
if ((not -e $anvil->data->{path}{exe}{drbdadm}) or ($anvil->Get->host_type eq "striker"))
{
# DRBD isn't installed or this is a striker node.
return(0);
}
# Parse drbdadm
my ($drbd_xml, $return_code) = $anvil->System->call({shell_call => $anvil->data->{path}{exe}{drbdadm}." dump-xml"});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { drbd_xml => $drbd_xml, return_code => $return_code }});
if ($return_code)
{
# Failed to dump the XML.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_drbd_error_0002", variables => { return_code => $return_code }});
return(0);
}
else
{
local $@;
my $dom = eval { XML::LibXML->load_xml(string => $drbd_xml); };
if ($@)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_drbd_error_0003", variables => {
xml => $drbd_xml,
error => $@,
}});
return(0);
}
else
{
# Successful parse!
### TODO: Might be best to config these default values by calling/parsing
### 'drbdsetup show <resource> --show-defaults'.
$anvil->data->{new}{scan_drbd}{scan_drbd_common_xml} = $drbd_xml;
$anvil->data->{new}{scan_drbd}{scan_drbd_flush_disk} = 1;
$anvil->data->{new}{scan_drbd}{scan_drbd_flush_md} = 1;
$anvil->data->{new}{scan_drbd}{scan_drbd_timeout} = 6; # Default is '60', 6 seconds
$anvil->data->{new}{scan_drbd}{scan_drbd_total_sync_speed} = 0;
foreach my $name ($dom->findnodes('/config/common/section'))
{
my $section = $name->{name};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { section => $section }});
foreach my $option_name ($name->findnodes('./option'))
{
my $variable = $option_name->{name};
my $value = $option_name->{value};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
's1:variable' => $variable,
's2:value' => $value,
}});
if ($section eq "net")
{
if ($variable eq "timeout")
{
$value /= 10;
$anvil->data->{new}{scan_drbd}{scan_drbd_timeout} = ($value / 10);
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"new::scan_drbd::scan_drbd_timeout" => $anvil->data->{new}{scan_drbd}{scan_drbd_timeout},
}});
}
}
if ($section eq "disk")
{
if ($variable eq "disk-flushes")
{
$anvil->data->{new}{scan_drbd}{scan_drbd_flush_disk} = $value eq "no" ? 0 : 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"new::scan_drbd::scan_drbd_flush_disk" => $anvil->data->{new}{scan_drbd}{scan_drbd_flush_disk},
}});
}
if ($variable eq "md-flushes")
{
$anvil->data->{new}{scan_drbd}{scan_drbd_flush_md} = $value eq "no" ? 0 : 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"new::scan_drbd::scan_drbd_flush_md" => $anvil->data->{new}{scan_drbd}{scan_drbd_flush_md},
}});
}
}
}
}
foreach my $name ($dom->findnodes('/config/resource'))
{
my $resource = $name->{name};
my $conf_file = $name->{'conf-file-line'};
$conf_file =~ s/:\d+$//;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
's1:resource' => $resource,
's2:conf_file' => $conf_file,
}});
$anvil->data->{new}{resource}{$resource}{up} = 0;
$anvil->data->{new}{resource}{$resource}{xml} = $name->toString;
$anvil->data->{new}{resource}{$resource}{config_file} = $conf_file;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
"new::resource::${resource}::xml" => $anvil->data->{new}{resource}{$resource}{xml},
"new::resource::${resource}::config_file" => $anvil->data->{new}{resource}{$resource}{config_file},
}});
### NOTE: We don't do this anymore.
# See if there's a scan_drbd_resource_uuid in the config file.
#my $scan_drbd_resource_uuid = $anvil->DRBD->resource_uuid({
# resource => $resource,
# resource_file => $conf_file,
#});
#$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { scan_drbd_resource_uuid => $scan_drbd_resource_uuid }});
#
#$anvil->data->{new}{resource}{$resource}{scan_drbd_resource_uuid} = $scan_drbd_resource_uuid eq "!!error!!" ? "" : $scan_drbd_resource_uuid;
#$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
# "new::resource::${resource}::scan_drbd_resource_uuid" => $anvil->data->{new}{resource}{$resource}{scan_drbd_resource_uuid},
#}});
foreach my $host ($name->findnodes('./host'))
{
my $this_host_name = $host->{name};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { this_host_name => $this_host_name }});
next if (($this_host_name ne $anvil->Get->host_name) && ($this_host_name ne $anvil->Get->short_host_name));
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 => 2, list => {
's1:volume' => $volume,
's2:meta_disk' => $meta_disk,
}});
$anvil->data->{new}{resource}{$resource}{volume}{$volume}{device_path} = $volume_vnr->findvalue('./device');
$anvil->data->{new}{resource}{$resource}{volume}{$volume}{device_minor} = $volume_vnr->findvalue('./device/@minor');
$anvil->data->{new}{resource}{$resource}{volume}{$volume}{size} = 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"s1:new::resource::${resource}::volume::${volume}::device_path" => $anvil->data->{new}{resource}{$resource}{volume}{$volume}{device_path},
"s2:new::resource::${resource}::volume::${volume}::device_minor" => $anvil->data->{new}{resource}{$resource}{volume}{$volume}{device_minor},
}});
}
}
foreach my $connection ($name->findnodes('./connection'))
{
my $peer = "";
foreach my $host ($connection->findnodes('./host'))
{
my $this_host_name = $host->{name};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { this_host_name => $this_host_name }});
next if (($this_host_name eq $anvil->Get->host_name) or ($this_host_name eq $anvil->Get->short_host_name));
$peer = $this_host_name;
$anvil->data->{new}{resource}{$resource}{peer}{$peer}{peer_ip_address} = $host->findvalue('./address');
$anvil->data->{new}{resource}{$resource}{peer}{$peer}{tcp_port} = $host->findvalue('./address/@port');;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"s1:new::resource::${resource}::peer::${peer}::peer_ip_address" => $anvil->data->{new}{resource}{$resource}{peer}{$peer}{peer_ip_address},
"s2:new::resource::${resource}::peer::${peer}::tcp_port" => $anvil->data->{new}{resource}{$resource}{peer}{$peer}{tcp_port},
}});
if (not exists $anvil->data->{new}{resource}{$resource}{peer}{$peer}{protocol})
{
$anvil->data->{new}{resource}{$resource}{peer}{$peer}{protocol} = "unknown";
$anvil->data->{new}{resource}{$resource}{peer}{$peer}{fencing} = "unknown";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"s1:new::resource::${resource}::peer::${peer}::protocol" => $anvil->data->{new}{resource}{$resource}{peer}{$peer}{protocol},
"s2:new::resource::${resource}::peer::${peer}::fencing" => $anvil->data->{new}{resource}{$resource}{peer}{$peer}{fencing},
}});
}
foreach my $volume (sort {$a cmp $b} keys %{$anvil->data->{new}{resource}{$resource}{volume}})
{
$anvil->data->{new}{resource}{$resource}{volume}{$volume}{peer}{$peer}{connection_state} = "disconnected";
$anvil->data->{new}{resource}{$resource}{volume}{$volume}{peer}{$peer}{local_disk_state} = "down";
$anvil->data->{new}{resource}{$resource}{volume}{$volume}{peer}{$peer}{peer_disk_state} = "unknown";
$anvil->data->{new}{resource}{$resource}{volume}{$volume}{peer}{$peer}{local_role} = "down";
$anvil->data->{new}{resource}{$resource}{volume}{$volume}{peer}{$peer}{peer_role} = "unknown";
$anvil->data->{new}{resource}{$resource}{volume}{$volume}{peer}{$peer}{out_of_sync_size} = -1;
$anvil->data->{new}{resource}{$resource}{volume}{$volume}{peer}{$peer}{replication_speed} = 0;
$anvil->data->{new}{resource}{$resource}{volume}{$volume}{peer}{$peer}{estimated_time_to_sync} = 0;
}
}
foreach my $name ($connection->findnodes('./section'))
{
my $section = $name->{name};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { section => $section }});
foreach my $option_name ($name->findnodes('./option'))
{
my $variable = $option_name->{name};
my $value = $option_name->{value};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
's1:variable' => $variable,
's2:value' => $value,
}});
if ($section eq "net")
{
if ($variable eq "protocol")
{
$anvil->data->{new}{resource}{$resource}{peer}{$peer}{protocol} = $value;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"new::resource::${resource}::peer::${peer}::protocol" => $anvil->data->{new}{resource}{$resource}{peer}{$peer}{protocol},
}});
}
if ($variable eq "fencing")
{
$anvil->data->{new}{resource}{$resource}{peer}{$peer}{fencing} = $value;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"new::resource::${resource}::peer::${peer}::fencing" => $anvil->data->{new}{resource}{$resource}{peer}{$peer}{fencing},
}});
}
}
}
}
}
}
}
}
# If DRBD is stopped, this directory won't exist.
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"scan-drbd::resource_status" => $anvil->data->{'scan-drbd'}{resource_status},
}});
if (-d $anvil->data->{'scan-drbd'}{resource_status})
{
local(*DIRECTORY);
opendir(DIRECTORY, $anvil->data->{'scan-drbd'}{resource_status});
while(my $file = readdir(DIRECTORY))
{
next if $file eq ".";
next if $file eq "..";
my $full_path = $anvil->data->{'scan-drbd'}{resource_status}."/".$file;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { full_path => $full_path }});
if (-d $full_path)
{
my $resource = $file;
$anvil->data->{new}{resource}{$resource}{up} = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"new::resource::${resource}::up" => $anvil->data->{new}{resource}{$resource}{up},
}});
}
}
closedir(DIRECTORY);
}
#print "Sync progress:\n";
#print " ".sprintf("%-${longest_resource}s", "Res")." ".sprintf("%-${longest_connection}s", "To")." Vol\n";
foreach my $resource (sort {$a cmp $b} keys %{$anvil->data->{new}{resource}})
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"new::resource::${resource}::up" => $anvil->data->{new}{resource}{$resource}{up},
}});
# If the resource isn't up, there's won't be a proc file to read.
next if not $anvil->data->{new}{resource}{$resource}{up};
foreach my $volume (sort {$a cmp $b} keys %{$anvil->data->{new}{resource}{$resource}{volume}})
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { volume => $volume }});
foreach my $peer (sort {$a cmp $b} keys %{$anvil->data->{new}{resource}{$resource}{volume}{$volume}{peer}})
{
my $proc_file = $anvil->data->{'scan-drbd'}{resource_status}."/".$resource."/connections/".$peer."/".$volume."/proc_drbd";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { proc_file => $proc_file }});
my $file_body = $anvil->Storage->read_file({file => $proc_file});
my $progress = "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { file_body => $file_body }});
foreach my $line (split/\n/, $file_body)
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { line => $line }});
if ($line =~ /cs:(.*?) /)
{
$anvil->data->{new}{resource}{$resource}{volume}{$volume}{peer}{$peer}{connection_state} = lc($1);
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"new::resource::${resource}::volume::${volume}::peer::${peer}::connection_state" => $anvil->data->{new}{resource}{$resource}{volume}{$volume}{peer}{$peer}{connection_state},
}});
}
if ($line =~ /ro:(.*?)\/(.*?) /)
{
$anvil->data->{new}{resource}{$resource}{volume}{$volume}{peer}{$peer}{local_role} = lc($1);
$anvil->data->{new}{resource}{$resource}{volume}{$volume}{peer}{$peer}{peer_role} = lc($2);
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"new::resource::${resource}::volume::${volume}::peer::${peer}::local_role" => $anvil->data->{new}{resource}{$resource}{volume}{$volume}{peer}{$peer}{local_role},
"new::resource::${resource}::volume::${volume}::peer::${peer}::peer_role" => $anvil->data->{new}{resource}{$resource}{volume}{$volume}{peer}{$peer}{peer_role},
}});
# If the peer is secondary, read the device size.
if ($anvil->data->{new}{resource}{$resource}{volume}{$volume}{peer}{$peer}{peer_role} eq "secondary")
{
# Get the size of the DRBD device.
my ($size, $return_code) = $anvil->System->call({secure => 1, shell_call => $anvil->data->{path}{exe}{blockdev}." --getsize64 /dev/drbd".$anvil->data->{new}{resource}{$resource}{volume}{$volume}{device_minor}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
size => $size,
return_code => $return_code,
}});
if (not $return_code)
{
$anvil->data->{new}{resource}{$resource}{volume}{$volume}{size} = $size;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"new::resource::${resource}::volume::${volume}::size" => $anvil->data->{new}{resource}{$resource}{volume}{$volume}{size}." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{new}{resource}{$resource}{volume}{$volume}{size}}).")",
}});
}
}
}
if ($line =~ /ds:(.*?)\/(.*?) /)
{
$anvil->data->{new}{resource}{$resource}{volume}{$volume}{peer}{$peer}{local_disk_state} = lc($1);
$anvil->data->{new}{resource}{$resource}{volume}{$volume}{peer}{$peer}{peer_disk_state} = lc($2);
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"new::resource::${resource}::volume::${volume}::peer::${peer}::local_disk_state" => $anvil->data->{new}{resource}{$resource}{volume}{$volume}{peer}{$peer}{local_disk_state},
"new::resource::${resource}::volume::${volume}::peer::${peer}::peer_disk_state" => $anvil->data->{new}{resource}{$resource}{volume}{$volume}{peer}{$peer}{peer_disk_state},
}});
}
if ($line =~ /oos:(\d+)/)
{
$anvil->data->{new}{resource}{$resource}{volume}{$volume}{peer}{$peer}{out_of_sync_size} = $1 * 1024;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"new::resource::${resource}::volume::${volume}::peer::${peer}::out_of_sync_size" => $anvil->data->{new}{resource}{$resource}{volume}{$volume}{peer}{$peer}{out_of_sync_size}." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{new}{resource}{$resource}{volume}{$volume}{peer}{$peer}{out_of_sync_size}}).")",
}});
}
=cut
0: cs:Established ro:Secondary/Secondary ds:Inconsistent/Inconsistent C r-----
ns:0 nr:0 dw:0 dr:0 al:0 bm:0 lo:0 pe:[0;0] ua:0 ap:[0;0] ep:1 wo:1 oos:0
resync: used:0/61 hits:0 misses:0 starving:0 locked:0 changed:0
act_log: used:0/1237 hits:0 misses:0 starving:0 locked:0 changed:0
blocked on activity log: 0/0/0
0: cs:SyncTarget ro:Secondary/Primary ds:Inconsistent/UpToDate C r-----
ns:0 nr:648960 dw:648728 dr:0 al:0 bm:0 lo:4 pe:[0;1] ua:4 ap:[0;0] ep:1 wo:1 oos:20321476
[>....................] sync'ed: 3.2% (19844/20476)M
finish: 0:03:39 speed: 92,672 (92,936 -- 92,672) want: 2,880 K/sec
3% sector pos: 1298032/41940408
resync: used:1/61 hits:31926 misses:10 starving:0 locked:0 changed:5
act_log: used:0/1237 hits:0 misses:0 starving:0 locked:0 changed:0
blocked on activity log: 0/0/0
=cut
if ($line =~ /sync'ed:\s+(\d.*\%)/)
{
$progress .= $1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { progress => $progress }});
}
if ($line =~ /speed: (.*?) \(/)
{
$anvil->data->{new}{resource}{$resource}{volume}{$volume}{peer}{$peer}{replication_speed} = $1;
$anvil->data->{new}{resource}{$resource}{volume}{$volume}{peer}{$peer}{replication_speed} =~ s/,//g;
$anvil->data->{new}{resource}{$resource}{volume}{$volume}{peer}{$peer}{replication_speed} *= 1024;
$anvil->data->{new}{scan_drbd}{scan_drbd_total_sync_speed} += $anvil->data->{new}{resource}{$resource}{volume}{$volume}{peer}{$peer}{replication_speed};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"s1:new::resource::${resource}::volume::${volume}::peer::${peer}::replication_speed" => $anvil->data->{new}{resource}{$resource}{volume}{$volume}{peer}{$peer}{replication_speed}." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{new}{resource}{$resource}{volume}{$volume}{peer}{$peer}{replication_speed}}).")",
"s2:new::scan_drbd::scan_drbd_total_sync_speed" => $anvil->data->{new}{scan_drbd}{scan_drbd_total_sync_speed}." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{new}{scan_drbd}{scan_drbd_total_sync_speed}}).")",
}});
}
if ($line =~ /finish: (\d+):(\d+):(\d+) /)
{
my $hours = $1;
my $minutes = $2;
my $seconds = $3;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
's1:hours' => $hours,
's2:minutes' => $minutes,
's3:seconds' => $seconds,
}});
$anvil->data->{new}{resource}{$resource}{volume}{$volume}{peer}{$peer}{estimated_time_to_sync} = (($hours * 3600) + ($minutes * 60) + $seconds);
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"new::resource::${resource}::volume::${volume}::peer::${peer}::estimated_time_to_sync" => $anvil->data->{new}{resource}{$resource}{volume}{$volume}{peer}{$peer}{estimated_time_to_sync}." (".$anvil->Convert->time({'time' => $anvil->data->{new}{resource}{$resource}{volume}{$volume}{peer}{$peer}{estimated_time_to_sync}, long => 1, translate => 1}).")",
}});
}
}
}
}
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"s2:new::scan_drbd::scan_drbd_total_sync_speed" => $anvil->data->{new}{scan_drbd}{scan_drbd_total_sync_speed}." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{new}{scan_drbd}{scan_drbd_total_sync_speed}}).")",
}});
return(1);
}
# This reads in the last scan's data. # This reads in the last scan's data.
sub read_last_scan sub read_last_scan
{ {

@ -271,6 +271,64 @@ The error was:
<key name="error_0196">The install disc ISO: [#!variable!install_iso!#] to be used for the new server: [#!variable!server_name!#] wasn't found on this system.</key> <key name="error_0196">The install disc ISO: [#!variable!install_iso!#] to be used for the new server: [#!variable!server_name!#] wasn't found on this system.</key>
<key name="error_0197">The driver disc ISO: [#!variable!install_iso!#] to be used for the new server: [#!variable!server_name!#] wasn't found on this system.</key> <key name="error_0197">The driver disc ISO: [#!variable!install_iso!#] to be used for the new server: [#!variable!server_name!#] wasn't found on this system.</key>
<key name="error_0198">The new server's name: [#!variable!server_name!#] is already in use. Has this job already run?</key> <key name="error_0198">The new server's name: [#!variable!server_name!#] is already in use. Has this job already run?</key>
<key name="error_0199">The storage group UUID: [#!variable!storage_group_uuid!#] wasn't found in the database.</key>
<key name="error_0200">The new DRBD resource will need a "minor" number and a TCP port. One or both are not provided or are invalid.</key>
<key name="error_0201">Failed to create the logical volume: [#!variable!lv_path!#]. Without this, we can't create the replicated storage backing the server, aborting.
Command: ... [#!variable!lv_create!#]
Return Code: [#!variable!return_code!#]
Output (if any):
====
#!variable!output!#
====
</key>
<key name="error_0202">Failed to write the DRBD resource file: [#!variable!drbd_res_file!#]. The cause of the failure should be in the logs.</key>
<key name="error_0203">Failed to load the DRBD resource file: [#!variable!drbd_res_file!#]. Tried dumping the new DRBD config and the file new resource wasn't found.</key>
<key name="error_0204">It appears that creating the DRBD meta data on the new logic volume(s) failed. Expected the return code '0' but got: [#!variable!return_code!#]. The command returned: [#!variable!output!#].</key>
<key name="error_0205">It appears that the initial forced primary role to initialize the new DRBD resource failed. Expected the return code '0' but got: [#!variable!return_code!#]. The command returned: [#!variable!output!#].</key>
<key name="error_0206">The logical volume behind the resource: [#!variable!resource!#] existed, and started the resource has the disk state 'diskless'. This is likely because the LV doesn't have DRBD meta-data. We can't (safely) create it. Please either remove the LV backing this resource or create the meta data manually.</key>
<!-- Files templates -->
<!-- NOTE: Translating these files requires an understanding of which likes are translatable -->
<!-- comments and which are command lines that can't be changed! -->
<key name="file_0001"><![CDATA[# Resource for #!variable!server!#
resource #!variable!server!# {
on #!variable!node1_short_name!# {
node-id 0;
volume 0 {
device /dev/drbd_#!variable!server!#_0 minor #!variable!minor!#;
disk #!variable!node1_lv_path!#;
meta-disk internal;
}
}
on #!variable!node2_short_name!# {
node-id 1;
volume 0 {
device /dev/drbd_#!variable!server!#_0 minor #!variable!minor!#;
disk #!variable!node2_lv_path!#;
meta-disk internal;
}
}
### NOTE: Remember to open the appropriate firewall port!
# firewall-cmd --zone=#!variable!sn_network!# --permanent --add-port=#!variable!tcp_port!#/tcp --permanent
# firewall-cmd --zone=#!variable!sn_network!# --permanent --add-port=#!variable!tcp_port!#/tcp
connection {
host #!variable!node1_short_name!# address #!variable!node1_sn_ip!#:#!variable!tcp_port!#;
host #!variable!node2_short_name!# address #!variable!node2_sn_ip!#:#!variable!tcp_port!#;
disk {
# Without this, the variable bit rate caps at 100 MiB/sec, and most deployments are
# 10 Gbps. So this lets the variable rate climb to 500 MiB/sec
c-max-rate 500M;
}
net {
protocol C;
fencing resource-and-stonith;
}
}
}
]]></key>
<!-- Table headers --> <!-- Table headers -->
<key name="header_0001">Current Network Interfaces and States</key> <key name="header_0001">Current Network Interfaces and States</key>
@ -527,6 +585,11 @@ Job Data:
====</key> ====</key>
<key name="job_0184">The job to create the new server has been registered as job: [#!variable!job_uuid!#]. <key name="job_0184">The job to create the new server has been registered as job: [#!variable!job_uuid!#].
It should be provisioned in the next minute or two.</key> It should be provisioned in the next minute or two.</key>
<key name="job_0185">Sanity checks complete.</key>
<key name="job_0186">The new DRBD resource will use minor number: [#!variable!minor!#] and the base TCP port: [#!variable!port!#].</key>
<key name="job_0187">[ Warning ] - The logical volume: [#!variable!lv_path!#] to use for this server already exists. We will NOT initialize it! If the LV does not have DRBD metadata, the server install will fail. If the LV is a DRBD resource, and it is inconsistent or outdated, provisioning will stall until the peer comes online. If the install fails, please determine why (or remove the existing LV) and try again.</key>
<key name="job_0188">The peer job: [#!variable!job_uuid!#] has been created for the peer: [#!variable!peer_name!#] to create it's side of the storage.</key>
<key name="job_0189">The new logical volume: [#!variable!lv_path!#] has been created. This will back the replicated storage used for the new server.</key>
<!-- Log entries --> <!-- Log entries -->
<key name="log_0001">Starting: [#!variable!program!#].</key> <key name="log_0001">Starting: [#!variable!program!#].</key>
@ -1198,6 +1261,9 @@ The file: [#!variable!file!#] needs to be updated. The difference is:
<key name="log_0575">The host: [#!variable!host_name!#] was powered off for thermal reasons. All available thermal sensors read as OK now. Booting it back up now.</key> <key name="log_0575">The host: [#!variable!host_name!#] was powered off for thermal reasons. All available thermal sensors read as OK now. Booting it back up now.</key>
<key name="log_0576">The file: [#!variable!file_path!#] isn't on (or isn't the right size on) Striker: [#!variable!host_name!#]. Not using it to pull from.</key> <key name="log_0576">The file: [#!variable!file_path!#] isn't on (or isn't the right size on) Striker: [#!variable!host_name!#]. Not using it to pull from.</key>
<key name="log_0577">The job: [#!variable!job_uuid!#] was assigned to our Anvil! and this is the primary node. Assigning the job to this machine.</key> <key name="log_0577">The job: [#!variable!job_uuid!#] was assigned to our Anvil! and this is the primary node. Assigning the job to this machine.</key>
<key name="log_0578">The LV(s) behind the resource: [#!variable!resource!#] already existed, and the DRBD resource is not in the disk state 'UpToDate'. As such, we'll keep waiting before provisioning the server.</key>
<key name="log_0579">The LV(s) behind the resource: [#!variable!resource!#] have had their DRBD metadata created successfully.</key>
<key name="log_0580">The LV(s) behind the resource: [#!variable!resource!#] have been forced to primary to initialize the resource.</key>
<!-- Messages for users (less technical than log entries), though sometimes used for logs, too. --> <!-- Messages for users (less technical than log entries), though sometimes used for logs, too. -->
<key name="message_0001">The host name: [#!variable!target!#] does not resolve to an IP address.</key> <key name="message_0001">The host name: [#!variable!target!#] does not resolve to an IP address.</key>

@ -63,7 +63,7 @@ if (not $anvil->data->{sys}{database}{connections})
if (not $anvil->data->{switches}{'job-uuid'}) if (not $anvil->data->{switches}{'job-uuid'})
{ {
# Load the job data. # Load the job data.
$anvil->data->{switches}{job_uuid} = $anvil->Job->get_job_uuid({program => $THIS_FILE}); $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->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "switches::job-uuid" => $anvil->data->{switches}{'job-uuid'} }});
} }
@ -119,12 +119,15 @@ sub run_jobs
my $storage_size = ""; my $storage_size = "";
my $install_iso_uuid = ""; my $install_iso_uuid = "";
my $driver_iso_uuid = ""; my $driver_iso_uuid = "";
my $drbd_minor = "";
my $drbd_tcp_port = "";
my $peer_mode = 0;
foreach my $line (split/\n/, $anvil->data->{jobs}{job_data}) foreach my $line (split/\n/, $anvil->data->{jobs}{job_data})
{ {
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }});
if ($line =~ /server_name=(.*)$/) if ($line =~ /server_name=(.*)$/)
{ {
$anvil_uuid = $1; $server_name = $1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { server_name => $server_name }}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { server_name => $server_name }});
} }
if ($line =~ /cpu_cores=(.*)$/) if ($line =~ /cpu_cores=(.*)$/)
@ -157,8 +160,25 @@ sub run_jobs
$driver_iso_uuid = $1; $driver_iso_uuid = $1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { driver_iso_uuid => $driver_iso_uuid }}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { driver_iso_uuid => $driver_iso_uuid }});
} }
if ($line =~ /peer_mode=true$/)
{
# We'll ONLY setup our DRBD resource, nothing else.
$peer_mode = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { peer_mode => $peer_mode }});
}
if ($line =~ /drbd_minor=(.*)$/)
{
$drbd_minor = $1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { drbd_minor => $drbd_minor }});
}
if ($line =~ /drbd_tcp_port=(.*)$/)
{
$drbd_tcp_port = $1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { drbd_tcp_port => $drbd_tcp_port }});
}
} }
# We need a server name and storage group UUID regardless of which mode we're in.
if (not $server_name) if (not $server_name)
{ {
$anvil->Job->update_progress({ $anvil->Job->update_progress({
@ -169,10 +189,44 @@ sub run_jobs
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => 'err', key => "error_0187", variables => { job_uuid => $anvil->data->{switches}{'job-uuid'} }}); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => 'err', key => "error_0187", variables => { job_uuid => $anvil->data->{switches}{'job-uuid'} }});
$anvil->nice_exit({exit_code => 1}); $anvil->nice_exit({exit_code => 1});
} }
if (not $storage_group_uuid)
{
$anvil->Job->update_progress({
progress => 100,
message => "error_0192,!!server_name!".$server_name."!!,!!job_uuid!".$anvil->data->{switches}{'job-uuid'}."!!",
job_status => "failed",
});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => 'err', key => "error_0192", variables => {
server_name => $server_name,
job_uuid => $anvil->data->{switches}{'job-uuid'},
}});
$anvil->nice_exit({exit_code => 1});
}
if (not $storage_size)
{
$anvil->Job->update_progress({
progress => 100,
message => "error_0193,!!server_name!".$server_name."!!,!!job_uuid!".$anvil->data->{switches}{'job-uuid'}."!!",
job_status => "failed",
});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => 'err', key => "error_0193", variables => {
server_name => $server_name,
job_uuid => $anvil->data->{switches}{'job-uuid'},
}});
$anvil->nice_exit({exit_code => 1});
}
# If we're the peer, there's only a few things we need to check.
if ($peer_mode)
{
# The server should already exist on the peer. All we need to do is create our LV, create the
# DRBD resource, bring the resource up, and save the XML definition file.
}
else
{
# Is the server name unique? # Is the server name unique?
$anvil->Database->get_servers(); $anvil->Database->get_servers();
if (exists $anvil->data->{servers}{anvil_uuid}{$server_anvil_uuid}{server_name}{$server_name}) if (exists $anvil->data->{servers}{anvil_uuid}{$anvil_uuid}{server_name}{$server_name})
{ {
# Duplicate name # Duplicate name
$anvil->Job->update_progress({ $anvil->Job->update_progress({
@ -242,32 +296,205 @@ sub run_jobs
}}); }});
$anvil->nice_exit({exit_code => 1}); $anvil->nice_exit({exit_code => 1});
} }
if (not $storage_group_uuid)
if (not $install_iso_uuid)
{ {
$anvil->Job->update_progress({ $anvil->Job->update_progress({
progress => 100, progress => 100,
message => "error_0192,!!server_name!".$server_name."!!,!!job_uuid!".$anvil->data->{switches}{'job-uuid'}."!!", message => "error_0195,!!server_name!".$server_name."!!,!!job_uuid!".$anvil->data->{switches}{'job-uuid'}."!!",
job_status => "failed", job_status => "failed",
}); });
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => 'err', key => "error_0192", variables => { $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => 'err', key => "error_0195", variables => {
server_name => $server_name, server_name => $server_name,
job_uuid => $anvil->data->{switches}{'job-uuid'}, job_uuid => $anvil->data->{switches}{'job-uuid'},
}}); }});
$anvil->nice_exit({exit_code => 1}); $anvil->nice_exit({exit_code => 1});
} }
if (not $storage_size) my $install_iso = $anvil->data->{files}{file_uuid}{$install_iso_uuid}{file_directory}."/".$anvil->data->{files}{file_uuid}{$install_iso_uuid}{file_name};
if (not -e $install_iso)
{ {
$anvil->Job->update_progress({ $anvil->Job->update_progress({
progress => 100, progress => 100,
message => "error_0193,!!server_name!".$server_name."!!,!!job_uuid!".$anvil->data->{switches}{'job-uuid'}."!!", message => "error_0196,!!server_name!".$server_name."!!,!!install_iso!".$install_iso."!!",
job_status => "failed", job_status => "failed",
}); });
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => 'err', key => "error_0193", variables => { $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => 'err', key => "error_0196", variables => {
server_name => $server_name, server_name => $server_name,
job_uuid => $anvil->data->{switches}{'job-uuid'}, install_iso => $install_iso,
}});
$anvil->nice_exit({exit_code => 1});
}
# Driver disc is optional.
if ($driver_iso_uuid)
{
my $driver_iso = $anvil->data->{files}{file_uuid}{$driver_iso_uuid}{file_directory}."/".$anvil->data->{files}{file_uuid}{$driver_iso_uuid}{file_name};
if (not -e $driver_iso)
{
$anvil->Job->update_progress({
progress => 100,
message => "error_0197,!!server_name!".$server_name."!!,!!driver_iso!".$driver_iso."!!",
job_status => "failed",
});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => 'err', key => "error_0197", variables => {
server_name => $server_name,
driver_iso => $driver_iso,
}});
$anvil->nice_exit({exit_code => 1});
}
}
}
# Read in VG information;
my $problem = $anvil->Storage->get_storage_group_details({
debug => 2,
storage_group_uuid => $storage_group_uuid,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { problem => $problem }});
if ($problem)
{
# Failed to collect storage group data.
$anvil->Job->update_progress({
progress => 100,
message => "error_0199,!!storage_group_uuid!".$storage_group_uuid."!!",
job_status => "failed",
});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => 'err', key => "error_0197", variables => { storage_group_uuid => $storage_group_uuid }});
$anvil->nice_exit({exit_code => 1});
}
if ((($drbd_minor eq "") or ($drbd_tcp_port eq "")) && (not $peer_mode))
{
my ($free_minor, $free_port) = $anvil->DRBD->get_next_resource({anvil_uuid => $anvil_uuid});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
free_minor => $free_minor,
free_port => $free_port,
}}); }});
if ($drbd_minor eq "")
{
$drbd_minor = $free_minor;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { drbd_minor => $drbd_minor }});
}
if ($drbd_tcp_port eq "")
{
$drbd_tcp_port = $free_port;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { drbd_tcp_port => $drbd_tcp_port }});
}
}
# If we don't have a DRBD minor or TCP port, we're stuck.
if (($drbd_minor eq "") or ($drbd_tcp_port eq ""))
{
$anvil->Job->update_progress({
progress => 100,
message => "error_0200",
job_status => "failed",
});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => 'err', key => "error_0200"});
$anvil->nice_exit({exit_code => 1}); $anvil->nice_exit({exit_code => 1});
} }
# Sanity checks passed
$anvil->Job->update_progress({
progress => 10,
message => "job_0185",
});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "job_0185"});
# Who is our peer?
$anvil->Database->get_anvils();
my $host_uuid = $anvil->Get->host_uuid();
my $node1_host_uuid = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_node1_host_uuid};
my $node2_host_uuid = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_node2_host_uuid};
my $peer_host_uuid = $host_uuid eq $node1_host_uuid ? $node2_host_uuid : $node1_host_uuid;
my $peer_name = $anvil->Get->host_name_from_uuid({host_uuid => $peer_host_uuid});
my $short_host_name = $anvil->Get->short_host_name;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
host_uuid => $host_uuid,
node1_host_uuid => $node1_host_uuid,
node2_host_uuid => $node2_host_uuid,
peer_host_uuid => $peer_host_uuid,
peer_name => $peer_name,
short_host_name => $short_host_name,
}});
# If we're not the peer, create the peer's job.
if (not $peer_mode)
{
my $job_data = $anvil->data->{jobs}{job_data}."\n";
$job_data .= "peer_mode=true\n";
$job_data .= "drbd_minor=".$drbd_minor."\n";
$job_data .= "drbd_tcp_port=".$drbd_tcp_port."\n";
my ($job_uuid) = $anvil->Database->insert_or_update_jobs({
debug => 2,
job_command => $anvil->data->{path}{exe}{'anvil-provision-server'},
job_data => $job_data,
job_name => "server::provision",
job_title => "job_0147",
job_description => "job_0148",
job_progress => 0,
job_host_uuid => $peer_host_uuid,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { job_uuid => $job_uuid }});
$anvil->Job->update_progress({
progress => 20,
message => "job_0188,!!job_uuid!".$job_uuid."!!,!!peer_name!".$peer_name."!!",
});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "job_0188", variables => {
job_uuid => $job_uuid,
peer_name => $peer_name,
}});
}
# Report the DRBD minor and TCP port that we'll use.
$anvil->Job->update_progress({
progress => 30,
message => "job_0186,!!minor!".$drbd_minor."!!,!!port!".$drbd_tcp_port."!!",
});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "job_0186", variables => {
minor => $drbd_minor,
port => $drbd_tcp_port,
}});
# We convert to extents as it ensure clean boundaries and, being based on bytes in both cases, gets
# us as close as we can to what the user asked for. The 'int()' always rounds down, so we don't ever
# ask for one more extent than is available by accident.
my $vg_name = $anvil->data->{storage_groups}{storage_group_uuid}{$storage_group_uuid}{host_uuid}{$host_uuid}{vg_name};
my $extent_size = $anvil->data->{storage_groups}{storage_group_uuid}{$storage_group_uuid}{host_uuid}{$host_uuid}{vg_extent_size};
my $extent_count = int($storage_size / $extent_size);
my $lv_path = "/dev/".$vg_name."/".$server_name."_0";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
vg_name => $vg_name,
extent_size => $extent_size,
extent_count => $extent_count,
lv_path => $lv_path,
}});
# We need the peer's LVM path for the DRBD config.
my $peer_vg_name = $anvil->data->{storage_groups}{storage_group_uuid}{$storage_group_uuid}{host_uuid}{$peer_host_uuid}{vg_name};
my $peer_lv_path = "/dev/".$peer_vg_name."/".$server_name."_0";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { peer_lv_path => $peer_lv_path }});
# If the LV exists, we won't initialize the DRBD resource. If the LV exists but isn't a DRBD backing
# device, this will cause the resource to not come up, but it's better than risking data loss.
my $initialize_drbd = 1;
if (-e $lv_path)
{
# Don't create and don't initialize.
$initialize_drbd = 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { initialize_drbd => $initialize_drbd }});
# Tell the user this might be an issue.
$anvil->Job->update_progress({
progress => 40,
message => "job_0187,!!lv_path!".$lv_path."!!",
});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "job_0187", variables => { lv_path => $lv_path }});
}
else
{
# Make sure we have enough space.
if ($storage_size > $anvil->data->{anvil_resources}{$anvil_uuid}{storage_group}{$storage_group_uuid}{free_size}) if ($storage_size > $anvil->data->{anvil_resources}{$anvil_uuid}{storage_group}{$storage_group_uuid}{free_size})
{ {
my $say_available_size = $anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{anvil_resources}{$anvil_uuid}{storage_group}{$storage_group_uuid}{free_size}})." (".$anvil->Convert->add_commas({number => $anvil->data->{anvil_resources}{$anvil_uuid}{storage_group}{$storage_group_uuid}{free_size}}).")"; my $say_available_size = $anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{anvil_resources}{$anvil_uuid}{storage_group}{$storage_group_uuid}{free_size}})." (".$anvil->Convert->add_commas({number => $anvil->data->{anvil_resources}{$anvil_uuid}{storage_group}{$storage_group_uuid}{free_size}}).")";
@ -286,54 +513,330 @@ sub run_jobs
}}); }});
$anvil->nice_exit({exit_code => 1}); $anvil->nice_exit({exit_code => 1});
} }
if (not $install_iso_uuid)
# Create the LV.
my $shell_call = $anvil->data->{path}{exe}{lvcreate}." -l ".$extent_count." -n ".$server_name."_0 ".$vg_name;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
my ($output, $return_code) = $anvil->System->call({shell_call => $shell_call});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
output => $output,
return_code => $return_code,
}});
if (not -e $lv_path)
{ {
# Something went wrong.
$anvil->Job->update_progress({ $anvil->Job->update_progress({
progress => 100, progress => 100,
message => "error_0195,!!server_name!".$server_name."!!,!!job_uuid!".$anvil->data->{switches}{'job-uuid'}."!!", message => "error_0201,!!lv_path!".$lv_path."!!,!!lv_create!".$shell_call."!!,!!return_code!".$return_code."!!,!!output!".$output."!!",
job_status => "failed", job_status => "failed",
}); });
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => 'err', key => "error_0195", variables => { $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => 'err', key => "error_0201", variables => {
server_name => $server_name, lv_path => $lv_path,
job_uuid => $anvil->data->{switches}{'job-uuid'}, lv_create => $shell_call,
return_code => $return_code,
output => $output,
}}); }});
$anvil->nice_exit({exit_code => 1}); $anvil->nice_exit({exit_code => 1});
} }
my $install_iso = $anvil->data->{files}{file_uuid}{$install_iso_uuid}{file_directory}."/".$anvil->data->{files}{file_uuid}{$install_iso_uuid}{file_name};
if (not -e $install_iso) # Report
$anvil->Job->update_progress({
progress => 35,
message => "job_0189,!!lv_path!".$lv_path."!!",
});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "job_0189", variables => { lv_path => $lv_path }});
}
# Create the resource config file now.
$anvil->Database->get_hosts();
my $node1_short_host_name = $anvil->data->{hosts}{host_uuid}{$node1_host_uuid}{short_host_name};
my $node2_short_host_name = $anvil->data->{hosts}{host_uuid}{$node2_host_uuid}{short_host_name};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
node1_short_host_name => $node1_short_host_name,
node2_short_host_name => $node2_short_host_name,
}});
# Load the IPs so we can find which SN network and IPs to use
my $node1_sn_ip = "";
my $node2_sn_ip = "";
my $sn_network = "";
$anvil->Network->load_ips({host => $node1_short_host_name, host_uuid => $node1_host_uuid});
$anvil->Network->load_ips({host => $node2_short_host_name, host_uuid => $node2_host_uuid});
my $match = $anvil->Network->find_matches({
first => $node1_short_host_name,
second => $node2_short_host_name,
});
my $matched_ips = keys %{$match};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { matched_ips => $matched_ips }});
foreach my $interface (sort {$a cmp $b} keys %{$match->{$node1_short_host_name}})
{
if ($interface =~ /sn/)
{
### TODO: This always chooses SN1 at this time, we need to support (later) VM
### build-time SN selection when 2+ SNs exist.
# Found an SN.
$sn_network = uc(($interface =~ /^(sn\d+)_/)[0]);
$node1_sn_ip = $match->{$node1_short_host_name}{$interface}{ip};
$node2_sn_ip = $match->{$node2_short_host_name}{$interface}{ip};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
sn_network => $sn_network,
node1_sn_ip => $node1_sn_ip,
node2_sn_ip => $node2_sn_ip,
}});
}
}
# Node 1 and Node 2 are set independent of which node we have.
my $node1_lv_path = "";
my $node2_lv_path = "";
if ($host_uuid eq $node1_host_uuid)
{ {
# We're node 1
$node1_lv_path = $lv_path;
$node2_lv_path = $peer_lv_path;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
node1_lv_path => $node1_lv_path,
node2_lv_path => $node2_lv_path,
}});
}
else
{
# We're node 2
$node1_lv_path = $peer_lv_path;
$node2_lv_path = $lv_path;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
node1_lv_path => $node1_lv_path,
node2_lv_path => $node2_lv_path,
}});
}
my $drbd_res_body = $anvil->Words->string({key => "file_0001", variables => {
server => $server_name,
minor => $drbd_minor,
tcp_port => $drbd_tcp_port,
sn_network => $sn_network,
node1_sn_ip => $node1_sn_ip,
node2_sn_ip => $node2_sn_ip,
node1_short_name => $node1_short_host_name,
node2_short_name => $node2_short_host_name,
node1_lv_path => $node1_lv_path,
node2_lv_path => $node2_lv_path,
}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { drbd_res_body => $drbd_res_body }});
# Write the file, then call drbdadm to validate it.
my $drbd_res_file = $anvil->data->{path}{directories}{drbd_resources}."/".$server_name.".res";
$drbd_res_file =~ s/\/\//\//g;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { drbd_res_file => $drbd_res_file }});
$problem = $anvil->Storage->write_file({
overwrite => 1,
backup => 1,
file => $drbd_res_file,
body => $drbd_res_body,
mode => "0644",
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { problem => $problem }});
if (not -e $drbd_res_file)
{
# Failed to write the config file.
$anvil->Job->update_progress({ $anvil->Job->update_progress({
progress => 100, progress => 100,
message => "error_0196,!!server_name!".$server_name."!!,!!install_iso!".$install_iso."!!", message => "error_0202,!!drbd_res_file!".$drbd_res_file."!!",
job_status => "failed", job_status => "failed",
}); });
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => 'err', key => "error_0196", variables => { $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => 'err', key => "error_0202", variables => { drbd_res_file => $drbd_res_file }});
server_name => $server_name, $anvil->nice_exit({exit_code => 1});
install_iso => $install_iso, }
# Call drbdadm and verify it's good.
$problem = $anvil->DRBD->gather_data({debug => 2});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { problem => $problem }});
if ((not exists $anvil->data->{new}{resource}{$server_name}) or ($anvil->data->{new}{resource}{$server_name}{config_file} ne $drbd_res_file))
{
# Failed to load the resource.
$anvil->Job->update_progress({
progress => 100,
message => "error_0203,!!drbd_res_file!".$drbd_res_file."!!",
job_status => "failed",
});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => 'err', key => "error_0203", variables => { drbd_res_file => $drbd_res_file }});
$anvil->nice_exit({exit_code => 1});
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { initialize_drbd => $initialize_drbd }});
if ($initialize_drbd)
{
# Create the DRBD metadata
my $shell_call = $anvil->data->{path}{exe}{drbdadm}." -- --force create-md ".$server_name;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
my ($output, $return_code) = $anvil->System->call({shell_call => $shell_call});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
output => $output,
return_code => $return_code,
}});
### Return codes
# 0 == Success
# 3 == Configuration not found.
if ($return_code eq "3")
{
# Metadata creation failed.
$anvil->Job->update_progress({
progress => 100,
message => "error_0204,!!return_code!".$return_code."!!,!!output!".$output."!!",
job_status => "failed",
});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => 'err', key => "error_0204", variables => {
return_code => $return_code,
output => $output,
}}); }});
$anvil->nice_exit({exit_code => 1}); $anvil->nice_exit({exit_code => 1});
} }
# Driver disc is optional. $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0579", variables => { resource => $server_name }});
if ($driver_iso_uuid) }
# Check to see if the resource needs to be started. It almost always will.
$anvil->DRBD->get_status();
my $startup_needed = 1;
# Is the current resource up locally already? If it is, we're done.
my $role = defined $anvil->data->{drbd}{status}{$short_host_name}{resource}{$server_name}{role} ? $anvil->data->{drbd}{status}{$short_host_name}{resource}{$server_name}{role} : "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
server => $server_name,
role => $role,
}});
if ((lc($role) ne "secondary") && (lc($role) ne "primary"))
{ {
my $driver_iso = $anvil->data->{files}{file_uuid}{$driver_iso_uuid}{file_directory}."/".$anvil->data->{files}{file_uuid}{$driver_iso_uuid}{file_name}; $startup_needed = 1;
if (not -e $driver_iso) $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { startup_needed => $startup_needed }});
}
else
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0434", variables => {
resource => $server_name,
role => $role,
}});
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { startup_needed => $startup_needed }});
if (not $startup_needed)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0431"});
}
else
{
# Bring the drbd resource up.
$anvil->DRBD->manage_resource({
debug => 2,
resource => $server_name,
task => "up",
});
my $waiting = 1;
while($waiting)
{
# Reload the DRBD data
$anvil->DRBD->get_status();
my $all_ready = 1;
foreach my $volume (sort {$a cmp $b} keys %{$anvil->data->{drbd}{status}{$short_host_name}{resource}{$server_name}{devices}{volume}})
{
my $disk_state = $anvil->data->{drbd}{status}{$short_host_name}{resource}{$server_name}{devices}{volume}{$volume}{'disk-state'};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
's1:short_host_name' => $short_host_name,
's2:server_name' => $server_name,
's3:volume' => $volume,
's4:disk_state' => $disk_state,
}});
# Is the peer isn't connected (directly or by being in Sync), or this volume
# isn't UpToDate, we need to keep waiting.
if ((lc($disk_state) ne "uptodate") &&
(lc($disk_state) ne "consistent") &&
(lc($disk_state) ne "outdated") &&
(lc($disk_state) ne "inconsistent"))
{ {
$all_ready = 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { all_ready => $all_ready }});
}
# If we're not initializing DRBD, we'll wait until we're uptodate.
if (not $initialize_drbd)
{
if (lc($disk_state) eq "diskless")
{
# This happens when the LV existed but there's no meta-data.
$anvil->Job->update_progress({ $anvil->Job->update_progress({
progress => 100, progress => 100,
message => "error_0197,!!server_name!".$server_name."!!,!!driver_iso!".$driver_iso."!!", message => "error_0206,!!resource!".$server_name."!!",
job_status => "failed", job_status => "failed",
}); });
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => 'err', key => "error_0197", variables => { $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => 'err', key => "error_0206", variables => { resource => $server_name }});
server_name => $server_name, $anvil->nice_exit({exit_code => 1});
driver_iso => $driver_iso, }
if (lc($disk_state) ne "uptodate")
{
# Log why we're waiting.
$all_ready = 0;
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0578", variables => { resource => $server_name }});
}
}
# If we're initializing and the resource is 'Inconsistent', force the resource to primary
if (($initialize_drbd) && (lc($disk_state) eq "inconsistent"))
{
# Create the DRBD metadata
my $shell_call = $anvil->data->{path}{exe}{drbdadm}." primary ".$server_name." --force";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
my ($output, $return_code) = $anvil->System->call({shell_call => $shell_call});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
output => $output,
return_code => $return_code,
}});
# Return code of '0' is success.
if ($return_code)
{
# Failed to promote
$anvil->Job->update_progress({
progress => 100,
message => "error_0205,!!return_code!".$return_code."!!,!!output!".$output."!!",
job_status => "failed",
});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => 'err', key => "error_0205", variables => {
return_code => $return_code,
output => $output,
}}); }});
$anvil->nice_exit({exit_code => 1}); $anvil->nice_exit({exit_code => 1});
} }
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0580", variables => { resource => $server_name }});
### TODO: Should we demote it again? For now, no.
}
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { all_ready => $all_ready }});
if ($all_ready)
{
$waiting = 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { waiting => $waiting }});
}
if ($waiting)
{
sleep 1;
}
}
} }
# Still alive? Ready to go! # If we're here, we can finally craft the 'virt-install' call!.
my $drbd_minor = $anvil->DRBD->get_next_resource({})
return(0); return(0);
} }

@ -27,7 +27,7 @@ $anvil->Database->connect({debug => 3});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0132"}); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0132"});
my $anvil_uuid = "a5ae5242-e9d3-46c9-9ce8-306855aa56db"; my $anvil_uuid = "a5ae5242-e9d3-46c9-9ce8-306855aa56db";
my ($free_minor, $free_port) = $anvil->DRBD->get_next_resource({anvil_uuid => "a5ae5242-e9d3-46c9-9ce8-306855aa56db"}) my ($free_minor, $free_port) = $anvil->DRBD->get_next_resource({anvil_uuid => "a5ae5242-e9d3-46c9-9ce8-306855aa56db"});
print "Next free minor: [".$free_minor."], port: [".$free_port."]\n"; print "Next free minor: [".$free_minor."], port: [".$free_port."]\n";
$anvil->nice_exit({exit_code => 0}); $anvil->nice_exit({exit_code => 0});

Loading…
Cancel
Save