* Created the new tools/anvil-provision-server tool which will handle provisioning new servers, as well as having an interactive menu system to provision servers from the command line.

* Created Cluster->assemble_storage_groups() and moved the logic to auto-assemble groups out of Get->available_resources().
* Created Cluster->get_anvil_name() that will return an Anvil! name for a given anvil_uuid, or the name of the Anvil! if the host is a member of an Anvil!.
* Updated Cluster->get_anvil_uuid() to return the 'anvil_uuid' if passed a specific 'anvil_name'.
* Updated Jobs->clear() to use 'switches::job-uuid' when a job_uuid is not passed but the value exists in 'switches::job-uuid'.

Signed-off-by: Digimer <digimer@alteeve.ca>
main
Digimer 4 years ago
parent ddffc9d782
commit f30cce3c5a
  1. 333
      Anvil/Tools/Cluster.pm
  2. 6
      Anvil/Tools/Database.pm
  3. 210
      Anvil/Tools/Get.pm
  4. 6
      Anvil/Tools/Job.pm
  5. 1
      Anvil/Tools/Storage.pm
  6. 1
      share/words.xml
  7. 354
      tools/anvil-provision-server

@ -14,8 +14,10 @@ our $VERSION = "3.0.0";
my $THIS_FILE = "Cluster.pm"; my $THIS_FILE = "Cluster.pm";
### Methods; ### Methods;
# assemble_storage_groups
# boot_server # boot_server
# check_node_status # check_node_status
# get_anvil_name
# get_anvil_uuid # get_anvil_uuid
# get_peers # get_peers
# migrate_server # migrate_server
@ -83,6 +85,268 @@ sub parent
# Public methods # # Public methods #
############################################################################################################# #############################################################################################################
=head2 assemble_storage_groups
This method takes an Anvil! UUID and sees if there are any ungrouped LVM VGs that can be automatically grouped together.
Parameters;
=head3 anvil_uuid (required)
This is the Anvil! UUID that we're looking for ungrouped VGs in.
=cut
sub assemble_storage_groups
{
my $self = shift;
my $parameter = shift;
my $anvil = $self->parent;
my $debug = defined $parameter->{debug} ? $parameter->{debug} : 2;
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "Cluster->assemble_storage_groups()" }});
my $anvil_uuid = defined $parameter->{anvil_uuid} ? $parameter->{anvil_uuid} : "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
anvil_uuid=> $anvil_uuid,
}});
if (not $anvil_uuid)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Cluster->assemble_storage_groups()", parameter => "anvil_uuid" }});
return("!!error!!");
}
# Get the node UUIDs for this anvil.
my $query = "
SELECT
anvil_name,
anvil_node1_host_uuid,
anvil_node2_host_uuid,
anvil_dr1_host_uuid
FROM
anvils
WHERE
anvil_uuid = ".$anvil->Database->quote($anvil_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)
{
# Not found.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "error_0169", variables => { anvil_uuid => $anvil_uuid }});
return("!!error!!");
}
# Get the details.
my $anvil_name = $results->[0]->[0];
my $node1_host_uuid = $results->[0]->[1];
my $node2_host_uuid = $results->[0]->[2];
my $dr1_host_uuid = defined $results->[0]->[3] ? $results->[0]->[3] : "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
anvil_name => $anvil_name,
node1_host_uuid => $node1_host_uuid,
node2_host_uuid => $node2_host_uuid,
dr1_host_uuid => $dr1_host_uuid,
}});
# Load known storage groups.
$anvil->Database->get_storage_group_data({debug => $debug});
# Look for ungrouped VGs and see if we can group them by matching identical sizes together.
foreach my $host_uuid ($node1_host_uuid, $node2_host_uuid, $dr1_host_uuid)
{
# If DR isn't defined, it'll be blank.
next if not $host_uuid;
my $this_is = "node1";
if ($host_uuid eq $node2_host_uuid) { $this_is = "node2"; }
elsif ($host_uuid eq $dr1_host_uuid) { $this_is = "dr1"; }
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { this_is => $this_is }});
$anvil->data->{ungrouped_vg_count}{$this_is} = 0;
my $query = "
SELECT
scan_lvm_vg_uuid,
scan_lvm_vg_name,
scan_lvm_vg_extent_size,
scan_lvm_vg_size,
scan_lvm_vg_free,
scan_lvm_vg_internal_uuid
FROM
scan_lvm_vgs
WHERE
scan_lvm_vg_host_uuid = ".$anvil->Database->quote($host_uuid)."
ORDER BY
scan_lvm_vg_size 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_lvm_vg_size = $row->[3];
my $scan_lvm_vg_internal_uuid = $row->[5];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
scan_lvm_vg_size => $scan_lvm_vg_size." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $scan_lvm_vg_size}).")",
scan_lvm_vg_internal_uuid => $scan_lvm_vg_internal_uuid,
}});
# Skip VGs that are in a group already.
if ((exists $anvil->data->{storage_groups}{vg_uuid}{$scan_lvm_vg_internal_uuid}) &&
($anvil->data->{storage_groups}{vg_uuid}{$scan_lvm_vg_internal_uuid}{storage_group_uuid}))
{
# Already in a group, we can skip it. We log this data for debugging reasons
# only.
my $storage_group_uuid = $anvil->data->{storage_groups}{vg_uuid}{$scan_lvm_vg_internal_uuid}{storage_group_uuid};
my $group_name = $anvil->data->{storage_groups}{anvil_uuid}{$anvil_uuid}{storage_group_uuid}{$storage_group_uuid}{group_name};
my $storage_group_member_uuid = $anvil->data->{storage_groups}{anvil_uuid}{$anvil_uuid}{storage_group_uuid}{$storage_group_uuid}{host_uuid}{$host_uuid}{vg_uuid}{$scan_lvm_vg_internal_uuid}{storage_group_member_uuid};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
anvil_uuid => $anvil_uuid,
host_uuid => $host_uuid,
storage_group_uuid => $storage_group_uuid,
scan_lvm_vg_internal_uuid => $scan_lvm_vg_internal_uuid,
storage_group_member_uuid => $storage_group_member_uuid,
}});
next;
}
$anvil->data->{ungrouped_vg_count}{$this_is}++;
$anvil->data->{ungrouped_vgs}{$scan_lvm_vg_size}{host_uuid}{$host_uuid}{vg_uuid} = $row->[0];
$anvil->data->{ungrouped_vgs}{$scan_lvm_vg_size}{host_uuid}{$host_uuid}{vg_name} = $row->[1];
$anvil->data->{ungrouped_vgs}{$scan_lvm_vg_size}{host_uuid}{$host_uuid}{vg_extent_size} = $row->[2];
$anvil->data->{ungrouped_vgs}{$scan_lvm_vg_size}{host_uuid}{$host_uuid}{vg_size} = $row->[3];
$anvil->data->{ungrouped_vgs}{$scan_lvm_vg_size}{host_uuid}{$host_uuid}{vg_free} = $row->[4];
$anvil->data->{ungrouped_vgs}{$scan_lvm_vg_size}{host_uuid}{$host_uuid}{vg_internal_uuid} = $row->[5];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"ungrouped_vg_count::${this_is}" => $anvil->data->{ungrouped_vg_count}{$this_is},
"ungrouped_vgs::${scan_lvm_vg_size}::host_uuid::${host_uuid}::count" => $anvil->data->{ungrouped_vgs}{$scan_lvm_vg_size}{host_uuid}{$host_uuid}{count},
"ungrouped_vgs::${scan_lvm_vg_size}::host_uuid::${host_uuid}::vg_uuid" => $anvil->data->{ungrouped_vgs}{$scan_lvm_vg_size}{host_uuid}{$host_uuid}{vg_uuid},
"ungrouped_vgs::${scan_lvm_vg_size}::host_uuid::${host_uuid}::vg_name" => $anvil->data->{ungrouped_vgs}{$scan_lvm_vg_size}{host_uuid}{$host_uuid}{vg_name},
"ungrouped_vgs::${scan_lvm_vg_size}::host_uuid::${host_uuid}::vg_extent_size" => $anvil->data->{ungrouped_vgs}{$scan_lvm_vg_size}{host_uuid}{$host_uuid}{vg_extent_size}." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{ungrouped_vgs}{$scan_lvm_vg_size}{host_uuid}{$host_uuid}{vg_extent_size}}).")",
"ungrouped_vgs::${scan_lvm_vg_size}::host_uuid::${host_uuid}::vg_size" => $anvil->data->{ungrouped_vgs}{$scan_lvm_vg_size}{host_uuid}{$host_uuid}{vg_size}." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{ungrouped_vgs}{$scan_lvm_vg_size}{host_uuid}{$host_uuid}{vg_size}}).")",
"ungrouped_vgs::${scan_lvm_vg_size}::host_uuid::${host_uuid}::vg_free" => $anvil->data->{ungrouped_vgs}{$scan_lvm_vg_size}{host_uuid}{$host_uuid}{vg_free}." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{ungrouped_vgs}{$scan_lvm_vg_size}{host_uuid}{$host_uuid}{vg_free}}).")",
"ungrouped_vgs::${scan_lvm_vg_size}::host_uuid::${host_uuid}::vg_internal_uuid" => $anvil->data->{ungrouped_vgs}{$scan_lvm_vg_size}{host_uuid}{$host_uuid}{vg_internal_uuid},
}});
}
}
# Fing ungrouped VGs and see if we can group them. First by looking for identical sizes.
my $reload_storage_groups = 0;
foreach my $scan_lvm_vg_size (sort {$a cmp $b} keys %{$anvil->data->{ungrouped_vgs}})
{
# If there are two or three VGs, we can create a group.
my $count = keys %{$anvil->data->{ungrouped_vgs}{$scan_lvm_vg_size}{host_uuid}};
if (($count == 2) or ($count == 3))
{
# Create the volume group ... group. First we need a group number
my $storage_group_uuid = $anvil->Database->insert_or_update_storage_groups({
debug => $debug,
storage_group_anvil_uuid => $anvil_uuid,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { storage_group_uuid => $storage_group_uuid }});
foreach my $host_uuid (keys %{$anvil->data->{ungrouped_vgs}{$scan_lvm_vg_size}{host_uuid}})
{
my $this_is = "node1";
if ($host_uuid eq $node2_host_uuid) { $this_is = "node2"; }
elsif ($host_uuid eq $dr1_host_uuid) { $this_is = "dr1"; }
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { this_is => $this_is }});
my $storage_group_member_vg_uuid = $anvil->data->{ungrouped_vgs}{$scan_lvm_vg_size}{host_uuid}{$host_uuid}{vg_internal_uuid};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { storage_group_member_vg_uuid => $storage_group_member_vg_uuid }});
my $storage_group_member_uuid = $anvil->Database->insert_or_update_storage_group_members({
debug => $debug,
storage_group_member_storage_group_uuid => $storage_group_uuid,
storage_group_member_host_uuid => $host_uuid,
storage_group_member_vg_uuid => $storage_group_member_vg_uuid,
});
$anvil->data->{ungrouped_vg_count}{$this_is}--;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"ungrouped_vg_count::${this_is}" => $anvil->data->{ungrouped_vg_count}{$this_is},
}});
}
# Reload storage group data
$reload_storage_groups = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { reload_storage_groups => $reload_storage_groups }});
}
}
# If there's only one VG on each node that is ungrouped, group them even though they're not the same
# size. If DR also has only 1 VG ungrouped, it'll be added, too.
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"ungrouped_vg_count::node1" => $anvil->data->{ungrouped_vg_count}{node1},
"ungrouped_vg_count::node2" => $anvil->data->{ungrouped_vg_count}{node2},
"ungrouped_vg_count::dr1" => $anvil->data->{ungrouped_vg_count}{dr1},
}});
if (($anvil->data->{ungrouped_vg_count}{node1} == 1) && ($anvil->data->{ungrouped_vg_count}{node2} == 1))
{
# We do!
my $storage_group_uuid = $anvil->Database->create_storage_group({
debug => $debug,
storage_group_anvil_uuid => $anvil_uuid,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { storage_group_uuid => $storage_group_uuid }});
my $hosts = [$node1_host_uuid, $node2_host_uuid];
if ($anvil->data->{ungrouped_vg_count}{dr1} == 1)
{
push @{$hosts}, $dr1_host_uuid;
}
foreach my $host_uuid (@{$hosts})
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { host_uuid => $host_uuid }});
# I need to find the size of VG UUID without knowing it's size.
my $storage_group_member_vg_uuid = "";
foreach my $scan_lvm_vg_size (sort {$a cmp $b} keys %{$anvil->data->{ungrouped_vgs}})
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
scan_lvm_vg_size => $scan_lvm_vg_size." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $scan_lvm_vg_size}).")",
}});
if ((exists $anvil->data->{ungrouped_vgs}{$scan_lvm_vg_size}{host_uuid}{$host_uuid}) &&
($anvil->data->{ungrouped_vgs}{$scan_lvm_vg_size}{host_uuid}{$host_uuid}{vg_internal_uuid}))
{
# Found it.
$storage_group_member_vg_uuid = $anvil->data->{ungrouped_vgs}{$scan_lvm_vg_size}{host_uuid}{$host_uuid}{vg_internal_uuid};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { storage_group_member_vg_uuid => $storage_group_member_vg_uuid }});
}
}
my $storage_group_member_uuid = $anvil->Database->insert_or_update_storage_group_members({
debug => $debug,
storage_group_member_storage_group_uuid => $storage_group_uuid,
storage_group_member_host_uuid => $host_uuid,
storage_group_member_vg_uuid => $storage_group_member_vg_uuid,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { storage_group_member_uuid => $storage_group_member_uuid }});
# Reload storage group data
$reload_storage_groups = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { reload_storage_groups => $reload_storage_groups }});
}
}
if ($reload_storage_groups)
{
$anvil->Database->get_storage_group_data({debug => $debug});
}
return(0);
}
=head2 boot_server =head2 boot_server
This uses pacemaker to boot a server. This uses pacemaker to boot a server.
@ -289,12 +553,65 @@ sub check_node_status
return($anvil->data->{cib}{parsed}{data}{node}{$node_name}{node_state}{ready}); return($anvil->data->{cib}{parsed}{data}{node}{$node_name}{node_state}{ready});
} }
=head2 get_anvil_name
This returns the C<< anvils >> -> C<< anvil_name >> for a given C<< anvil_uuid >>. If no C<< anvil_uuid >> is passed, a check is made to see if this host is in an Anvil! and, if so, the Anvil! name it's a member of is returned.
If not match is found, a blank string is returned.
Parameters;
=head3 anvil_uuid (optional, default Cluster->get_anvil_uuid)
This is the C<< anvil_uuid >> of the Anvil! whose name we're looking for.
=cut
sub get_anvil_name
{
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 => "Cluster->get_anvil_name()" }});
my $anvil_uuid = defined $parameter->{anvil_uuid} ? $parameter->{anvil_uuid} : $anvil->Get->anvil_uuid;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
anvil_uuid => $anvil_uuid,
}});
my $anvil_name = "";
if (not $anvil_uuid)
{
$anvil_uuid = $anvil->Cluster->get_anvil_uuid({debug => $debug});
}
if (not $anvil_uuid)
{
return($anvil_name);
}
# Load the Anvil! data.
$anvil->Database->get_anvils({debug => $debug});
if (exists $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid})
{
$anvil_name = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_name};
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { anvil_name => $anvil_name }});
return($anvil_name);
}
=head2 get_anvil_uuid =head2 get_anvil_uuid
This returns the C<< anvils >> -> C<< anvil_uuid >> that a host belongs to. If the host is not found in any Anvil!, an empty string is returned. This returns the C<< anvils >> -> C<< anvil_uuid >> that a host belongs to. If the host is not found in any Anvil!, an empty string is returned.
Optionally, this method can be passed an C<< anvil_name >>. If so, the name is used to find the UUID.
Parameters; Parameters;
=head3 anvil_name (optional)
If set, this is used to look up the Anvil! UUID.
=head3 host_uuid (optional, default Get->host_uuid) =head3 host_uuid (optional, default Get->host_uuid)
This is the C<< host_uuid >> of the host who we're looking for Anvil! membership of. This is the C<< host_uuid >> of the host who we're looking for Anvil! membership of.
@ -308,15 +625,29 @@ sub get_anvil_uuid
my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3; my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3;
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "Cluster->get_anvil_uuid()" }}); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "Cluster->get_anvil_uuid()" }});
my $anvil_name = defined $parameter->{anvil_name} ? $parameter->{anvil_name} : "";
my $host_uuid = defined $parameter->{host_uuid} ? $parameter->{host_uuid} : $anvil->Get->host_uuid; my $host_uuid = defined $parameter->{host_uuid} ? $parameter->{host_uuid} : $anvil->Get->host_uuid;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
anvil_name => $anvil_name,
host_uuid => $host_uuid, host_uuid => $host_uuid,
}}); }});
# Load the Anvil! data. # Load the Anvil! data.
$anvil->Database->get_anvils({debug => $debug}); $anvil->Database->get_anvils({debug => $debug});
my $member_anvil_uuid = "";
if ($anvil_name)
{
# Convert to the UUID directly.
my $anvil_uuid = "";
if (exists $anvil->data->{anvils}{anvil_name}{$anvil_name})
{
$anvil_uuid = $anvil->data->{anvils}{anvil_name}{$anvil_name}{anvil_uuid};
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { anvil_uuid => $anvil_uuid }});
return($anvil_uuid);
}
my $member_anvil_uuid = "";
foreach my $anvil_uuid (keys %{$anvil->data->{anvils}{anvil_uuid}}) foreach my $anvil_uuid (keys %{$anvil->data->{anvils}{anvil_uuid}})
{ {
my $anvil_name = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_name}; my $anvil_name = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_name};

@ -3758,6 +3758,12 @@ FROM
"servers::server_uuid::${server_uuid}::server_updated_by_user" => $anvil->data->{servers}{server_uuid}{$server_uuid}{server_updated_by_user}, "servers::server_uuid::${server_uuid}::server_updated_by_user" => $anvil->data->{servers}{server_uuid}{$server_uuid}{server_updated_by_user},
"servers::server_uuid::${server_uuid}::server_boot_time" => $anvil->data->{servers}{server_uuid}{$server_uuid}{server_boot_time}, "servers::server_uuid::${server_uuid}::server_boot_time" => $anvil->data->{servers}{server_uuid}{$server_uuid}{server_boot_time},
}}); }});
# Store the servers in a hash under each Anvil!, sortable.
$anvil->data->{servers}{anvil_uuid}{$server_anvil_uuid}{server_name}{$server_name}{server_uuid} = $server_uuid;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"servers::anvil_uuid::${server_anvil_uuid}::server_name::${server_name}::server_uuid" => $anvil->data->{servers}{anvil_uuid}{$server_anvil_uuid}{server_name}{$server_name}{server_uuid},
}});
} }
return(0); return(0);

@ -385,203 +385,21 @@ WHERE
"anvil_resources::${anvil_uuid}::has_dr" => $anvil->data->{anvil_resources}{$anvil_uuid}{has_dr}, "anvil_resources::${anvil_uuid}::has_dr" => $anvil->data->{anvil_resources}{$anvil_uuid}{has_dr},
}}); }});
# Load hosts, Network bridge, and Storages group data # Load hosts and network bridges
$anvil->Database->get_hosts({debug => $debug}); $anvil->Database->get_hosts({debug => $debug});
$anvil->Database->get_bridges({debug => $debug}); $anvil->Database->get_bridges({debug => $debug});
$anvil->Database->get_storage_group_data({debug => $debug});
# This both loads storage group data and assembles ungrouped VGs into storage groups, when possible.
$anvil->Cluster->assemble_storage_groups({
debug => $debug,
anvil_uuid => $anvil_uuid,
});
# This will store the available resources based on the least of the nodes. # This will store the available resources based on the least of the nodes.
$anvil->data->{anvil_resources}{$anvil_uuid}{cpu}{cores} = 0; $anvil->data->{anvil_resources}{$anvil_uuid}{cpu}{cores} = 0;
$anvil->data->{anvil_resources}{$anvil_uuid}{cpu}{threads} = 0; $anvil->data->{anvil_resources}{$anvil_uuid}{cpu}{threads} = 0;
$anvil->data->{anvil_resources}{$anvil_uuid}{ram}{hardware} = 0; $anvil->data->{anvil_resources}{$anvil_uuid}{ram}{hardware} = 0;
# Before we see how much disk space is available, look for ungrouped VGs and see if we can group them
# by matching identical sizes together.
foreach my $host_uuid ($node1_host_uuid, $node2_host_uuid, $dr1_host_uuid)
{
# If DR isn't defined, it'll be blank.
next if not $host_uuid;
my $this_is = "node1";
if ($host_uuid eq $node2_host_uuid) { $this_is = "node2"; }
elsif ($host_uuid eq $dr1_host_uuid) { $this_is = "dr1"; }
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { this_is => $this_is }});
$anvil->data->{ungrouped_vg_count}{$this_is} = 0;
my $query = "
SELECT
scan_lvm_vg_uuid,
scan_lvm_vg_name,
scan_lvm_vg_extent_size,
scan_lvm_vg_size,
scan_lvm_vg_free,
scan_lvm_vg_internal_uuid
FROM
scan_lvm_vgs
WHERE
scan_lvm_vg_host_uuid = ".$anvil->Database->quote($host_uuid)."
ORDER BY
scan_lvm_vg_size 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_lvm_vg_size = $row->[3];
my $scan_lvm_vg_internal_uuid = $row->[5];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
scan_lvm_vg_size => $scan_lvm_vg_size." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $scan_lvm_vg_size}).")",
scan_lvm_vg_internal_uuid => $scan_lvm_vg_internal_uuid,
}});
# Skip VGs that are in a group already.
if ((exists $anvil->data->{storage_groups}{vg_uuid}{$scan_lvm_vg_internal_uuid}) &&
($anvil->data->{storage_groups}{vg_uuid}{$scan_lvm_vg_internal_uuid}{storage_group_uuid}))
{
# Already in a group, we can skip it. We log this data for debugging reasons
# only.
my $storage_group_uuid = $anvil->data->{storage_groups}{vg_uuid}{$scan_lvm_vg_internal_uuid}{storage_group_uuid};
my $group_name = $anvil->data->{storage_groups}{anvil_uuid}{$anvil_uuid}{storage_group_uuid}{$storage_group_uuid}{group_name};
my $storage_group_member_uuid = $anvil->data->{storage_groups}{anvil_uuid}{$anvil_uuid}{storage_group_uuid}{$storage_group_uuid}{host_uuid}{$host_uuid}{vg_uuid}{$scan_lvm_vg_internal_uuid}{storage_group_member_uuid};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
anvil_uuid => $anvil_uuid,
host_uuid => $host_uuid,
storage_group_uuid => $storage_group_uuid,
scan_lvm_vg_internal_uuid => $scan_lvm_vg_internal_uuid,
storage_group_member_uuid => $storage_group_member_uuid,
}});
next;
}
$anvil->data->{ungrouped_vg_count}{$this_is}++;
$anvil->data->{ungrouped_vgs}{$scan_lvm_vg_size}{host_uuid}{$host_uuid}{vg_uuid} = $row->[0];
$anvil->data->{ungrouped_vgs}{$scan_lvm_vg_size}{host_uuid}{$host_uuid}{vg_name} = $row->[1];
$anvil->data->{ungrouped_vgs}{$scan_lvm_vg_size}{host_uuid}{$host_uuid}{vg_extent_size} = $row->[2];
$anvil->data->{ungrouped_vgs}{$scan_lvm_vg_size}{host_uuid}{$host_uuid}{vg_size} = $row->[3];
$anvil->data->{ungrouped_vgs}{$scan_lvm_vg_size}{host_uuid}{$host_uuid}{vg_free} = $row->[4];
$anvil->data->{ungrouped_vgs}{$scan_lvm_vg_size}{host_uuid}{$host_uuid}{vg_internal_uuid} = $row->[5];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"ungrouped_vg_count::${this_is}" => $anvil->data->{ungrouped_vg_count}{$this_is},
"ungrouped_vgs::${scan_lvm_vg_size}::host_uuid::${host_uuid}::count" => $anvil->data->{ungrouped_vgs}{$scan_lvm_vg_size}{host_uuid}{$host_uuid}{count},
"ungrouped_vgs::${scan_lvm_vg_size}::host_uuid::${host_uuid}::vg_uuid" => $anvil->data->{ungrouped_vgs}{$scan_lvm_vg_size}{host_uuid}{$host_uuid}{vg_uuid},
"ungrouped_vgs::${scan_lvm_vg_size}::host_uuid::${host_uuid}::vg_name" => $anvil->data->{ungrouped_vgs}{$scan_lvm_vg_size}{host_uuid}{$host_uuid}{vg_name},
"ungrouped_vgs::${scan_lvm_vg_size}::host_uuid::${host_uuid}::vg_extent_size" => $anvil->data->{ungrouped_vgs}{$scan_lvm_vg_size}{host_uuid}{$host_uuid}{vg_extent_size}." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{ungrouped_vgs}{$scan_lvm_vg_size}{host_uuid}{$host_uuid}{vg_extent_size}}).")",
"ungrouped_vgs::${scan_lvm_vg_size}::host_uuid::${host_uuid}::vg_size" => $anvil->data->{ungrouped_vgs}{$scan_lvm_vg_size}{host_uuid}{$host_uuid}{vg_size}." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{ungrouped_vgs}{$scan_lvm_vg_size}{host_uuid}{$host_uuid}{vg_size}}).")",
"ungrouped_vgs::${scan_lvm_vg_size}::host_uuid::${host_uuid}::vg_free" => $anvil->data->{ungrouped_vgs}{$scan_lvm_vg_size}{host_uuid}{$host_uuid}{vg_free}." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{ungrouped_vgs}{$scan_lvm_vg_size}{host_uuid}{$host_uuid}{vg_free}}).")",
"ungrouped_vgs::${scan_lvm_vg_size}::host_uuid::${host_uuid}::vg_internal_uuid" => $anvil->data->{ungrouped_vgs}{$scan_lvm_vg_size}{host_uuid}{$host_uuid}{vg_internal_uuid},
}});
}
}
# Fing ungrouped VGs and see if we can pair them
my $reload_storage_groups = 0;
foreach my $scan_lvm_vg_size (sort {$a cmp $b} keys %{$anvil->data->{ungrouped_vgs}})
{
# If there are two or three VGs, we can create a group.
my $count = keys %{$anvil->data->{ungrouped_vgs}{$scan_lvm_vg_size}{host_uuid}};
if (($count == 2) or ($count == 3))
{
# Create the volume group ... group. First we need a group number
my $storage_group_uuid = $anvil->Database->insert_or_update_storage_groups({
debug => $debug,
storage_group_anvil_uuid => $anvil_uuid,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { storage_group_uuid => $storage_group_uuid }});
foreach my $host_uuid (keys %{$anvil->data->{ungrouped_vgs}{$scan_lvm_vg_size}{host_uuid}})
{
my $this_is = "node1";
if ($host_uuid eq $node2_host_uuid) { $this_is = "node2"; }
elsif ($host_uuid eq $dr1_host_uuid) { $this_is = "dr1"; }
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { this_is => $this_is }});
my $storage_group_member_vg_uuid = $anvil->data->{ungrouped_vgs}{$scan_lvm_vg_size}{host_uuid}{$host_uuid}{vg_internal_uuid};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { storage_group_member_vg_uuid => $storage_group_member_vg_uuid }});
my $storage_group_member_uuid = $anvil->Database->insert_or_update_storage_group_members({
debug => $debug,
storage_group_member_storage_group_uuid => $storage_group_uuid,
storage_group_member_host_uuid => $host_uuid,
storage_group_member_vg_uuid => $storage_group_member_vg_uuid,
});
$anvil->data->{ungrouped_vg_count}{$this_is}--;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"ungrouped_vg_count::${this_is}" => $anvil->data->{ungrouped_vg_count}{$this_is},
}});
}
# Reload storage group data
$reload_storage_groups = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { reload_storage_groups => $reload_storage_groups }});
}
}
# If there's only one VG on each node that is ungrouped, group them even though they're not the same
# size. If DR also has only 1 VG ungrouped, it'll be added, too.
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"ungrouped_vg_count::node1" => $anvil->data->{ungrouped_vg_count}{node1},
"ungrouped_vg_count::node2" => $anvil->data->{ungrouped_vg_count}{node2},
"ungrouped_vg_count::dr1" => $anvil->data->{ungrouped_vg_count}{dr1},
}});
if (($anvil->data->{ungrouped_vg_count}{node1} == 1) && ($anvil->data->{ungrouped_vg_count}{node2} == 1))
{
# We do!
my $storage_group_uuid = $anvil->Database->create_storage_group({
debug => $debug,
storage_group_anvil_uuid => $anvil_uuid,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { storage_group_uuid => $storage_group_uuid }});
my $hosts = [$node1_host_uuid, $node2_host_uuid];
if ($anvil->data->{ungrouped_vg_count}{dr1} == 1)
{
push @{$hosts}, $dr1_host_uuid;
}
foreach my $host_uuid (@{$hosts})
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { host_uuid => $host_uuid }});
# I need to find the size of VG UUID without knowing it's size.
my $storage_group_member_vg_uuid = "";
foreach my $scan_lvm_vg_size (sort {$a cmp $b} keys %{$anvil->data->{ungrouped_vgs}})
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
scan_lvm_vg_size => $scan_lvm_vg_size." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $scan_lvm_vg_size}).")",
}});
if ((exists $anvil->data->{ungrouped_vgs}{$scan_lvm_vg_size}{host_uuid}{$host_uuid}) &&
($anvil->data->{ungrouped_vgs}{$scan_lvm_vg_size}{host_uuid}{$host_uuid}{vg_internal_uuid}))
{
# Found it.
$storage_group_member_vg_uuid = $anvil->data->{ungrouped_vgs}{$scan_lvm_vg_size}{host_uuid}{$host_uuid}{vg_internal_uuid};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { storage_group_member_vg_uuid => $storage_group_member_vg_uuid }});
}
}
my $storage_group_member_uuid = $anvil->Database->insert_or_update_storage_group_members({
debug => $debug,
storage_group_member_storage_group_uuid => $storage_group_uuid,
storage_group_member_host_uuid => $host_uuid,
storage_group_member_vg_uuid => $storage_group_member_vg_uuid,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { storage_group_member_uuid => $storage_group_member_uuid }});
# Reload storage group data
$reload_storage_groups = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { reload_storage_groups => $reload_storage_groups }});
}
}
if ($reload_storage_groups)
{
$anvil->Database->get_storage_group_data({debug => $debug});
}
foreach my $host_uuid ($node1_host_uuid, $node2_host_uuid, $dr1_host_uuid) foreach my $host_uuid ($node1_host_uuid, $node2_host_uuid, $dr1_host_uuid)
{ {
# If DR isn't defined, it'll be blank. # If DR isn't defined, it'll be blank.
@ -691,18 +509,6 @@ WHERE
}}); }});
} }
} }
# Now read in the LVM VG data.
undef $query;
undef $results;
undef $count;
# TODO: Left off here; We'll now look for unassigned VGs. Ones that aren't, if we find a
# matching size one on both nodes / DR, we'll group them automatically. If only one VG
# is unassigned on each node / dr host, they will be grouped as well.
# After this, we'll look at groups and track which has the least free space per group,
# ignoring DR for now as it's feasible a user builds a lesser-spec'ed DR for a subset
# of VMs
} }
# Read in the amount of RAM allocated to servers and subtract it from the RAM available. # Read in the amount of RAM allocated to servers and subtract it from the RAM available.
@ -809,6 +615,8 @@ ORDER BY
This finds a list of bridges on the host. Bridges that are found are stored is ' This finds a list of bridges on the host. Bridges that are found are stored is '
This method takes no parameters.
=cut =cut
sub bridges sub bridges
{ {

@ -102,6 +102,12 @@ sub clear
my $job_uuid = defined $parameter->{job_uuid} ? $parameter->{job_uuid} : ""; my $job_uuid = defined $parameter->{job_uuid} ? $parameter->{job_uuid} : "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { job_uuid => $job_uuid }}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { job_uuid => $job_uuid }});
if ((not $job_uuid) && ($anvil->data->{switches}{'job-uuid'}))
{
$job_uuid = $anvil->data->{switches}{'job-uuid'};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { job_uuid => $job_uuid }});
}
# Return if we don't have a program name. # Return if we don't have a program name.
if ($job_uuid eq "") if ($job_uuid eq "")
{ {

@ -99,6 +99,7 @@ sub parent
# Public methods # # Public methods #
############################################################################################################# #############################################################################################################
=head2 backup =head2 backup
This will create a copy of the file under the C<< path::directories::backups >> directory with the datestamp as a suffix. The path is preserved under the backup directory. The path and file name are returned. This will create a copy of the file under the C<< path::directories::backups >> directory with the datestamp as a suffix. The path is preserved under the backup directory. The path and file name are returned.

@ -1375,6 +1375,7 @@ About to try to download aproximately: [#!variable!packages!#] packages needed t
# Please do edit or remove it. # Please do edit or remove it.
# scan_drbd_resource_uuid = #!variable!uuid!# # scan_drbd_resource_uuid = #!variable!uuid!#
</key> <!-- Translation note: The format of [# scan_drbd_resource_uuid = #!variable!uuid!#] is important, don't alter it. --> </key> <!-- Translation note: The format of [# scan_drbd_resource_uuid = #!variable!uuid!#] is important, don't alter it. -->
<key name="message_0190">Preparing to provision a new server.</key>
<!-- Success messages shown to the user --> <!-- Success messages shown to the user -->
<key name="ok_0001">Saved the mail server information successfully!</key> <key name="ok_0001">Saved the mail server information successfully!</key>

@ -0,0 +1,354 @@
#!/usr/bin/perl
#
# This provisions a new virtual machine server. It handles creating the logical volumes, DRBD resources,
# verifies the needed files are ready, creates the provision script, begins the installation, and adds the
# new server to pacemaker.
#
# Exit codes;
# 0 = Normal exit.
use strict;
use warnings;
use Anvil::Tools;
require POSIX;
use Term::Cap;
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();
$anvil->Log->level({set => 2});
$anvil->Log->secure({set => 1});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, secure => 0, key => "log_0115", variables => { program => $THIS_FILE }});
# Read switches (target ([user@]host[:port]) and the file with the target's password. If the password is
# passed directly, it will be used. Otherwise, the password will be read from the database.
$anvil->data->{switches}{'anvil-uuid'} = "";
$anvil->data->{switches}{cpu} = "";
$anvil->data->{switches}{'job-uuid'} = "";
$anvil->data->{switches}{name} = "";
$anvil->Get->switches;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
'switches::anvil-uuid' => $anvil->data->{switches}{'anvil-uuid'},
'switches::cpu' => $anvil->data->{switches}{cpu},
'switches::job-uuid' => $anvil->data->{switches}{'job-uuid'},
'switches::name' => $anvil->data->{switches}{name},
}});
$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_0077"});
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'} }});
}
# If we still don't have a job-uuit, go into interactive mode.
if ($anvil->data->{switches}{'job-uuid'})
{
# Load the job data.
$anvil->Job->clear();
$anvil->Job->get_job_details();
$anvil->Job->update_progress({
progress => 1,
message => "message_0190",
});
# Job data will be in $anvil->data->{jobs}{job_data}
}
else
{
# Interactive!
interactive_question($anvil);
}
$anvil->nice_exit({exit_code => 0});
#############################################################################################################
# Functions #
#############################################################################################################
# Go through a series of questions to ask the user how they want to build their server.
sub interactive_question
{
my ($anvil) = @_;
# Do we know or can we find the Anvil! UUID?
$anvil->data->{new_server}{anvil_uuid} = $anvil->data->{switches}{'anvil-uuid'} ? $anvil->data->{switches}{'anvil-uuid'} : "";
$anvil->data->{new_server}{anvil_name} = $anvil->data->{switches}{'anvil-name'} ? $anvil->data->{switches}{'anvil-name'} : "";
if ((not $anvil->data->{new_server}{anvil_uuid}) && (not $anvil->data->{new_server}{anvil_name}))
{
# Nothing given. Is this host a node, perhaps?
my $anvil_uuid = $anvil->Cluster->get_anvil_uuid();
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { anvil_uuid => $anvil_uuid }});
if ($anvil_uuid)
{
$anvil->data->{new_server}{anvil_uuid} = $anvil_uuid;
$anvil->data->{new_server}{anvil_name} = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_name};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"new_server::anvil_name" => $anvil->data->{new_server}{anvil_name},
"new_server::anvil_uuid" => $anvil->data->{new_server}{anvil_uuid},
}});
}
}
elsif (not $anvil->data->{new_server}{anvil_uuid})
{
$anvil->data->{new_server}{anvil_uuid} = $anvil->Cluster->get_anvil_uuid({anvil_name => $anvil->data->{new_server}{anvil_name}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "new_server::anvil_uuid" => $anvil->data->{new_server}{anvil_uuid} }});
}
elsif (not $anvil->data->{new_server}{anvil_name})
{
$anvil->data->{new_server}{anvil_name} = $anvil->Cluster->get_anvil_name({anvil_uuid => $anvil->data->{new_server}{anvil_uuid}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "new_server::anvil_name" => $anvil->data->{new_server}{anvil_name} }});
}
$anvil->data->{new_server}{name} = $anvil->data->{switches}{name} ? $anvil->data->{switches}{name} : "";
# If this is a node, load the anvil_uuid automatically.
my $termios = new POSIX::Termios;
$termios->getattr;
my $ospeed = $termios->getospeed;
my $terminal = Tgetent Term::Cap { TERM => undef, OSPEED => $ospeed };
$terminal->Trequire(qw/ce ku kd/);
interactive_ask_anvil_name($anvil, $terminal);
interactive_ask_server_name($anvil, $terminal);
interactive_ask_server_cpu($anvil, $terminal);
return(0);
}
sub interactive_ask_anvil_name
{
my ($anvil, $terminal) = @_;
$anvil->Database->get_anvils();
my $retry = 0;
while(1)
{
my $default_anvil = $anvil->data->{new_server}{anvil_name};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { default_anvil => $default_anvil }});
if (not $default_anvil)
{
my $known_anvils = keys %{$anvil->data->{anvils}{anvil_name}};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { known_anvils => $known_anvils }});
if (not $known_anvils)
{
print "There are no known Anvil! systems at this time. Please setup an Anvil! and try again later.\n";
$anvil->nice_exit({exit_code => 1});
}
elsif ($known_anvils == 1)
{
foreach my $anvil_name (keys %{$anvil->data->{anvils}{anvil_name}})
{
$default_anvil = $anvil_name;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { default_anvil => $default_anvil }});
}
}
}
print $terminal->Tputs('cl');
print "Provision a new server menu:\n";
print "Anvil name: [".$default_anvil."]\n\n\n";
# Show all the current server names.
if ($retry)
{
print "* That was not a recognized Anvil! name. please try again.\n\n";
}
print "-=] Existing Anvil! systems [=-\n";
foreach my $anvil_name (sort {$a cmp $b} keys %{$anvil->data->{anvils}{anvil_name}})
{
print "- ".$anvil_name.": - ".$anvil->data->{anvils}{anvil_name}{$anvil_name}{anvil_description}."\n";
}
print $terminal->Tgoto('cm', 0, 2);
my $answer = <STDIN>;
chomp $answer;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { answer => $answer }});
if ((not $answer) && ($default_anvil))
{
$answer = $default_anvil;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { answer => $answer }});
}
# Reload in case a new anvil! was saved while we waited.
$anvil->Database->get_anvils();
if (exists $anvil->data->{anvils}{anvil_name}{$answer})
{
# Valid.
$anvil->data->{new_server}{anvil_name} = $answer;
$anvil->data->{new_server}{anvil_uuid} = $anvil->Cluster->get_anvil_uuid({anvil_name => $answer});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"new_server::anvil_name" => $anvil->data->{new_server}{anvil_name},
"new_server::anvil_uuid" => $anvil->data->{new_server}{anvil_uuid},
}});
print "Loading available resources for: [".$anvil->data->{new_server}{anvil_name}."] (".$anvil->data->{new_server}{anvil_uuid}.")\n";
$anvil->Get->available_resources({
debug => 2,
anvil_uuid => $anvil->data->{new_server}{anvil_uuid},
});
last;
}
else
{
$retry = 1;
}
}
return(0);
}
sub interactive_ask_server_name
{
my ($anvil, $terminal) = @_;
$anvil->Database->get_servers({debug => 2});
### TODO: Figure out how many rows we have and break the server list into columns if too long.
my $retry = 0;
while(1)
{
my $default = "";
if ($anvil->data->{switches}{name})
{
$default = $anvil->data->{switches}{name};
}
print $terminal->Tputs('cl');
print "Provision a new server menu:\n";
print "Anvil name: [".$anvil->data->{new_server}{anvil_name}."]\n";
print "Server name: [".$anvil->data->{new_server}{name}."]\n\n\n";
# Show all the current server names.
if ($retry)
{
print "* Please enter a unique server name.\n\n";
}
my $anvil_uuid = $anvil->data->{new_server}{anvil_uuid};
print "-=] Existing Servers on the Anvil! [".$anvil->data->{new_server}{anvil_name}."] [=-\n";
foreach my $server_name (sort {$a cmp $b} keys %{$anvil->data->{servers}{anvil_uuid}{$anvil_uuid}{server_name}})
{
print "- ".$server_name."\n";
}
print $terminal->Tgoto('cm', 0, 3);
my $answer = <STDIN>;
chomp $answer;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { answer => $answer }});
if ((not $answer) && ($default))
{
$answer = $default;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { answer => $answer }});
}
# Reload in case a new anvil! was saved while we waited.
$anvil->Database->get_servers();
if (($answer) && (not exists $anvil->data->{servers}{anvil_uuid}{$anvil_uuid}{server_name}{$answer}))
{
# Valid.
$anvil->data->{new_server}{name} = $answer;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"new_server::name" => $anvil->data->{new_server}{name},
}});
last;
}
else
{
$retry = 1;
}
}
return(0);
}
sub interactive_ask_server_cpu
{
my ($anvil, $terminal) = @_;
my $retry = 0;
while(1)
{
my $anvil_uuid = $anvil->data->{new_server}{anvil_uuid};
$anvil->Database->get_anvils();
$anvil->Get->available_resources({anvil_uuid => $anvil_uuid});
my $default_cpu = $anvil->data->{switches}{cpu};
if (not $default_cpu)
{
# Default to 2, unless only one core is available.
$default_cpu = $anvil->data->{anvil_resources}{$anvil_uuid}{cpu}{threads} == 1 ? 1 : 2;
}
print $terminal->Tputs('cl');
print "Provision a new server menu:\n";
print "Anvil name: [".$anvil->data->{new_server}{anvil_name}."]\n";
print "Server name: [".$anvil->data->{new_server}{name}."]\n";
print "CPU Cores: . [".$default_cpu."]\n\n\n";
if ($retry)
{
print "* Please enter a number between 1 and ".$anvil->data->{anvil_resources}{$anvil_uuid}{cpu}{threads}.".\n\n";
}
print "-=] Available cores / threads: [".$anvil->data->{anvil_resources}{$anvil_uuid}{cpu}{cores}." / ".$anvil->data->{anvil_resources}{$anvil_uuid}{cpu}{threads}."]\n";
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};
print " - Node 1 CPU Model: [".$anvil->data->{anvil_resources}{$anvil_uuid}{host_uuid}{$node1_host_uuid}{cpu}{model}."]\n";
print " - Node 2 CPU Model: [".$anvil->data->{anvil_resources}{$anvil_uuid}{host_uuid}{$node2_host_uuid}{cpu}{model}."]\n";
print $terminal->Tgoto('cm', 0, 4);
my $answer = <STDIN>;
chomp $answer;
if ($answer eq "")
{
$answer = $default_cpu;
}
if (($answer) && ($answer =~ /^\d+$/) && ($answer <= $anvil->data->{anvil_resources}{$anvil_uuid}{cpu}{threads}))
{
# Valid.
$anvil->data->{new_server}{cpu} = $answer;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"new_server::cpu" => $anvil->data->{new_server}{cpu},
}});
last;
}
else
{
$retry = 1;
}
}
return(0);
}
Loading…
Cancel
Save