You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@vcl.apache.org by ar...@apache.org on 2017/06/06 16:09:58 UTC
svn commit: r1797800 - in /vcl/trunk/managementnode/lib/VCL:
DataStructure.pm Module/OS/Windows.pm utils.pm
Author: arkurth
Date: Tue Jun 6 16:09:58 2017
New Revision: 1797800
URL: http://svn.apache.org/viewvc?rev=1797800&view=rev
Log:
VCL-867
Renamed Windows.pm::ad_join to ad_join_ps to differentiate it from the experimental ad_join_wmic.
Fixed problems with passwords containing special characters in ad_join_ps. Single quotes are now escaped.
Added debugging output to the script generated in ad_join_ps and ad_search.
Replaced utils.pm::get_active_directory_domain_credentials with get_management_node_ad_domain_credentials, called from DataStructure.pm::get_domain_credentials.
Added DataStructure.pm::get_domain_credentials, called from Windows.pm::ad_search instead of utils.pm::get_active_directory_domain_credentials. When retrieving credentials for a domain other than one assigned to the image of the current reservation, VCL object access is required to decrypt the password.
Modified:
vcl/trunk/managementnode/lib/VCL/DataStructure.pm
vcl/trunk/managementnode/lib/VCL/Module/OS/Windows.pm
vcl/trunk/managementnode/lib/VCL/utils.pm
Modified: vcl/trunk/managementnode/lib/VCL/DataStructure.pm
URL: http://svn.apache.org/viewvc/vcl/trunk/managementnode/lib/VCL/DataStructure.pm?rev=1797800&r1=1797799&r2=1797800&view=diff
==============================================================================
--- vcl/trunk/managementnode/lib/VCL/DataStructure.pm (original)
+++ vcl/trunk/managementnode/lib/VCL/DataStructure.pm Tue Jun 6 16:09:58 2017
@@ -2797,7 +2797,44 @@ sub get_image_domain_password {
return;
}
- return $self->mn_os->decrypt_cryptsecret($secret_id, $encrypted_password);
+ my $image_domain_password = $self->mn_os->decrypt_cryptsecret($secret_id, $encrypted_password);
+ #notify($ERRORS{'DEBUG'}, 0, string_to_ascii($image_domain_password));
+ return $image_domain_password;
+}
+
+#//////////////////////////////////////////////////////////////////////////////
+
+=head2 get_domain_credentials
+
+ Parameters : $domain_identifier
+ Returns : array ($username, $domain_password)
+ Description : Attempts to determine and decrypt the username and password for
+ the domain specified by the argument.
+
+=cut
+
+sub get_domain_credentials {
+ my $self = shift;
+ if (ref($self) !~ /VCL::/i) {
+ notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
+ return 0;
+ }
+
+ my $domain_identifier = shift;
+ if (!defined($domain_identifier)) {
+ notify($ERRORS{'WARNING'}, 0, "domain identifier argument was not supplied");
+ return;
+ }
+
+ my $management_node_id = $self->get_management_node_id();
+
+ my ($username, $secret_id, $encrypted_password) = get_management_node_ad_domain_credentials($management_node_id, $domain_identifier);
+ return unless $username && $secret_id && $encrypted_password;
+
+ my $domain_password = $self->mn_os->decrypt_cryptsecret($secret_id, $encrypted_password) || return;
+
+ notify($ERRORS{'DEBUG'}, 0, "retrieved credentials for Active Directory domain:\nusername: '$username'\npassword: '$domain_password'");
+ return ($username, $domain_password);
}
#//////////////////////////////////////////////////////////////////////////////
Modified: vcl/trunk/managementnode/lib/VCL/Module/OS/Windows.pm
URL: http://svn.apache.org/viewvc/vcl/trunk/managementnode/lib/VCL/Module/OS/Windows.pm?rev=1797800&r1=1797799&r2=1797800&view=diff
==============================================================================
--- vcl/trunk/managementnode/lib/VCL/Module/OS/Windows.pm (original)
+++ vcl/trunk/managementnode/lib/VCL/Module/OS/Windows.pm Tue Jun 6 16:09:58 2017
@@ -13243,8 +13243,8 @@ sub run_powershell_command {
Description : Accepts a string containing the contents of a Powershell script,
creates the script on the computer under C:\cygwin\VCL\Scripts,
and executes the script. The script is named after the calling
- subroutine, so ad_join.ps1 would be generated when invoked from
- ad_join().
+ subroutine, so ad_join_ps.ps1 would be generated when invoked from
+ ad_join_ps().
By default, the script file is deleted after it is executed for
safety. This can be overridden if the $retain_script_file
@@ -13556,7 +13556,7 @@ sub ad_check {
if (!$computer_current_domain_name) {
# Computer is not joined to an AD domain, return the result of attempting to join
notify($ERRORS{'OK'}, 0, "image is configured to join the $image_domain_dns_name domain, $computer_name is not joined to a domain, attempting to join the domain");
- return $self->ad_join();
+ return $self->ad_join_ps();
}
@@ -13568,7 +13568,7 @@ sub ad_check {
notify($ERRORS{'WARNING'}, 0, "image is configured to join the $image_domain_dns_name, failed to unjoin $computer_name from the $computer_current_domain_name domain, returning undefined");
return;
}
- elsif (!$self->ad_join()) {
+ elsif (!$self->ad_join_ps()) {
notify($ERRORS{'WARNING'}, 0, "image is configured to join the $image_domain_dns_name, unjoined $computer_name from the incorrect $computer_current_domain_name domain but failed to rejoin the correct $image_domain_dns_name domain, returning undefined");
return;
}
@@ -13618,7 +13618,7 @@ sub ad_check {
notify($ERRORS{'WARNING'}, 0, "failed to unjoin $computer_name from the $computer_current_domain_name domain in order to rejoin in the correct OU, returning undefined");
return;
}
- elsif (!$self->ad_join()) {
+ elsif (!$self->ad_join_ps()) {
notify($ERRORS{'WARNING'}, 0, "failed to rejoin $computer_name to the correct OU in the $image_domain_dns_name domain: '$image_ou_dn', returning undefined");
return;
}
@@ -13630,7 +13630,7 @@ sub ad_check {
#//////////////////////////////////////////////////////////////////////////////
-=head2 ad_join
+=head2 ad_join_ps
Parameters : none
Returns : boolean
@@ -13639,7 +13639,7 @@ sub ad_check {
=cut
-sub ad_join {
+sub ad_join_ps {
my $self = shift;
if (ref($self) !~ /windows/i) {
notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
@@ -13657,7 +13657,6 @@ sub ad_join {
my $domain_dns_name = $self->data->get_image_domain_dns_name();
my $domain_username = $self->data->get_image_domain_username();
my $domain_password = $self->data->get_image_domain_password();
-
my $computer_ou_dn = $self->get_ad_computer_ou_dn();
if (!defined($domain_dns_name)) {
@@ -13676,26 +13675,24 @@ sub ad_join {
# Figure out/fix the computer OU and assemble optional section to add to PowerShell command
my $domain_computer_command_section = '';
if ($computer_ou_dn) {
- $domain_computer_command_section = "-OUPath \"$computer_ou_dn\"";
+ $domain_computer_command_section = "-OUPath '$computer_ou_dn'";
}
my $domain_user_string = "$domain_username\@$domain_dns_name";
+ # Escape single quotes by doubling them
+ (my $domain_password_escaped = $domain_password) =~ s/(['])/$1$1/g;
+
notify($ERRORS{'DEBUG'}, 0, "attempting to join $computer_name to AD\n" .
"domain DNS name : $domain_dns_name\n" .
"domain user string : $domain_user_string\n" .
- "domain password : $domain_password\n" .
+ "domain password : $domain_password (escaped: $domain_password_escaped)\n" .
"domain computer OU : " . ($computer_ou_dn ? $computer_ou_dn : '<not configured>')
);
# Perform preparation tasks
$self->ad_join_prepare() || return;
- # Assemble the PowerShell script
- my $ad_powershell_script;
- $ad_powershell_script .= "\$ps_credential = New-Object System.Management.Automation.PsCredential(\"$domain_user_string\", (ConvertTo-SecureString \"$domain_password\" -AsPlainText -Force))\n";
- $ad_powershell_script .= "Add-Computer -DomainName \"$domain_dns_name\" -Credential \$ps_credential $domain_computer_command_section -Verbose -ErrorAction Stop\n";
-
# Note: commented out because this isn't consistently working
# The rename occasionally fails with 'The directory service is busy.'
# Check if the computer needs to be renamed
@@ -13728,8 +13725,24 @@ sub ad_join {
#}
+ # Assemble the PowerShell script
+ my $ad_powershell_script = <<EOF;
+\$Host.UI.RawUI.BufferSize = New-Object Management.Automation.Host.Size(5000, 500)
+Clear-Host
+\$username = '$domain_user_string'
+\$password = '$domain_password_escaped'
+Write-Host "username (between >*<): `n>\$username<`n"
+Write-Host "password (between >*<): `n>\$password<`n"
+\$ps_credential = New-Object System.Management.Automation.PsCredential(\$username, (ConvertTo-SecureString \$password -AsPlainText -Force))
+Add-Computer -DomainName '$domain_dns_name' -Credential \$ps_credential $domain_computer_command_section -Verbose -ErrorAction Stop
+EOF
- notify($ERRORS{'DEBUG'}, 0, "PowerShell script contents:\n$ad_powershell_script");
+ notify($ERRORS{'DEBUG'}, 0, "attempting to join $computer_name to $domain_dns_name domain using PowerShell script:\n$ad_powershell_script");
+ my ($exit_status, $output) = $self->run_powershell_as_script($ad_powershell_script, 0, 0); # (path, show output, retain file)
+ if (!defined($output)) {
+ notify($ERRORS{'WARNING'}, 0, "failed to execute PowerShell script to join $computer_name to Active Directory domain");
+ return;
+ }
# Success:
# WARNING: The changes will take effect after you restart the computer
@@ -13737,7 +13750,7 @@ sub ad_join {
# Possible errors:
- # File C:\Users\Administrator\Desktop\ad_join.ps1 cannot be loaded because
+ # File C:\Users\Administrator\Desktop\ad_join_ps.ps1 cannot be loaded because
# the execution of scripts is disabled on this system. Please see "get-help
# about_signing" for more details.
@@ -13755,46 +13768,60 @@ sub ad_join {
# Add-Computer : This command cannot be executed on target
# computer('VCLV98-247') due to following error: The account already exists.
- my ($exit_status, $output) = $self->run_powershell_as_script($ad_powershell_script, 0, 1);
- if (!defined($output)) {
- notify($ERRORS{'WARNING'}, 0, "failed to execute PowerShell script to join $computer_name to Active Directory domain");
- return;
- }
-
- # Combine the output lines into a single string or else unpredictable text wrapping may occur
- my $output_string = join(' ', @$output);
- $output_string =~ s/\s+/ /g;
-
- if ($output_string =~ /(error:|does not exist|cannot be loaded)/i) {
- notify($ERRORS{'WARNING'}, 0, "failed to join $computer_name to Active Directory domain, output:\n$output_string");
+ my $reboot_after_join = 1;
+ if (grep(/(failed to join|error:|does not exist|cannot be loaded)/i, @$output)) {
+ notify($ERRORS{'WARNING'}, 0, "failed to join $computer_name to Active Directory domain, output:\n" . join("\n", @$output));
return 0;
}
+ elsif (grep(/already in that domain/i, @$output)) {
+ # Add-Computer : Cannot add computer '<hostname>' to domain '<domain DNS name>' because it is already in that domain.
+ notify($ERRORS{'OK'}, 0, "$computer_name is already joined to Active Directory domain, output:\n" . join("\n", @$output));
+ $reboot_after_join = 0;
+ }
else {
notify($ERRORS{'OK'}, 0, "executed PowerShell script to join $computer_name to Active Directory domain, output:\n" . join("\n", @$output));
}
-
- # Reboot, computer should be joined to AD with the correct hostname
- # If computer had to be rebooted to be renamed, certain tasks in reboot() don't need to be performed again
- # Set reboot()'s last $pre_configure flag accordingly
- my $ad_join_reboot_pre_configure = ($rename_computer_reboot_duration ? 0 : 1);
- my $ad_join_reboot_start = time;
- if (!$self->reboot(300, 3, 1, $ad_join_reboot_pre_configure)) {
- notify($ERRORS{'WARNING'}, 0, "failed to join $computer_name to Active Directory domain, failed to reboot computer after it joined the domain");
- return;
+ if ($reboot_after_join) {
+ # Reboot, computer should be joined to AD with the correct hostname
+ # If computer had to be rebooted to be renamed, certain tasks in reboot() don't need to be performed again
+ # Set reboot()'s last $pre_configure flag accordingly
+ my $ad_join_reboot_pre_configure = ($rename_computer_reboot_duration ? 0 : 1);
+
+ my $ad_join_reboot_start = time;
+ if (!$self->reboot(300, 3, 1, $ad_join_reboot_pre_configure)) {
+ notify($ERRORS{'WARNING'}, 0, "failed to join $computer_name to Active Directory domain, failed to reboot computer after it joined the domain");
+ return;
+ }
+ $ad_join_reboot_duration = (time - $ad_join_reboot_start);
+ }
+ else {
+ notify($ERRORS{'DEBUG'}, 0, "$computer_name does NOT need to be rebooted because it was already joined to the domain");
}
- $ad_join_reboot_duration = (time - $ad_join_reboot_start);
my $total_duration = (time - $start_time);
my $other_tasks_duration = ($total_duration - $rename_computer_reboot_duration - $ad_join_reboot_duration);
- notify($ERRORS{'DEBUG'}, 0, "successfully joined $computer_name to Active Directory domain: $domain_dns_name, time statistics:\n" .
- "computer rename reboot : $rename_computer_reboot_duration seconds\n" .
- "AD join reboot : $ad_join_reboot_duration seconds\n" .
- "other tasks : $other_tasks_duration seconds\n" .
- "total : $total_duration seconds"
- );
- return 1;
+ # Verify computer is now in the correct AD domain
+ my $current_domain = $self->ad_get_current_domain();
+ if (!$current_domain) {
+ notify($ERRORS{'WARNING'}, 0, "attempted to join $computer_name to $domain_dns_name domain but name of domain computer is currently joined to could not be retrieved, PowerShell script execution output:\n" . join("\n", @$output));
+ return;
+ }
+ elsif ($domain_dns_name !~ /^$current_domain/) {
+ notify($ERRORS{'WARNING'}, 0, "attempted to join $computer_name to $domain_dns_name domain but computer is currently joined to $current_domain domain, PowerShell script execution output:\n" . join("\n", @$output));
+ return;
+ }
+ else {
+ notify($ERRORS{'DEBUG'}, 0, "successfully joined $computer_name to Active Directory domain: $domain_dns_name, time statistics:\n" .
+ "computer rename reboot : $rename_computer_reboot_duration seconds\n" .
+ "AD join reboot : $ad_join_reboot_duration seconds\n" .
+ "other tasks : $other_tasks_duration seconds\n" .
+ "-------------------------------------\n" .
+ "total : $total_duration seconds"
+ );
+ return 1;
+ }
}
#//////////////////////////////////////////////////////////////////////////////
@@ -13940,7 +13967,7 @@ sub ad_join_wmic {
notify($ERRORS{'OK'}, 0, "joined $computer_name to Active Directory domain $domain_dns_name using wmic.exe");
}
elsif (my $error_message = $error_messages->{$join_return_value}) {
- notify($ERRORS{'WARNING'}, 0, "failed to join $computer_name to Active Directory domain $domain_dns_name using wmic.exe\nreason: $error_message\noutput:\n$join_output_string");
+ notify($ERRORS{'WARNING'}, 0, "failed to join $computer_name to Active Directory domain $domain_dns_name using wmic.exe, reason: $error_message\noutput:\n$join_output_string");
return;
}
else {
@@ -14091,7 +14118,7 @@ sub ad_unjoin {
#}
#EOF
#
- # my ($exit_status, $output) = $self->run_powershell_as_script($ad_powershell_script, 1, 1);
+ # my ($exit_status, $output) = $self->run_powershell_as_script($ad_powershell_script, 0, 0);
# if (!defined($output)) {
# notify($ERRORS{'WARNING'}, 0, "failed to execute PowerShell script to remove $computer_name from Active Directory domain");
# return;
@@ -14227,9 +14254,9 @@ sub ad_search {
my $domain_dns_name;
my $domain_username;
my $domain_password;
- if (defined($arguments->{domain_dns_name})) {
+ if (defined($arguments->{domain_dns_name}) && $arguments->{domain_dns_name} ne $self->data->get_image_domain_dns_name()) {
$domain_dns_name = $arguments->{domain_dns_name};
- ($domain_username, $domain_password) = get_active_directory_domain_credentials($domain_dns_name);
+ ($domain_username, $domain_password) = $self->data->get_domain_credentials($domain_dns_name);
if (!defined($domain_username) || !defined($domain_password)) {
notify($ERRORS{'WARNING'}, 0, "unable to search domain: $domain_dns_name, domain DNS name argument was specified but credentials could not be determined from existing 'addomain' table entries");
return;
@@ -14277,17 +14304,31 @@ sub ad_search {
$ldap_filter .= ')' if ($search_attribute_count > 1);
notify($ERRORS{'DEBUG'}, 0, "assembled LDAP filter: '$ldap_filter'");
+ my $domain_user_string = "$domain_username\@$domain_dns_name";
+
+ # Escape single quotes by doubling them
+ (my $domain_password_escaped = $domain_password) =~ s/(['])/$1$1/g;
+
+ my $delete = ($operation eq 'delete' ? 1 : 0);
# Assemble the PowerShell script
- my $powershell_script_contents = <<'EOF';
-$Host.UI.RawUI.BufferSize = New-Object Management.Automation.Host.Size(5000, 500)
+ my $powershell_script_contents = <<EOF;
+\$Host.UI.RawUI.BufferSize = New-Object Management.Automation.Host.Size(5000, 500)
+Clear-Host
+
+\$domain_dns_name = '$domain_dns_name'
+\$domain_username = '$domain_user_string'
+\$domain_password = '$domain_password_escaped'
+\$ldap_filter = '$ldap_filter'
+\$delete = '$delete'
+
+Write-Host "domain: $domain_dns_name"
+Write-Host "domain username (between >*<): >\$domain_username<"
+Write-Host "domain password (between >*<): >\$domain_password<"
-$domain_dns_name = '[domain_dns_name]'
-$domain_username = '[domain_username]@[domain_dns_name]'
-$domain_password = '[domain_password]'
-$ldap_filter = '[ldap_filter]'
-$delete = '[delete]'
+EOF
+ $powershell_script_contents .= <<'EOF';
$type = [System.DirectoryServices.ActiveDirectory.DirectoryContextType]"Domain"
$directory_context = New-Object System.DirectoryServices.ActiveDirectory.DirectoryContext($type, $domain_dns_name, $domain_username, $domain_password)
try {
@@ -14350,21 +14391,9 @@ ForEach($result in $results) {
}
EOF
- $powershell_script_contents =~ s/\[domain_dns_name\]/$domain_dns_name/g;
- $powershell_script_contents =~ s/\[domain_username\]/$domain_username/g;
- $powershell_script_contents =~ s/\[domain_password\]/$domain_password/g;
- $powershell_script_contents =~ s/\[ldap_filter\]/$ldap_filter/;
-
- if ($operation eq 'delete') {
- $powershell_script_contents =~ s/\[delete\]/1/g;
- }
- else {
- $powershell_script_contents =~ s/\[delete\]/0/g;
- }
-
my ($exit_status, $output);
for (my $attempt=1; $attempt<=$attempt_limit; $attempt++) {
- ($exit_status, $output) = $self->run_powershell_as_script($powershell_script_contents);
+ ($exit_status, $output) = $self->run_powershell_as_script($powershell_script_contents, 0, 0);
if (!defined($output)) {
notify($ERRORS{'WARNING'}, 0, "failed to execute PowerShell script on $computer_name to $operation objects in $domain_dns_name AD domain matching LDAP filter: '$ldap_filter'");
return;
@@ -14388,13 +14417,15 @@ EOF
my @matching_dns;
for my $line (@$output) {
+ next if ($line !~ /\w/);
+
# Remove leading and trailing spaces
$line =~ s/(^\s+|\s+$)//g;
if ($line =~ /^[A-Z]{2}=.+/i) {
push @matching_dns, $line;
}
- else {
- notify($ERRORS{'WARNING'}, 0, "unexpected output found $operation objects on $computer_name in $domain_dns_name AD domain matching LDAP filter: '$ldap_filter': '$line'");
+ elsif ($line !~ /^domain.*:/) {
+ notify($ERRORS{'WARNING'}, 0, "unexpected output found $operation objects on $computer_name in $domain_dns_name AD domain matching LDAP filter: '$ldap_filter':\n$line");
}
}
@@ -14474,7 +14505,7 @@ sub ad_search_computer {
return;
}
- my ($computer_samaccountname, $domain_dns_name) = @_;
+ my ($computer_samaccountname, $domain_dns_name, $ad_search_arguments) = @_;
$computer_samaccountname = $self->data->get_computer_short_name() unless $computer_samaccountname;
@@ -14482,12 +14513,8 @@ sub ad_search_computer {
# A dollar sign will be present if retrieved directly from AD
$computer_samaccountname =~ s/\$*$/\$/g;
- my $ad_search_arguments = {
- 'ldap_filter' => {
- 'objectClass' => 'computer',
- 'sAMAccountName' => $computer_samaccountname,
- }
- };
+ $ad_search_arguments->{ldap_filter}{objectClass} = 'computer';
+ $ad_search_arguments->{ldap_filter}{sAMAccountName} = $computer_samaccountname;
# If a specific domain was specified, retrieve the username and password for that domain
if ($domain_dns_name) {
Modified: vcl/trunk/managementnode/lib/VCL/utils.pm
URL: http://svn.apache.org/viewvc/vcl/trunk/managementnode/lib/VCL/utils.pm?rev=1797800&r1=1797799&r2=1797800&view=diff
==============================================================================
--- vcl/trunk/managementnode/lib/VCL/utils.pm (original)
+++ vcl/trunk/managementnode/lib/VCL/utils.pm Tue Jun 6 16:09:58 2017
@@ -118,7 +118,6 @@ our @EXPORT = qw(
format_data
format_hash_keys
format_number
- get_active_directory_domain_credentials
get_all_reservation_ids
get_affiliation_info
get_array_intersection
@@ -162,6 +161,7 @@ our @EXPORT = qw(
get_imagerevision_reservation_info
get_local_user_info
get_managable_resource_groups
+ get_management_node_ad_domain_credentials
get_management_node_blockrequests
get_management_node_computer_ids
get_management_node_id
@@ -8687,9 +8687,10 @@ sub get_calling_subroutine {
=head2 get_management_node_id
- Parameters :
- Returns :
- Description :
+ Parameters : none
+ Returns : integer
+ Description : Retrieves the managementnode.id value of the local management
+ node.
=cut
@@ -8698,7 +8699,6 @@ sub get_management_node_id {
# Check the management_node_id environment variable
if ($ENV{management_node_id}) {
- notify($ERRORS{'DEBUG'}, 0, "environment variable: $ENV{management_node_id}");
return $ENV{management_node_id};
}
else {
@@ -14603,61 +14603,6 @@ EOF
#//////////////////////////////////////////////////////////////////////////////
-=head2 get_active_directory_domain_credentials
-
- Parameters : $domain_dns_name, $no_cache (optional)
- Returns : ($username, $password)
- Description : Attempts to retrieve the username and password for the domain
- from the addomain table. This is used if a computer needs to be
- removed from a domain but the reservation image is not configured
- for Active Directory. When this occurs, the credentials are not
- available from $self->data.
-
-=cut
-
-sub get_active_directory_domain_credentials {
- my ($domain_dns_name, $no_cache) = @_;
- if (!$domain_dns_name) {
- notify($ERRORS{'WARNING'}, 0, "domain DNS name argument was not specified");
- return;
- }
-
- if (!$no_cache && defined($ENV{active_directory_domain_credentials}{$domain_dns_name})) {
- notify($ERRORS{'DEBUG'}, 0, "returning cached Active Directory credentials for $domain_dns_name domain");
- return @{$ENV{active_directory_domain_credentials}{$domain_dns_name}};
- }
-
- # Construct the select statement
- my $select_statement = <<EOF;
-SELECT DISTINCT
-username,
-password
-FROM
-addomain
-WHERE
-addomain.domainDNSName = '$domain_dns_name'
-EOF
-
- # Call the database select subroutine
- my @selected_rows = database_select($select_statement);
-
- # Check to make sure 1 row was returned
- if (scalar @selected_rows == 0) {
- notify($ERRORS{'DEBUG'}, 0, "Active Directory domain does not exist in the database: $domain_dns_name");
- return ();
- }
-
- # Get the single row returned from the select statement
- my $row = $selected_rows[0];
- my $username = $row->{username};
- my $password = $row->{password};
- notify($ERRORS{'DEBUG'}, 0, "retrieved credentials for $domain_dns_name domain from database, username: '$username', password: '$password'");
- $ENV{active_directory_domain_credentials}{$domain_dns_name} = [$username, $password];
- return @{$ENV{active_directory_domain_credentials}{$domain_dns_name}};
-}
-
-#//////////////////////////////////////////////////////////////////////////////
-
=head2 get_collapsed_hash_reference
Parameters : $hash_reference
@@ -15090,6 +15035,80 @@ EOF
}
#//////////////////////////////////////////////////////////////////////////////
+
+=head2 get_management_node_ad_domain_credentials
+
+ Parameters : $management_node_id, $domain_dns_name, $no_cache (optional)
+ Returns : ($username, $secret_id, $encrypted_password)
+ Description : Attempts to retrieve the username, encrypted password, and secret
+ ID for the domain from the addomain table. This is used if a
+ computer needs to be removed from a domain but the reservation
+ image is not configured for Active Directory. When this occurs,
+ the credentials are not available from $self->data.
+
+=cut
+
+sub get_management_node_ad_domain_credentials {
+ my ($management_node_id, $domain_identifier, $no_cache) = @_;
+ if (!defined($management_node_id)) {
+ notify($ERRORS{'WARNING'}, 0, "management node ID argument was not supplied");
+ return;
+ }
+ elsif (!$domain_identifier) {
+ notify($ERRORS{'WARNING'}, 0, "domain identifier name argument was not specified");
+ return;
+ }
+
+ if (!$no_cache && defined($ENV{management_node_ad_domain_credentials}{$domain_identifier})) {
+ notify($ERRORS{'DEBUG'}, 0, "returning cached Active Directory credentials for domain: $domain_identifier");
+ return @{$ENV{management_node_ad_domain_credentials}{$domain_identifier}};
+ }
+
+ # Construct the select statement
+ my $select_statement = <<EOF;
+SELECT DISTINCT
+username,
+password,
+secretid
+FROM
+addomain
+WHERE
+EOF
+
+ if ($domain_identifier =~ /^\d+$/) {
+ $select_statement .= "addomain.id = $domain_identifier";
+ }
+ else {
+ $select_statement .= "addomain.domainDNSName LIKE '$domain_identifier%'";
+ }
+
+ # Call the database select subroutine
+ my @selected_rows = database_select($select_statement);
+
+ # Check to make sure 1 row was returned
+ if (scalar @selected_rows == 0) {
+ notify($ERRORS{'DEBUG'}, 0, "Active Directory domain does not exist in the database: $domain_identifier");
+ return ();
+ }
+
+ # Get the single row returned from the select statement
+ my $row = $selected_rows[0];
+ my $username = $row->{username};
+ my $secret_id = $row->{secretid};
+ my $encrypted_password = $row->{password};
+
+
+
+ notify($ERRORS{'DEBUG'}, 0, "retrieved credentials for domain: $domain_identifier\n" .
+ "username : '$username'\n" .
+ "secret ID : '$secret_id'\n" .
+ "encrypted password : '$encrypted_password'"
+ );
+ $ENV{management_node_ad_domain_credentials}{$domain_identifier} = [$username, $secret_id, $encrypted_password];
+ return @{$ENV{management_node_ad_domain_credentials}{$domain_identifier}};
+}
+
+#//////////////////////////////////////////////////////////////////////////////
=head2 delete_management_node_cryptsecret