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 2011/10/06 22:53:09 UTC
svn commit: r1179847 - in
/incubator/vcl/trunk/managementnode/lib/VCL/Module: OS.pm OS/Linux.pm
OS/Windows.pm
Author: arkurth
Date: Thu Oct 6 20:53:08 2011
New Revision: 1179847
URL: http://svn.apache.org/viewvc?rev=1179847&view=rev
Log:
VCL-523
Improved Windows code which retrieves services configured to run as a particular user. It was very slow. The service information is now exported from the registry into a text file and parsed. This is faster than running 'reg.exe query' since the services section is very large. Moved get_file_contents from Linux.pm to OS.pm since it can also be used by the Windows code.
Modified:
incubator/vcl/trunk/managementnode/lib/VCL/Module/OS.pm
incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Linux.pm
incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Windows.pm
Modified: incubator/vcl/trunk/managementnode/lib/VCL/Module/OS.pm
URL: http://svn.apache.org/viewvc/incubator/vcl/trunk/managementnode/lib/VCL/Module/OS.pm?rev=1179847&r1=1179846&r2=1179847&view=diff
==============================================================================
--- incubator/vcl/trunk/managementnode/lib/VCL/Module/OS.pm (original)
+++ incubator/vcl/trunk/managementnode/lib/VCL/Module/OS.pm Thu Oct 6 20:53:08 2011
@@ -1570,6 +1570,52 @@ sub create_text_file {
#/////////////////////////////////////////////////////////////////////////////
+=head2 get_file_contents
+
+ Parameters : $file_path
+ Returns : array
+ Description : Returns an array containing the contents of the file specified by
+ the file path argument. Each array element contains a line from
+ the file.
+
+=cut
+
+sub get_file_contents {
+ my $self = shift;
+ if (ref($self) !~ /module/i) {
+ notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
+ return;
+ }
+
+ # Get the path argument
+ my $path = shift;
+ if (!$path) {
+ notify($ERRORS{'WARNING'}, 0, "path argument was not specified");
+ return;
+ }
+
+ my $computer_short_name = $self->data->get_computer_short_name();
+
+ # Run cat to retrieve the contents of the file
+ my $command = "cat \"$path\"";
+ my ($exit_status, $output) = $self->execute($command);
+ if (!defined($output)) {
+ notify($ERRORS{'WARNING'}, 0, "failed to run command to read file on $computer_short_name:\n path: '$path'\ncommand: '$command'");
+ return;
+ }
+ elsif (grep(/^cat: /, @$output)) {
+ notify($ERRORS{'WARNING'}, 0, "failed to read contents of file on $computer_short_name: '$path', exit status: $exit_status, output:\n" . join("\n", @$output));
+ return;
+ }
+ else {
+ notify($ERRORS{'DEBUG'}, 0, "retrieved " . scalar(@$output) . " lines from file on $computer_short_name: '$path'");
+ map { s/[\r\n]+$//g; } (@$output);
+ return @$output;
+ }
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
=head2 execute
Parameters : $command, $display_output (optional)
@@ -1850,7 +1896,7 @@ sub manage_server_access {
notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
return;
}
-
+
my $computer_node_name = $self->data->get_computer_node_name() || return;
my $reservation_id = $self->data->get_reservation_id();
my $server_request_id = $self->data->get_server_request_id();
Modified: incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Linux.pm
URL: http://svn.apache.org/viewvc/incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Linux.pm?rev=1179847&r1=1179846&r2=1179847&view=diff
==============================================================================
--- incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Linux.pm (original)
+++ incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Linux.pm Thu Oct 6 20:53:08 2011
@@ -1558,51 +1558,6 @@ sub move_file {
#/////////////////////////////////////////////////////////////////////////////
-=head2 get_file_contents
-
- Parameters : $file_path
- Returns : array
- Description : Returns an array containing the contents of the file specified by
- the file path argument. Each array element contains a line from
- the file.
-
-=cut
-
-sub get_file_contents {
- my $self = shift;
- if (ref($self) !~ /module/i) {
- notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
- return;
- }
-
- # Get the path argument
- my $path = shift;
- if (!$path) {
- notify($ERRORS{'WARNING'}, 0, "path argument was not specified");
- return;
- }
-
- my $computer_short_name = $self->data->get_computer_short_name();
-
- # Run cat to retrieve the contents of the file
- my $command = "cat \"$path\"";
- my ($exit_status, $output) = $self->execute($command);
- if (!defined($output)) {
- notify($ERRORS{'WARNING'}, 0, "failed to run command to read file on $computer_short_name:\n path: '$path'\ncommand: '$command'");
- return;
- }
- elsif (grep(/^cat: /, @$output)) {
- notify($ERRORS{'WARNING'}, 0, "failed to read contents of file on $computer_short_name: '$path', exit status: $exit_status, output:\n" . join("\n", @$output));
- return;
- }
- else {
- notify($ERRORS{'DEBUG'}, 0, "retrieved " . scalar(@$output) . " lines from file on $computer_short_name: '$path'");
- return @$output;
- }
-}
-
-#/////////////////////////////////////////////////////////////////////////////
-
=head2 get_available_space
Parameters : $path
Modified: incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Windows.pm
URL: http://svn.apache.org/viewvc/incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Windows.pm?rev=1179847&r1=1179846&r2=1179847&view=diff
==============================================================================
--- incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Windows.pm (original)
+++ incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Windows.pm Thu Oct 6 20:53:08 2011
@@ -2444,6 +2444,9 @@ sub reg_query {
$command .= "/v \"$value_argument_escaped\"";
}
+ # Ignore error lines, it will throw off parsing
+ $command .= " 2>/dev/null";
+
# Run reg.exe QUERY
my ($exit_status, $output) = run_ssh_command($computer_node_name, $management_node_keys, $command, '', '', 0);
if (!defined($output)) {
@@ -2498,6 +2501,11 @@ sub reg_query {
$type =~ s/(^\s+|\s+$)//g;
$data =~ s/(^\s+|\s+$)//g;
+ if ($type =~ /binary/i) {
+ #notify($ERRORS{'DEBUG'}, 0, "ignoring $type data, key: $key, value: $value");
+ next;
+ }
+
$value = '(Default)' if $value =~ /NO NAME/;
$data = $self->reg_query_convert_data($type, $data);
@@ -2570,6 +2578,12 @@ sub reg_query_convert_data {
}
if ($type eq 'REG_DWORD') {
+ # Make sure a valid hex value was returned
+ if ($data !~ /^0x[a-fA-F0-9]+$/) {
+ notify($ERRORS{'WARNING'}, 0, "invalid $type value: '$data'");
+ return;
+ }
+
# Convert the hex value to decimal
$data = hex($data);
}
@@ -2804,13 +2818,13 @@ sub reg_export {
notify($ERRORS{'WARNING'}, 0, "registry file path was not passed correctly as an argument");
return;
}
- $registry_file_path = $self->format_path_unix($registry_file_path);
+ $registry_file_path = $self->format_path_dos($registry_file_path);
- # Escape backslashes in the root key
- $root_key =~ s/\\+/\\\\/;
+ # Replace forward slashes with backslashes in registry key
+ $root_key =~ s/\//\\\\/g;
# Run reg.exe EXPORT
- my $command .= $system32_path . "/reg.exe EXPORT $root_key $registry_file_path /y";
+ my $command .= "cmd.exe /c \"$system32_path/reg.exe EXPORT $root_key $registry_file_path.tmp /y && type $registry_file_path.tmp > $registry_file_path\"";
my ($exit_status, $output) = run_ssh_command($computer_node_name, $management_node_keys, $command, '', '', 1);
if (!defined($output)) {
notify($ERRORS{'WARNING'}, 0, "failed to run SSH command to export registry key $root_key to file: $registry_file_path");
@@ -3830,53 +3844,7 @@ sub set_service_credentials {
#/////////////////////////////////////////////////////////////////////////////
-=head2 get_service_list
-
- Parameters : none
- Returns : array
- Description : Retrieves the names of the services installed on the computer.
-
-=cut
-
-sub get_service_list {
- 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");
- return;
- }
-
- my $computer_node_name = $self->data->get_computer_node_name();
- my $system32_path = $self->get_system32_path() || return;
-
- # Call sc query
- my $sc_query_command = $system32_path . "/sc.exe query";
- my ($sc_query_exit_status, $sc_query_output) = $self->execute($sc_query_command);
- if (defined($sc_query_exit_status) && $sc_query_exit_status == 0) {
- #notify($ERRORS{'OK'}, 0, "retrieved service list on $computer_node_name:\n" . join("\n", @$sc_query_output));
- }
- elsif (defined($sc_query_exit_status)) {
- notify($ERRORS{'WARNING'}, 0, "failed to retrieve service list from $computer_node_name, exit status: $sc_query_exit_status, output:\n@{$sc_query_output}");
- return 0;
- }
- else {
- notify($ERRORS{'WARNING'}, 0, "failed to run ssh command to failed to retrieve service list from $computer_node_name");
- return;
- }
-
- my @service_names;
- for my $line (@$sc_query_output) {
- if ($line =~ /SERVICE_NAME: (.*)/) {
- push @service_names, $1;
- }
- }
-
- notify($ERRORS{'DEBUG'}, 0, "found " . scalar(@service_names) . " services on $computer_node_name");
- return @service_names;
-} ## end sub get_service_list
-
-#/////////////////////////////////////////////////////////////////////////////
-
-=head2 get_service_info
+=head2 get_service_configuration
Parameters : none
Returns : hash reference
@@ -3884,61 +3852,51 @@ sub get_service_list {
reference is returned. The hash keys are service names.
Example:
"sshd" => {
- "BINARY_PATH_NAME" => "C:\\cygwin\\bin\\cygrunsrv.exe",
- "DEPENDENCIES" => "tcpip",
- "DISPLAY_NAME" => "CYGWIN sshd",
- "ERROR_CONTROL" => "1 NORMAL",
- "LOAD_ORDER_GROUP" => "",
- "SERVICE_NAME" => "sshd",
"SERVICE_START_NAME" => ".\\root",
- "START_TYPE" => "2 AUTO_START",
- "TAG" => 0,
- "TYPE" => "10 WIN32_OWN_PROCESS "
},
=cut
-sub get_service_info {
+sub get_service_configuration {
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");
return;
}
- return $self->{service_info} if $self->{service_info};
+ return $self->{service_configuration} if $self->{service_configuration};
my $computer_node_name = $self->data->get_computer_node_name();
- my $system32_path = $self->get_system32_path() || return;
- my @service_list = $self->get_service_list();
+ notify($ERRORS{'DEBUG'}, 0, "retrieving service configuration information from the registry");
+ my $services_key = 'HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services';
+ my $node_reg_file_path = "\$TMP/services_$computer_node_name.reg";
+ if (!$self->reg_export($services_key, $node_reg_file_path)) {
+ notify($ERRORS{'WARNING'}, 0, "failed to retrieve service credential information from the registry on $computer_node_name");
+ return;
+ }
- my $service_info;
- for my $service (@service_list) {
- # Call sc query
- my $command = "$system32_path/sc.exe qc \"$service\"";
- my ($exit_status, $output) = $self->execute($command);
- if (defined($exit_status) && $exit_status == 0) {
- #notify($ERRORS{'DEBUG'}, 0, "retrieved '$service' service info:\n" . join("\n", @$output));
-
- for my $line (@$output) {
- if (my ($property, $value) = $line =~ /^[\s\t]*(\w+)[\s\t]*:[\s\t]*(.*)/g) {
- $service_info->{$service}{$property} = $value;
- }
- }
- }
- elsif (defined($exit_status)) {
- notify($ERRORS{'WARNING'}, 0, "failed to retrieve '$service' service info from $computer_node_name, exit status: $exit_status, output:\n" . join("\n", @$output));
- next SERVICE;
+ my @reg_file_contents = $self->get_file_contents($node_reg_file_path);
+ if (!@reg_file_contents) {
+ notify($ERRORS{'WARNING'}, 0, "failed to retrieve contents of file on $computer_node_name containing exported service credential information from the registry: $node_reg_file_path");
+ return;
+ }
+
+ my $service_configuration;
+ my $service_name;
+ for my $line (@reg_file_contents) {
+ if ($line =~ /Services\\([^\\]+)\]$/i) {
+ $service_name = $1;
+ $service_configuration->{$service_name} = {};
}
- else {
- notify($ERRORS{'WARNING'}, 0, "failed to run command to retrieve '$service' service info from $computer_node_name");
- next SERVICE;
+ elsif ($line =~ /"ObjectName"="(.+)"/i) {
+ my $object_name = $1;
+ $service_configuration->{$service_name}{SERVICE_START_NAME} = $object_name;
}
}
- $self->{service_info} = $service_info;
- #notify($ERRORS{'DEBUG'}, 0, "retrieved service info:\n" . format_data($service_info));
- return $service_info;
+ $self->{service_configuration} = $service_configuration;
+ return $self->{service_configuration};
}
#/////////////////////////////////////////////////////////////////////////////
@@ -3969,23 +3927,23 @@ sub get_services_using_login_id {
return;
}
- # Get infor for all the services installed on the computer
- my $service_info = $self->get_service_info() || return;
+ # Get configuration for all the services installed on the computer
+ my $service_configuration = $self->get_service_configuration();
my @matching_service_names;
- for my $service_name (sort keys %$service_info) {
- my $service_start_name = $service_info->{$service_name}{SERVICE_START_NAME};
+ for my $service_name (sort keys %$service_configuration) {
+ my $service_start_name = $service_configuration->{$service_name}{SERVICE_START_NAME};
# The service start name may be in any of the following forms:
# LocalSystem
# NT AUTHORITY\LocalService
# .\root
- if ($service_start_name && $service_start_name =~ /^((NT AUTHORITY|\.)\\)?$login_id$/i) {
+ if ($service_start_name && $service_start_name =~ /^((NT AUTHORITY|\.)\\+)?$login_id$/i) {
push @matching_service_names, $service_name;
}
}
-
- notify($ERRORS{'DEBUG'}, 0, "found " . scalar(@matching_service_names) . " services using login ID '$login_id': " . join(", ", @matching_service_names));
+
+ notify($ERRORS{'DEBUG'}, 0, "services found using login ID '$login_id' (" . scalar(@matching_service_names) . "): " . join(", ", @matching_service_names));
return @matching_service_names;
} ## end sub get_services_using_login_id