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 2010/09/14 21:15:55 UTC

svn commit: r997046 - in /incubator/vcl/trunk/managementnode/lib/VCL: Module.pm utils.pm

Author: arkurth
Date: Tue Sep 14 19:15:54 2010
New Revision: 997046

URL: http://svn.apache.org/viewvc?rev=997046&view=rev
Log:
VCL-164
Added setup() and setup_add_local_account() to Module.pm to allow local accounts to be added via 'vcld -setup'.  Updated utils.pm::get_user_info() to accept an optional affiliation identifier argument because.  The user.unityid column is not unique, but user.unityid+user.affiliationid must be unique.  This argument allows the affiliation to be specified so that a single user is found even if the same unityid is used for different affiliations.

Other
Changed utils.pm::format_data to use Data::Dumper.  The old subroutine was very difficult to debug/maintain and Data::Dumper performs the same function.

Removed progressive delay in between failed SSH attempts in utils.pm::run_ssh_command.  The progressive delay never added any benefit, but delayed a process before it failed.

Modified:
    incubator/vcl/trunk/managementnode/lib/VCL/Module.pm
    incubator/vcl/trunk/managementnode/lib/VCL/utils.pm

Modified: incubator/vcl/trunk/managementnode/lib/VCL/Module.pm
URL: http://svn.apache.org/viewvc/incubator/vcl/trunk/managementnode/lib/VCL/Module.pm?rev=997046&r1=997045&r2=997046&view=diff
==============================================================================
--- incubator/vcl/trunk/managementnode/lib/VCL/Module.pm (original)
+++ incubator/vcl/trunk/managementnode/lib/VCL/Module.pm Tue Sep 14 19:15:54 2010
@@ -83,8 +83,9 @@ use strict;
 use warnings;
 use diagnostics;
 use English '-no_match_vars';
+use Digest::SHA1 qw(sha1_hex);
 
-use VCL::utils qw($SETUP_MODE $VERBOSE %ERRORS &notify &getnewdbh format_data);
+use VCL::utils;
 use VCL::DataStructure;
 use VCL::Module::Semaphore;
 
@@ -499,6 +500,176 @@ sub get_semaphore {
 
 #/////////////////////////////////////////////////////////////////////////////
 
+=head2 setup
+
+ Parameters  : none
+ Returns     : 
+ Description : This subroutine is used when vcld is run in setup mode. It
+               presents a menu for overall VCL configuration settings.
+
+=cut
+
+sub setup {
+	my $self = shift;
+	unless (ref($self) && $self->isa('VCL::Module')) {
+		notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
+		return;
+	}
+	
+	push @{$ENV{setup_path}}, 'User Accounts';
+	
+	my @operation_choices = (
+		'Add Local VCL User Account',
+	);
+	
+	my @setup_path = @{$ENV{setup_path}};
+	OPERATION: while (1) {
+		@{$ENV{setup_path}} = @setup_path;
+		
+		print '-' x 76 . "\n";
+		
+		print "Choose an operation:\n";
+		my $operation_choice_index = setup_get_array_choice(@operation_choices);
+		last if (!defined($operation_choice_index));
+		my $operation_name = $operation_choices[$operation_choice_index];
+		print "\n";
+		
+		push @{$ENV{setup_path}}, $operation_name;
+		
+		if ($operation_name =~ /add local/i) {
+			$self->setup_add_local_account();
+		}
+	}
+	
+	pop @{$ENV{setup_path}};
+	return 1;
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 setup_add_local_account
+
+ Parameters  : none
+ Returns     : boolean
+ Description : Presents an interface to create a local VCL user account. This
+               subroutine is executed when vcld is run with the -setup argument.
+
+=cut
+
+sub setup_add_local_account {
+	my $self = shift;
+	unless (ref($self) && $self->isa('VCL::Module')) {
+		notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
+		return;
+	}
+	
+	#myusername', 'myfirstname', 'mylastname', 'myemailaddr',
+	
+	# Get the username (user.unityid)
+	my $username;
+	while (!$username) {
+		$username = setup_get_input_string("Enter the user login name");
+		return if (!defined($username));
+		
+		# Check format of username
+		if ($username !~ /^[\w\-_]+$/i) {
+			print "User name is not valid: '$username'\n\n";
+			$username = undef;
+		}
+		
+		# Make sure username does not already exist
+		my $user_info = get_user_info($username, 'Local');
+		if ($user_info && $user_info->{unityid} eq $username) {
+			print "Local VCL user account already exists: $username\n\n";
+			$username = undef;
+		}
+	}
+	print "\n";
+	
+	# Get the other required information
+	my $first_name;
+	while (!$first_name) {
+		$first_name = setup_get_input_string("Enter the first name");
+		return if (!defined($first_name));
+	}
+	print "\n";
+	
+	my $last_name;
+	while (!$last_name) {
+		$last_name = setup_get_input_string("Enter the last name");
+		return if (!defined($last_name));
+	}
+	print "\n";
+	
+	my $email_address;
+	while (!defined($email_address)) {
+		$email_address = setup_get_input_string("Enter the email address", 'not set');
+		return if (!defined($email_address));
+		
+		# Check format of the email address
+		if ($email_address eq 'not set') {
+			$email_address = '';
+		}
+		elsif ($email_address !~ /^([A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}(,?))+$/i) {
+			print "Email address is not valid: '$email_address'\n\n";
+			$email_address = undef;
+		}
+	}
+	print "\n";
+	
+	my $password;
+	while (!$password) {
+		$password = setup_get_input_string("Enter the password");
+		return if (!defined($password));
+	}
+	print "\n";
+	
+	# Generate an 8-character random string
+	my @characters = ("a" .. "z", "A" .. "Z", "0" .. "9");
+	my $random_string;
+	srand;
+	for (1 .. 8) {
+		$random_string .= $characters[rand((scalar(@characters) - 1))];
+	}
+	
+	# Get an SHA1 hex digest from the password and random string
+	my $digest = sha1_hex("$password$random_string");
+	
+	# Insert a row into the user table
+	my $insert_user_statement = <<EOF;
+INSERT INTO user
+(unityid, affiliationid, firstname, lastname, email, lastupdated)
+VALUES
+('$username', (SELECT id FROM affiliation WHERE name LIKE 'Local'), '$first_name', '$last_name', '$email_address', NOW())
+EOF
+	
+	my $user_id = database_execute($insert_user_statement);
+	if (!defined($user_id)) {
+		print "ERROR: failed to insert into user table\n";
+		return;
+	}
+	
+	# Insert a row into the localauth table
+	my $insert_localauth_statement = <<EOF;
+INSERT INTO localauth
+(userid, passhash, salt, lastupdated)
+VALUES
+($user_id, '$digest', '$random_string', NOW())
+EOF
+	
+	my $localauth_id = database_execute($insert_localauth_statement);
+	if (!defined($localauth_id)) {
+		print "ERROR: failed to insert into localauth table\n";
+		return;
+	}
+	
+	print "Local VCL user account successfully created: $username\n";
+	
+	return 1;
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
 1;
 __END__
 

Modified: incubator/vcl/trunk/managementnode/lib/VCL/utils.pm
URL: http://svn.apache.org/viewvc/incubator/vcl/trunk/managementnode/lib/VCL/utils.pm?rev=997046&r1=997045&r2=997046&view=diff
==============================================================================
--- incubator/vcl/trunk/managementnode/lib/VCL/utils.pm (original)
+++ incubator/vcl/trunk/managementnode/lib/VCL/utils.pm Tue Sep 14 19:15:54 2010
@@ -70,6 +70,7 @@ use List::Util qw(min max);
 use HTTP::Headers;
 use RPC::XML::Client;
 use Scalar::Util 'blessed';
+use Data::Dumper;
 
 #use Date::Calc qw(Delta_DHMS Time_to_Date Date_to_Time);
 
@@ -5422,16 +5423,9 @@ sub run_ssh_command {
 		
 		# Delay performing next attempt if this isn't the first attempt
 		if ($attempts > 1) {
-			my $delay;
-			if ($attempts == 2) {
-				$delay = 2;
-			}
-			else {
-				# Progressively increase the delay
-				$delay = (5 * $attempts);
-			}
-			notify($ERRORS{'DEBUG'}, 0, "sleeping for $delay seconds before making next SSH attempt") if $output_level;
-			sleep $delay;
+			my $delay_seconds = 2;
+			notify($ERRORS{'DEBUG'}, 0, "sleeping for $delay_seconds seconds before making next SSH attempt") if $output_level;
+			sleep $delay_seconds;
 		}
 
 		## Add -v (verbose) argument to command if this is the 2nd attempt
@@ -7918,7 +7912,7 @@ sub get_computer_grp_members {
 
 =head2 get_user_info
 
- Parameters  : $user_identifier
+ Parameters  : $user_identifier, $affiliation_identifier (optional)
  Returns     : hash reference
  Description : Retrieves user information from the database. The user identifier
                argument can either be a user ID or unityid. A hash reference is
@@ -7961,13 +7955,13 @@ sub get_computer_grp_members {
 =cut
 
 sub get_user_info {
-   my ($user_identifier) = @_;
+	my ($user_identifier, $affiliation_identifier) = @_;
 	if (!defined($user_identifier)) {
 		notify($ERRORS{'WARNING'}, 0, "user identifier argument was not specified");
 		return;
 	}
-
-   my $select_statement = <<EOF;
+	
+	my $select_statement = <<EOF;
 SELECT DISTINCT
 user.*,
 adminlevel.name AS adminlevel_name,
@@ -7985,13 +7979,25 @@ LEFT JOIN (affiliation) ON (affiliation.
 LEFT JOIN (IMtype) ON (IMtype.id = user.IMtypeid)
 WHERE
 EOF
-
+	
+	# If the user identifier is all digits match it to user.id
+	# Otherwise, match user.unityid
 	if ($user_identifier =~ /^\d+$/) {
 		$select_statement .= "user.id = $user_identifier";
 	}
 	else {
 		$select_statement .= "user.unityid = '$user_identifier'";
 	}
+	
+	# If the affiliation identifier argument was specified add affiliation table clause
+	if (defined($affiliation_identifier)) {
+		if ($affiliation_identifier =~ /^\d+$/) {
+			$select_statement .= "\nAND affiliation.id = $affiliation_identifier";
+		}
+		else {
+			$select_statement .= "\nAND affiliation.name LIKE '$affiliation_identifier'";
+		}
+	}
 
 	# Call the database select subroutine
 	# This will return an array of one or more rows based on the select statement
@@ -8631,98 +8637,29 @@ sub update_cluster_info {
 
 =head2 format_data
 
- Parameters  :
- Returns     : 0 or 1
- Description :
+ Parameters  : $data
+ Returns     : string
+ Description : Formats the data argument using Data::Dumper.
 
 =cut
 
 sub format_data {
+	my @data = @_;
 	
-	my $return_string;
-
-	my $level = 0;
-	$level = $_[scalar(@_) - 2] if (scalar(@_) > 2 && !ref($_[scalar(@_) - 2]));
-
-	my $name = '';
-	$name = $_[scalar(@_) - 1] if (scalar(@_) > 1 && !ref($_[scalar(@_) - 1]));
-
-	my $type;
-	my $data;
-
-	if (ref($_[0]) eq "HASH" || (blessed($_[0]) && $_[0]->isa("HASH"))) {
-		$data = $_[0];
-		$type = '%';
-		return "%<empty>" if (keys(%{$_[0]}) == 0);
+	if (!(@data)) {
+		return '<undefined>';
 	}
-	elsif (ref($_[0]) eq "ARRAY" || (blessed($_[0]) && $_[0]->isa("ARRAY"))) {
-		my $index = 0;
-		for (@{$_[0]}) {
-			$data->{$index} = $_;
-			$index++;
-		}
-		$type = '@';
-		return "@<empty>" if (@{$_[0]} == 0);
-	}
-	elsif (ref($_[0]) eq "SCALAR") {
-		$data = $_[0];
-		$type = '$';
-	}
-	else {
-		$data = \$_[0];
-		$type = '$';
-
-		$return_string .= "ref: " . ref($_[0]) . "\n";
-		$return_string .= "data: " . $_[0] . "\n";
-
-		return $return_string;
-	}
-
-	$data = 'NULL' if (!defined $data);
-
-	$return_string .= "$type$name\n";
-
-	# Loop through values
-	foreach my $key (sort {lc($a) cmp lc($b)} keys(%{$data})) {
-		my $value = $data->{$key};
-
-		$value = 'NULL' if (!defined $value);
-
-		for (my $count = 0; $count < $level; $count++) {
-			$return_string .= "..." if ($count < $level);
-		}
-		$return_string .= "|--";
-
-		if (ref($value) eq 'SCALAR') {
-			$value = "\\'$$value'";
-		}
-		elsif (!ref($value) && $value ne 'NULL') {
-			$value = "'$value'";
-		}
-
-		if (!ref($value)) {
-			if ($type eq '@') {
-				$return_string .= "[$key] = $value\n";
-			}
-			elsif ($type eq '%') {
-				$return_string .= "[$name]{$key} = $value\n";
-			}
-		}
-		else {
-			if ($type eq '@') {
-				#$return_string .= "\[$key\]\n";
-				$return_string .= format_data($value, $level + 1, "$name\[$key\]");
-			}
-			elsif ($type eq '%') {
-				#$return_string .= "\{$key\} $name\n";
-				$return_string .= format_data($value, $level + 1, "$name\{$key\}");
-			}
-		} ## end else [ if (!ref($value))
-
-	} ## end foreach my $key (sort {lc($a) cmp lc($b)} keys(...
-
-	return $return_string;
-} ## end sub format_data
+	
+	$Data::Dumper::Indent    = 1;
+	$Data::Dumper::Purity    = 1;
+	$Data::Dumper::Useqq     = 1;      # Use double quotes for representing string values
+	$Data::Dumper::Terse     = 1;
+	$Data::Dumper::Quotekeys = 1;      # Quote hash keys
+	$Data::Dumper::Pair      = ' => '; # Specifies the separator between hash keys and values
+	$Data::Dumper::Sortkeys  = 1;      # Hash keys are dumped in sorted order
+	
+	return Dumper(@data);
+}
 
 #/////////////////////////////////////////////////////////////////////////////