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/08/04 16:11:02 UTC
svn commit: r982258 - in /incubator/vcl/trunk/managementnode/lib/VCL:
Module/OS.pm Module/OS/Linux.pm Module/Provisioning/VMware/VMware.pm utils.pm
Author: arkurth
Date: Wed Aug 4 14:11:02 2010
New Revision: 982258
URL: http://svn.apache.org/viewvc?rev=982258&view=rev
Log:
VCL-363
Removed the code from Linux.pm::changepasswd so that it does not recreate /etc/shadow. Removed utils.pm::changelinuxpassword because it is no longer being called.
VCL-49
Removed the commented-out section from utils.pm::reservation_being_processed that called pgrep to check if a process was already running for the reservation. Replaced this with a call to utils.pm::is_management_node_process_running. Updated is_management_node_process_running. It was not parsing the pgrep arguments correctly.
VCL-298
Added code to VMware.pm to check the image.project value and add additional network interfaces if the project is not 'vcl'. It gets a list of all the networks available on the VM host and adds an adapter for any that match up with the image project name. Added Linux.pm::activate_interfaces which finds and activates network interfaces which don't have a corresponding ifcfg-eth* file. The file is created and the interface is brought up allowing interfaces to be added dynamically during load. This is called by Linux.pm::post_load.
Fixed a bug in VMware.pm::get_active_vmx_file_path. It wasn't working correcly when run during an image capture when a new image was created with a different ID.
VCL-100
Added get_network_configuration, get_private_mac_address, get_public_mac_address, and get_public_ip_address to Linux.pm. Added get_private_interface_name and get_public_interface_name to OS.pm. These subroutines make the Linux code more inline with the Windows code and will allow the utils.pm::getdynamicaddress to be removed.
Fixed a bug in Linux.pm::execute. It was using the computer host name rather than the node name. This caused SSH commands to fail because it was attempting to connect to a full DNS host name configured in the computer table which didn't resolve.
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/Provisioning/VMware/VMware.pm
incubator/vcl/trunk/managementnode/lib/VCL/utils.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=982258&r1=982257&r2=982258&view=diff
==============================================================================
--- incubator/vcl/trunk/managementnode/lib/VCL/Module/OS.pm (original)
+++ incubator/vcl/trunk/managementnode/lib/VCL/Module/OS.pm Wed Aug 4 14:11:02 2010
@@ -782,6 +782,153 @@ sub set_vcld_post_load_status {
return 1;
}
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 get_private_interface_name
+
+ Parameters : none
+ Returns : string
+ Description : Determines the private interface name based on the information in
+ the network configuration hash returned by
+ get_network_configuration. The interface which is assigned the
+ private IP address for the reservation computer is returned.
+
+=cut
+
+sub get_private_interface_name {
+ my $self = shift;
+ if (ref($self) !~ /VCL::Module/i) {
+ notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
+ return;
+ }
+
+ # Get the network configuration hash reference
+ my $network_configuration = $self->get_network_configuration();
+ if (!$network_configuration) {
+ notify($ERRORS{'WARNING'}, 0, "unable to determine private interface name, failed to retrieve network configuration");
+ return;
+ }
+
+ # Get the computer private IP address
+ my $computer_private_ip_address = $self->data->get_computer_private_ip_address();
+ if (!$computer_private_ip_address) {
+ notify($ERRORS{'DEBUG'}, 0, "unable to retrieve computer private IP address from reservation data");
+ return;
+ }
+
+ # Loop through all of the network interfaces found
+ foreach my $interface_name (sort keys %$network_configuration) {
+ # Get the interface IP addresses and make sure an IP address was found
+ my @ip_addresses = keys %{$network_configuration->{$interface_name}{ip_address}};
+ if (!@ip_addresses) {
+ notify($ERRORS{'DEBUG'}, 0, "interface is not assigned an IP address: $interface_name");
+ next;
+ }
+
+ # Check if interface has the private IP address assigned to it
+ if (grep { $_ eq $computer_private_ip_address } @ip_addresses) {
+ notify($ERRORS{'DEBUG'}, 0, "determined private interface name: $interface_name (" . join (", ", @ip_addresses) . ")");
+ return $interface_name;
+ }
+ }
+
+ notify($ERRORS{'WARNING'}, 0, "failed to determined private interface name, no interface is assigned the private IP address for the reservation: $computer_private_ip_address\n" . format_data($network_configuration));
+ return;
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 get_public_interface_name
+
+ Parameters : none
+ Returns : string
+ Description : Determines the public interface name based on the information in
+ the network configuration hash returned by
+ get_network_configuration.
+
+=cut
+
+sub get_public_interface_name {
+ my $self = shift;
+ if (ref($self) !~ /VCL::Module/i) {
+ notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
+ return;
+ }
+
+ # Get the network configuration hash reference
+ my $network_configuration = $self->get_network_configuration();
+ if (!$network_configuration) {
+ notify($ERRORS{'WARNING'}, 0, "unable to determine public interface name, failed to retrieve network configuration");
+ return;
+ }
+
+ # Get the computer private IP address
+ my $computer_private_ip_address = $self->data->get_computer_private_ip_address();
+ if (!$computer_private_ip_address) {
+ notify($ERRORS{'DEBUG'}, 0, "unable to retrieve computer private IP address from reservation data");
+ return;
+ }
+
+ my $public_interface_name;
+
+ # Loop through all of the network interfaces found
+ foreach my $interface_name (sort keys %$network_configuration) {
+ # Get the interface IP addresses and make sure an IP address was found
+ my @ip_addresses = keys %{$network_configuration->{$interface_name}{ip_address}};
+ if (!@ip_addresses) {
+ notify($ERRORS{'DEBUG'}, 0, "interface is not assigned an IP address: $interface_name");
+ next;
+ }
+
+ # Check if interface has private IP address assigned to it
+ if (grep { $_ eq $computer_private_ip_address } @ip_addresses) {
+ notify($ERRORS{'DEBUG'}, 0, "ignoring private interface: $interface_name (" . join (", ", @ip_addresses) . ")");
+ next;
+ }
+
+ my $description = $network_configuration->{$interface_name}{description} || '';
+
+ # Check if the interface should be ignored based on the name or description
+ if ($interface_name =~ /(^lo|loopback|vmnet|afs|tunnel|6to4|isatap|teredo)/i) {
+ notify($ERRORS{'DEBUG'}, 0, "interface ignored because of name: $interface_name (" . join (", ", @ip_addresses) . ")");
+ next;
+ }
+ elsif ($description =~ /loopback|virtual|afs|tunnel|pseudo|6to4|isatap/i) {
+ notify($ERRORS{'DEBUG'}, 0, "interface ignored because of description: $interface_name, description: $description (" . join (", ", @ip_addresses) . ")");
+ next;
+ }
+
+ # Loop through the IP addresses for the interface
+ # Try to find a public address
+ for my $ip_address (@ip_addresses) {
+
+ if (is_public_ip_address($ip_address)) {
+ notify($ERRORS{'DEBUG'}, 0, "determined public interface name: $interface_name (" . join (", ", @ip_addresses) . ")");
+ return $interface_name;
+ }
+ else {
+ notify($ERRORS{'DEBUG'}, 0, "found interface assigned a private address not matching private address for reservation: $interface_name (" . join(", ", @ip_addresses) . ")");
+
+ if ($public_interface_name) {
+ notify($ERRORS{'DEBUG'}, 0, "already found another interface with a private address not matching private address for reservation: $public_interface_name, the first one found will be used if an interface with a public address isn't found");
+ }
+ else {
+ $public_interface_name = $interface_name;
+ notify($ERRORS{'DEBUG'}, 0, "assuming interface is public if another interface with a public address isn't found: $public_interface_name");
+ }
+ }
+ }
+ }
+
+ if ($public_interface_name) {
+ notify($ERRORS{'DEBUG'}, 0, "did not find any interfaces assigned a public IP address, returning interface assigned a private IP address not matching the private IP address assigned to the reservation computer: $public_interface_name");
+ return $public_interface_name;
+ }
+ else {
+ notify($ERRORS{'WARNING'}, 0, "failed to determine the public interface from the network configuration:\n" . format_data($network_configuration));
+ return;
+ }
+}
#/////////////////////////////////////////////////////////////////////////////
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=982258&r1=982257&r2=982258&view=diff
==============================================================================
--- incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Linux.pm (original)
+++ incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Linux.pm Wed Aug 4 14:11:02 2010
@@ -284,6 +284,9 @@ sub post_load {
else {
notify($ERRORS{'DEBUG'}, 0, "ran $script_path");
}
+
+ # Attempt to generate ifcfg-eth* files and ifup any interfaces which the file does not exist
+ $self->activate_interfaces();
return 1;
@@ -339,54 +342,52 @@ sub post_reserve {
Parameters :
Returns : 1,0 success or failure
- Description : To be used for nodes that have both private and public addresses.
- Set hostname to that of the public address.
+ Description : To be used for nodes that have both private and public addresses.
+ Set hostname to that of the public address.
=cut
sub update_public_hostname {
- my $self = shift;
- unless (ref($self) && $self->isa('VCL::Module')) {
- notify($ERRORS{'CRITICAL'}, 0, "subroutine can only be called as a VCL::Module module object method");
- return;
- }
-
- my $management_node_keys = $self->data->get_management_node_keys();
- my $computer_node_name = $self->data->get_computer_node_name();
- my $image_os_type = $self->data->get_image_os_type();
- my $image_os_name = $self->data->get_image_os_name();
- my $computer_short_name = $self->data->get_computer_short_name();
- my $public_hostname;
-
- #Get the IP address of the public adapter
-
- my $public_IP_address = getdynamicaddress($computer_short_name, $image_os_name, $image_os_type);
- if (!($public_IP_address)) {
- notify($ERRORS{'WARNING'}, 0, "Unable to get public IP address");
- return 0;
- }
-
- #Get the hostname for the public IP address
- my $get_public_hostname = "/bin/ipcalc --hostname $public_IP_address";
- my ($ipcalc_status, $ipcalc_output) = run_ssh_command($computer_short_name, $management_node_keys,$get_public_hostname);
- if (!defined($ipcalc_status)) {
- notify($ERRORS{'WARNING'}, 0, "unable to run ssh cmd $get_public_hostname on $computer_short_name");
- return 0;
- }
- elsif ("@$ipcalc_output" =~ /HOSTNAME=(.*)/i) {
- $public_hostname = $1;
- notify($ERRORS{'DEBUG'}, 0, "collected public hostname= $public_hostname");
- }
-
- #Set the node's hostname to public hostname
- my ($set_hostname_status, $set_hostname_output) = run_ssh_command($computer_short_name, $management_node_keys,"hostname -v $public_hostname");
- unless (defined($set_hostname_status) && $set_hostname_status == 0) {
- notify($ERRORS{'OK'}, 0, "failed to set public_hostname on $computer_short_name output: @${set_hostname_output}");
- }
-
- notify($ERRORS{'OK'}, 0, "successfully set public_hostname on $computer_short_name output: @${set_hostname_output}");
- return 1;
-
+ my $self = shift;
+ unless (ref($self) && $self->isa('VCL::Module')) {
+ notify($ERRORS{'CRITICAL'}, 0, "subroutine can only be called as a VCL::Module module object method");
+ return;
+ }
+
+ my $management_node_keys = $self->data->get_management_node_keys();
+ my $computer_node_name = $self->data->get_computer_node_name();
+ my $image_os_type = $self->data->get_image_os_type();
+ my $image_os_name = $self->data->get_image_os_name();
+ my $computer_short_name = $self->data->get_computer_short_name();
+ my $public_hostname;
+
+ # Get the IP address of the public adapter
+ my $public_IP_address = getdynamicaddress($computer_short_name, $image_os_name, $image_os_type);
+ if (!($public_IP_address)) {
+ notify($ERRORS{'WARNING'}, 0, "Unable to get public IP address");
+ return 0;
+ }
+
+ # Get the hostname for the public IP address
+ my $get_public_hostname = "/bin/ipcalc --hostname $public_IP_address";
+ my ($ipcalc_status, $ipcalc_output) = run_ssh_command($computer_short_name, $management_node_keys,$get_public_hostname);
+ if (!defined($ipcalc_status)) {
+ notify($ERRORS{'WARNING'}, 0, "unable to run ssh cmd $get_public_hostname on $computer_short_name");
+ return 0;
+ }
+ elsif ("@$ipcalc_output" =~ /HOSTNAME=(.*)/i) {
+ $public_hostname = $1;
+ notify($ERRORS{'DEBUG'}, 0, "collected public hostname= $public_hostname");
+ }
+
+ #Set the node's hostname to public hostname
+ my ($set_hostname_status, $set_hostname_output) = run_ssh_command($computer_short_name, $management_node_keys,"hostname -v $public_hostname");
+ unless (defined($set_hostname_status) && $set_hostname_status == 0) {
+ notify($ERRORS{'OK'}, 0, "failed to set public_hostname on $computer_short_name output: @${set_hostname_output}");
+ }
+
+ notify($ERRORS{'OK'}, 0, "successfully set public_hostname on $computer_short_name output: @${set_hostname_output}");
+ return 1;
}
#/////////////////////////////////////////////////////////////////////////////
@@ -420,7 +421,6 @@ sub clear_private_keys {
notify($ERRORS{'CRITICAL'}, 0, "failed to clear any id_rsa keys from /root/.ssh");
return 0;
}
-
}
#/////////////////////////////////////////////////////////////////////////////
@@ -619,23 +619,6 @@ sub set_static_public_address {
#/////////////////////////////////////////////////////////////////////////////
-=head2 get_public_interface_name
-
- Parameters :
- Returns :
- Description :
-
-=cut
-
-sub get_public_interface_name {
-
- #global varible pulled from vcld.conf
- return $ETHDEVICE;
-
-}
-
-#/////////////////////////////////////////////////////////////////////////////
-
=head2 get_public_default_gateway
Parameters :
@@ -959,73 +942,17 @@ sub changepasswd {
notify($ERRORS{'WARNING'}, 0, "node is not defined") if (!(defined($node)));
notify($ERRORS{'WARNING'}, 0, "account is not defined") if (!(defined($account)));
-
- my @ssh;
- my $l;
- if ($account eq "root") {
-
- #if not a predefined password, get one!
- $passwd = getpw(15) if (!(defined($passwd)));
- notify($ERRORS{'OK'}, 0, "password for $node is $passwd");
-
- if (open(OPENSSL, "openssl passwd -1 $passwd 2>&1 |")) {
- $passwd = <OPENSSL>;
- chomp $passwd;
- close(OPENSSL);
- if ($passwd =~ /command not found/) {
- notify($ERRORS{'CRITICAL'}, 0, "failed $passwd ");
- return 0;
- }
- my $tmpfile = "/tmp/shadow.$node";
- if (open(TMP, ">$tmpfile")) {
- print TMP "$account:$passwd:13061:0:99999:7:::\n";
- close(TMP);
- if (run_ssh_command($node, $management_node_keys, "cat /etc/shadow \|grep -v $account >> $tmpfile", "root")) {
- notify($ERRORS{'DEBUG'}, 0, "collected /etc/shadow file from $node");
- if (run_scp_command($tmpfile, "$node:/etc/shadow", $management_node_keys)) {
- notify($ERRORS{'DEBUG'}, 0, "copied updated /etc/shadow file to $node");
- if (run_ssh_command($node, $management_node_keys, "chmod 600 /etc/shadow", "root")) {
- notify($ERRORS{'DEBUG'}, 0, "updated permissions to 600 on /etc/shadow file on $node");
- unlink $tmpfile;
- return 1;
- }
- else {
- notify($ERRORS{'WARNING'}, 0, "failed to change file permissions on $node /etc/shadow");
- unlink $tmpfile;
- return 0;
- }
- } ## end if (run_scp_command($tmpfile, "$node:/etc/shadow"...
- else {
- notify($ERRORS{'WARNING'}, 0, "failed to copy contents of shadow file on $node ");
- }
- } ## end if (run_ssh_command($node, $identity_key, ...
- else {
- notify($ERRORS{'WARNING'}, 0, "failed to copy contents of shadow file on $node ");
- unlink $tmpfile;
- return 0;
- }
- } ## end if (open(TMP, ">$tmpfile"))
- else {
- notify($ERRORS{'OK'}, 0, "failed could open $tmpfile $!");
- }
- } ## end if (open(OPENSSL, "openssl passwd -1 $passwd 2>&1 |"...
- return 0;
- } ## end if ($account eq "root")
- else {
- #actual user
- #push it through passwd cmd stdin
- # not all distros' passwd command support stdin
- my @sshcmd = run_ssh_command($node, $management_node_keys, "echo $passwd \| /usr/bin/passwd -f $account --stdin", "root");
- foreach my $l (@{$sshcmd[1]}) {
- if ($l =~ /authentication tokens updated successfully/) {
- notify($ERRORS{'OK'}, 0, "successfully changed local password account $account");
- return 1;
- }
- }
-
- } ## end else [ if ($account eq "root")
-
-} ## end sub changepasswd
+
+ $passwd = getpw(15) if (!(defined($passwd)));
+
+ my ($exit_status, $output) = run_ssh_command($node, $management_node_keys, "echo $passwd \| /usr/bin/passwd -f $account --stdin", "root");
+ if (!defined($output)) {
+ notify($ERRORS{'WARNING'}, 0, "failed to run SSH command to set password for account: $account");
+ return;
+ }
+ notify($ERRORS{'OK'}, 0, "changed password for account: $account, output:\n" . join("\n", @$output));
+ return 1;
+}
#/////////////////////////////////////////////////////////////////////////////
@@ -1299,14 +1226,14 @@ sub execute {
# Get 2nd display output argument if supplied, or set default value
my $display_output = shift || '0';
- # Get the computer hostname
- my $computer_hostname = $self->data->get_computer_hostname() || return;
+ # Get the computer node name
+ my $computer_name = $self->data->get_computer_node_name() || return;
# Get the identity keys used by the management node
my $management_node_keys = $self->data->get_management_node_keys() || '';
# Run the command via SSH
- my ($exit_status, $output) = run_ssh_command($computer_hostname, $management_node_keys, $command, '', '', $display_output);
+ my ($exit_status, $output) = run_ssh_command($computer_name, $management_node_keys, $command, '', '', $display_output);
if (defined($exit_status) && defined($output)) {
if ($display_output) {
notify($ERRORS{'OK'}, 0, "executed command: '$command', exit status: $exit_status, output:\n" . join("\n", @$output));
@@ -1314,7 +1241,7 @@ sub execute {
return ($exit_status, $output);
}
else {
- notify($ERRORS{'WARNING'}, 0, "failed to run command on $computer_hostname: $command");
+ notify($ERRORS{'WARNING'}, 0, "failed to run command on $computer_name: $command");
return;
}
}
@@ -2322,6 +2249,315 @@ sub generate_ext_sshd_init {
return 1;
}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 activate_interfaces
+
+ Parameters : none
+ Returns : true
+ Description : Finds all networking interfaces with an active link. Checks if an
+ ifcfg-eth* file exists for the interface. An ifcfg-eth* file is
+ generated if it does not exist using DHCP and the interface is
+ brought up via ifup. This is useful if additional interfaces are
+ added by the provisioning module when an image is loaded.
+
+=cut
+
+sub activate_interfaces {
+ my $self = shift;
+ if (ref($self) !~ /VCL::Module/i) {
+ notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
+ return 0;
+ }
+
+ # Run 'ip link' to find all interfaces with links
+ my $command = "ip link";
+ notify($ERRORS{'DEBUG'}, 0, "attempting to find network interfaces with an active link");
+ my ($exit_status, $output) = $self->execute($command, 1);
+ if (!defined($output)) {
+ notify($ERRORS{'WARNING'}, 0, "failed to run command to find network interfaces with an active link:\n$command");
+ return;
+ }
+
+ # Extract the interface names from the 'ip link' output
+ my @interface_names = grep { /^\d+:\s+(eth\d+)/ ; $_ = $1 } @$output;
+ notify($ERRORS{'DEBUG'}, 0, "found interface names:\n" . join("\n", @interface_names));
+
+ # Find existing ifcfg-eth* files
+ my $ifcfg_directory = '/etc/sysconfig/network-scripts';
+ my @ifcfg_paths = $self->find_files($ifcfg_directory, 'ifcfg-eth*');
+ notify($ERRORS{'DEBUG'}, 0, "found existing ifcfg-eth* files:\n" . join("\n", @ifcfg_paths));
+
+ # Loop through the linked interfaces
+ for my $interface_name (@interface_names) {
+ my $ifcfg_path = "$ifcfg_directory/ifcfg-$interface_name";
+
+ # Check if an ifcfg-eth* file already exists for the interface
+ if (grep(/$ifcfg_path/, @ifcfg_paths)) {
+ notify($ERRORS{'DEBUG'}, 0, "ifcfg file already exists for $interface_name");
+ next;
+ }
+
+ notify($ERRORS{'DEBUG'}, 0, "ifcfg file does not exist for $interface_name");
+
+ # Assemble the contents of the ifcfg-eth* file for the interface
+ my $ifcfg_contents = <<EOF;
+DEVICE=$interface_name
+BOOTPROTO=dhcp
+STARTMODE=onboot
+ONBOOT=yes
+EOF
+
+ # Create the ifcfg-eth* file and attempt to call ifup on the interface
+ my $echo_command = "echo \E \"$ifcfg_contents\" > $ifcfg_path && ifup $interface_name";
+ notify($ERRORS{'DEBUG'}, 0, "attempting to echo contents to $ifcfg_path:\n$ifcfg_contents");
+ my ($echo_exit_status, $echo_output) = $self->execute($echo_command, 1);
+ if (!defined($echo_output)) {
+ notify($ERRORS{'WARNING'}, 0, "failed to run command to echo contents to $ifcfg_path");
+ return;
+ }
+ elsif (grep(/done\./, @$echo_output)) {
+ notify($ERRORS{'OK'}, 0, "created $ifcfg_path and enabled interface: $interface_name, output:\n" . join("\n", @$echo_output));
+ }
+ else {
+ notify($ERRORS{'WARNING'}, 0, "failed to create $ifcfg_path and enable interface: $interface_name, output:\n" . join("\n", @$echo_output));
+ }
+ }
+
+ return 1;
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 get_network_configuration
+
+ Parameters : $network_type (optional)
+ Returns : hash reference
+ Description : Retrieves the network configuration on the Linux computer and
+ constructs a hash. A $network_type argument can be supplied
+ containing either 'private' or 'public'. If the $network_type
+ argument is not supplied, the hash keys are the network interface
+ names and the hash reference returned is formatted as follows:
+ |--%{eth0}
+ |--%{eth0}{ip_address}
+ |--{eth0}{ip_address}{10.10.4.35} = '255.255.240.0'
+ |--{eth0}{name} = 'eth0'
+ |--{eth0}{physical_address} = '00:50:56:08:00:f8'
+ |--%{eth1}
+ |--%{eth1}{ip_address}
+ |--{eth1}{ip_address}{152.1.14.200} = '255.255.255.0'
+ |--{eth1}{name} = 'eth1'
+ |--{eth1}{physical_address} = '00:50:56:08:00:f9'
+ |--%{eth2}
+ |--%{eth2}{ip_address}
+ |--{eth2}{ip_address}{10.1.2.33} = '255.255.240.0'
+ |--{eth2}{name} = 'eth2'
+ |--{eth2}{physical_address} = '00:0c:29:ba:c1:77'
+ |--%{lo}
+ |--%{lo}{ip_address}
+ |--{lo}{ip_address}{127.0.0.1} = '255.0.0.0'
+ |--{lo}{name} = 'lo'
+
+ If the $network_type argument is supplied, a hash reference is
+ returned containing only the configuration for the specified
+ interface:
+ |--%{ip_address}
+ |--{ip_address}{10.1.2.33} = '255.255.240.0'
+ |--{name} = 'eth2'
+ |--{physical_address} = '00:0c:29:ba:c1:77'
+
+=cut
+
+sub get_network_configuration {
+ my $self = shift;
+ if (ref($self) !~ /VCL::Module/i) {
+ notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
+ return;
+ }
+
+ # Check if a 'public' or 'private' network type argument was specified
+ my $network_type = lc(shift());
+ if ($network_type && $network_type !~ /(public|private)/i) {
+ notify($ERRORS{'WARNING'}, 0, "network type argument can only be 'public' or 'private'");
+ return;
+ }
+
+ my %network_configuration;
+
+ # Check if the network configuration has already been retrieved and saved in this object
+ if (!$self->{network_configuration}) {
+ # Run ipconfig
+ my $command = "ifconfig -a";
+ my ($exit_status, $output) = $self->execute($command);
+ if (!defined($output)) {
+ notify($ERRORS{'WARNING'}, 0, "failed to run command to retrieve network configuration: $command");
+ return;
+ }
+
+ # Loop through the ifconfig output lines
+ my $interface_name;
+ for my $line (@$output) {
+ # Extract the interface name from the Link line:
+ # eth2 Link encap:Ethernet HWaddr 00:0C:29:78:77:AB
+ if ($line =~ /^([^\s]+).*Link/) {
+ $interface_name = $1;
+ $network_configuration{$interface_name}{name} = $interface_name;
+ }
+
+ # Skip to the next line if the interface name has not been determined yet
+ next if !$interface_name;
+
+ # Parse the HWaddr line:
+ # eth2 Link encap:Ethernet HWaddr 00:0C:29:78:77:AB
+ if ($line =~ /HWaddr\s+([\w:]+)/) {
+ $network_configuration{$interface_name}{physical_address} = lc($1);
+ }
+
+ # Parse the IP address line:
+ # inet addr:10.10.4.35 Bcast:10.10.15.255 Mask:255.255.240.0
+ if ($line =~ /inet addr:([\d\.]+).*Mask:([\d\.]+)/) {
+ $network_configuration{$interface_name}{ip_address}{$1} = $2;
+ }
+ }
+
+ $self->{network_configuration} = \%network_configuration;
+ notify($ERRORS{'DEBUG'}, 0, "retrieved network configuration:\n" . format_data(\%network_configuration));
+ }
+ else {
+ notify($ERRORS{'DEBUG'}, 0, "network configuration has already been retrieved");
+ %network_configuration = %{$self->{network_configuration}};
+ }
+
+ # 'public' or 'private' wasn't specified, return all network interface information
+ if (!$network_type) {
+ return \%network_configuration;
+ }
+
+ # Determine either the private or public interface name based on the $network_type argument
+ my $interface_name;
+ if ($network_type =~ /private/i) {
+ $interface_name = $self->get_private_interface_name();
+ }
+ else {
+ $interface_name = $self->get_public_interface_name();
+ }
+ if (!$interface_name) {
+ notify($ERRORS{'WARNING'}, 0, "failed to determine the $network_type interface name");
+ return;
+ }
+
+ # Extract the network configuration specific to the public or private interface
+ my $return_network_configuration = $network_configuration{$interface_name};
+ if (!$return_network_configuration) {
+ notify($ERRORS{'WARNING'}, 0, "network configuration does not exist for interface: $interface_name, network configuration:\n" . format_data(\%network_configuration));
+ return;
+ }
+ notify($ERRORS{'DEBUG'}, 0, "returning $network_type network configuration");
+ return $return_network_configuration;
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 get_private_mac_address
+
+ Parameters : none
+ Returns : string
+ Description : Returns the MAC address of the interface assigned the private IP
+ address.
+
+=cut
+
+sub get_private_mac_address {
+ my $self = shift;
+ if (ref($self) !~ /VCL::Module/i) {
+ notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
+ return;
+ }
+
+ my $private_network_configuration = $self->get_network_configuration('private');
+ if (!$private_network_configuration) {
+ notify($ERRORS{'WARNING'}, 0, "failed to retrieve private network configuration");
+ return;
+ }
+
+ my $private_mac_address = $private_network_configuration->{physical_address};
+ if (!$private_mac_address) {
+ notify($ERRORS{'WARNING'}, 0, "'physical_address' key is not set in the private network configuration hash:\n" . format_data($private_network_configuration));
+ return;
+ }
+
+ notify($ERRORS{'DEBUG'}, 0, "retrieved private MAC address: $private_mac_address");
+ return $private_mac_address;
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 get_public_mac_address
+
+ Parameters : none
+ Returns : string
+ Description : Returns the MAC address of the interface assigned the public IP
+ address.
+
+=cut
+
+sub get_public_mac_address {
+ my $self = shift;
+ if (ref($self) !~ /VCL::Module/i) {
+ notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
+ return;
+ }
+
+ my $public_network_configuration = $self->get_network_configuration('public');
+ if (!$public_network_configuration) {
+ notify($ERRORS{'WARNING'}, 0, "failed to retrieve public network configuration");
+ return;
+ }
+
+ my $public_mac_address = $public_network_configuration->{physical_address};
+ if (!$public_mac_address) {
+ notify($ERRORS{'WARNING'}, 0, "'physical_address' key is not set in the public network configuration hash:\n" . format_data($public_network_configuration));
+ return;
+ }
+
+ notify($ERRORS{'DEBUG'}, 0, "retrieved public MAC address: $public_mac_address");
+ return $public_mac_address;
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 get_public_ip_address
+
+ Parameters : none
+ Returns : string
+ Description : Returns the public IP address assigned to the computer.
+
+=cut
+
+sub get_public_ip_address {
+ my $self = shift;
+ if (ref($self) !~ /VCL::Module/i) {
+ notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
+ return;
+ }
+
+ my $public_network_configuration = $self->get_network_configuration('public');
+ if (!$public_network_configuration) {
+ notify($ERRORS{'WARNING'}, 0, "failed to retrieve public network configuration");
+ return;
+ }
+
+ my $public_ip_address = (keys %{$public_network_configuration->{ip_address}})[0];
+ if (!$public_ip_address) {
+ notify($ERRORS{'WARNING'}, 0, "'ip_address' key is not set in the public network configuration hash:\n" . format_data($public_network_configuration));
+ return;
+ }
+
+ notify($ERRORS{'DEBUG'}, 0, "retrieved public IP address: $public_ip_address");
+ return $public_ip_address;
+}
+
#/////////////////////////////////////////////////////////////////////////////
1;
Modified: incubator/vcl/trunk/managementnode/lib/VCL/Module/Provisioning/VMware/VMware.pm
URL: http://svn.apache.org/viewvc/incubator/vcl/trunk/managementnode/lib/VCL/Module/Provisioning/VMware/VMware.pm?rev=982258&r1=982257&r2=982258&view=diff
==============================================================================
--- incubator/vcl/trunk/managementnode/lib/VCL/Module/Provisioning/VMware/VMware.pm (original)
+++ incubator/vcl/trunk/managementnode/lib/VCL/Module/Provisioning/VMware/VMware.pm Wed Aug 4 14:11:02 2010
@@ -545,13 +545,6 @@ sub get_active_vmx_file_path {
my $computer_name = $self->data->get_computer_short_name();
- # Get the normal, expected vmx file path for this reservation
- my $vmx_file_path = $self->get_vmx_file_path();
- if (!$vmx_file_path) {
- notify($ERRORS{'WARNING'}, 0, "unable to determine normal vmx file path");
- return;
- }
-
# Get the MAC addresses being used by the running VM for this reservation
my @vm_mac_addresses = ($self->os->get_private_mac_address(), $self->os->get_public_mac_address());
if (!@vm_mac_addresses) {
@@ -564,18 +557,22 @@ sub get_active_vmx_file_path {
# Get an array containing the existing vmx file paths on the VM host
my @host_vmx_file_paths = $self->get_vmx_file_paths();
-
- # Remove the normal vmx file from the array and add it to the beginning
- # This causes it to be checked first
- @host_vmx_file_paths = grep($_ ne $vmx_file_path, @host_vmx_file_paths);
- unshift @host_vmx_file_paths, $vmx_file_path;
-
notify($ERRORS{'DEBUG'}, 0, "retrieved vmx file paths currently residing on the VM host:\n" . join("\n", @host_vmx_file_paths));
-
+
+ # Sort the vmx file path list so that paths containing the computer name are checked first
+ my @ordered_host_vmx_file_paths;
+ push @ordered_host_vmx_file_paths, grep(/$computer_name\_/, @host_vmx_file_paths);
+ push @ordered_host_vmx_file_paths, grep(!/$computer_name\_/, @host_vmx_file_paths);
+ @host_vmx_file_paths = @ordered_host_vmx_file_paths;
+ notify($ERRORS{'DEBUG'}, 0, "sorted vmx file paths so that directories containing $computer_name are checked first:\n" . join("\n", @host_vmx_file_paths));
+
# Loop through the vmx files found on the VM host
# Check if the MAC addresses in the vmx file match the MAC addresses currently in use on the VM to be captured
my @matching_host_vmx_paths;
for my $host_vmx_path (@host_vmx_file_paths) {
+ # Quit checking if a match has already been found and the vmx path being checked doesn't contain the computer name
+ last if (@matching_host_vmx_paths && $host_vmx_path !~ /$computer_name/);
+
# Get the info from the existing vmx file on the VM host
my $host_vmx_info = $self->get_vmx_info($host_vmx_path);
if (!$host_vmx_info) {
@@ -600,12 +597,7 @@ sub get_active_vmx_file_path {
notify($ERRORS{'DEBUG'}, 0, "comparing MAC addresses\nused by $computer_name:\n" . join("\n", sort(@vm_mac_addresses)) . "\nconfigured in $vmx_file_name:\n" . join("\n", sort(@vmx_mac_addresses)));
my @matching_mac_addresses = map { my $vm_mac_address = $_; grep(/$vm_mac_address/i, @vmx_mac_addresses) } @vm_mac_addresses;
- if (@matching_mac_addresses) {
- push @matching_host_vmx_paths, $host_vmx_path;
- notify($ERRORS{'DEBUG'}, 0, "found matching MAC addresses: $computer_name <==> $vmx_file_name (" . join(", ", @matching_mac_addresses) . ")");
- last if ($vmx_file_path eq $host_vmx_path && scalar(@matching_host_vmx_paths) == 1);
- }
- else {
+ if (!@matching_mac_addresses) {
notify($ERRORS{'DEBUG'}, 0, "ignoring $vmx_file_name because MAC addresses do not match the ones being used by $computer_name");
next;
}
@@ -964,6 +956,7 @@ sub prepare_vmx {
# Get the required data to configure the .vmx file
my $image_id = $self->data->get_image_id() || return;
my $imagerevision_id = $self->data->get_imagerevision_id() || return;
+ my $image_project = $self->data->get_image_project() || return;
my $computer_id = $self->data->get_computer_id() || return;
my $vmx_file_name = $self->get_vmx_file_name() || return;
my $vmx_file_path = $self->get_vmx_file_path() || return;
@@ -1194,6 +1187,45 @@ sub prepare_vmx {
));
}
+ # Add additional Ethernet interfaces if the image project name is not vcl
+ if ($image_project !~ /^vcl$/i) {
+ notify($ERRORS{'DEBUG'}, 0, "image project is: $image_project, checking if additional network adapters should be configured");
+
+ # Get a list of all the network names configured on the VMware host
+ my @network_names = $self->api->get_network_names();
+ notify($ERRORS{'DEBUG'}, 0, "retrieved network names configured on the VM host: " . join(", ", @network_names));
+
+ # Check each network name
+ # Begin the index at 2 for additional interfaces added because ethernet0 and ethernet1 have already been added
+ my $interface_index = 2;
+ for my $network_name (@network_names) {
+ # Ignore network names which have already been added
+ if ($network_name =~ /^($virtual_switch_0|$virtual_switch_1)$/) {
+ notify($ERRORS{'DEBUG'}, 0, "ignoring network name because it is already being used for the private or public interface: $network_name");
+ next;
+ }
+ elsif ($network_name =~ /$image_project/i || $image_project =~ /$network_name/i) {
+ notify($ERRORS{'DEBUG'}, 0, "network name ($network_name) and image project name ($image_project) intersect, adding network interface to VM for network $network_name");
+
+ $vmx_parameters{"ethernet$interface_index.addressType"} = "generated";
+ $vmx_parameters{"ethernet$interface_index.present"} = "TRUE";
+ $vmx_parameters{"ethernet$interface_index.virtualDev"} = "$vm_ethernet_adapter_type";
+ $vmx_parameters{"ethernet$interface_index.networkName"} = "$network_name";
+
+ $interface_index++;
+ }
+ else {
+ notify($ERRORS{'DEBUG'}, 0, "network name ($network_name) and image project name ($image_project) do not intersect, network interface will not be added to VM for network $network_name");
+ }
+ }
+
+ }
+ else {
+ notify($ERRORS{'DEBUG'}, 0, "image project is: $image_project, additional network adapters will not be configured");
+ }
+
+ notify($ERRORS{'DEBUG'}, 0, "vmx parameters:\n" . format_data(\%vmx_parameters));
+
# Create a string from the hash
my $vmx_contents = "#!/usr/bin/vmware\n";
map { $vmx_contents .= "$_ = \"$vmx_parameters{$_}\"\n" } sort keys %vmx_parameters;
Modified: incubator/vcl/trunk/managementnode/lib/VCL/utils.pm
URL: http://svn.apache.org/viewvc/incubator/vcl/trunk/managementnode/lib/VCL/utils.pm?rev=982258&r1=982257&r2=982258&view=diff
==============================================================================
--- incubator/vcl/trunk/managementnode/lib/VCL/utils.pm (original)
+++ incubator/vcl/trunk/managementnode/lib/VCL/utils.pm Wed Aug 4 14:11:02 2010
@@ -3227,90 +3227,6 @@ sub known_hosts {
#/////////////////////////////////////////////////////////////////////////////
-=head2 changelinuxpassword
-
- Parameters : $node, $account, $passwd
- Returns : 0 or 1
- Description : changes linux root password on stock blade installs
-
-=cut
-
-sub changelinuxpassword {
-# change the privileged account passwords on the blade images
- my ($node, $account, $passwd) = @_;
- my ($package, $filename, $line, $sub) = caller(0);
- notify($ERRORS{'WARNING'}, 0, "node is not defined") if (!(defined($node)));
- notify($ERRORS{'WARNING'}, 0, "account is not defined") if (!(defined($account)));
-
- my @ssh;
- my $l;
- my $identity_keys = $ENV{management_node_info}{keys};
- if ($account eq "root") {
-
-
- #if not a predefined password, get one!
- $passwd = getpw(15) if (!(defined($passwd)));
- notify($ERRORS{'OK'}, 0, "password for $node is $passwd");
-
- if (open(OPENSSL, "openssl passwd -1 $passwd 2>&1 |")) {
- $passwd = <OPENSSL>;
- chomp $passwd;
- close(OPENSSL);
- if ($passwd =~ /command not found/) {
- notify($ERRORS{'CRITICAL'}, 0, "failed $passwd ");
- return 0;
- }
- my $tmpfile = "/tmp/shadow.$node";
- if (open(TMP, ">$tmpfile")) {
- print TMP "$account:$passwd:13061:0:99999:7:::\n";
- close(TMP);
- if (run_ssh_command($node, $identity_keys, "cat /etc/shadow \|grep -v $account >> $tmpfile", "root")) {
- notify($ERRORS{'DEBUG'}, 0, "collected /etc/shadow file from $node");
- if (run_scp_command($tmpfile, "$node:/etc/shadow", $identity_keys)) {
- notify($ERRORS{'DEBUG'}, 0, "copied updated /etc/shadow file to $node");
- if (run_ssh_command($node, $identity_keys, "chmod 600 /etc/shadow", "root")) {
- notify($ERRORS{'DEBUG'}, 0, "updated permissions to 600 on /etc/shadow file on $node");
- unlink $tmpfile;
- return 1;
- }
- else {
- notify($ERRORS{'WARNING'}, 0, "failed to change file permissions on $node /etc/shadow");
- unlink $tmpfile;
- return 0;
- }
- } ## end if (run_scp_command($tmpfile, "$node:/etc/shadow"...
- else {
- notify($ERRORS{'WARNING'}, 0, "failed to copy contents of shadow file on $node ");
- }
- } ## end if (run_ssh_command($node, $identity_keys...
- else {
- notify($ERRORS{'WARNING'}, 0, "failed to copy contents of shadow file on $node ");
- unlink $tmpfile;
- return 0;
- }
- } ## end if (open(TMP, ">$tmpfile"))
- else {
- notify($ERRORS{'OK'}, 0, "failed could open $tmpfile $!");
- }
- } ## end if (open(OPENSSL, "openssl passwd -1 $passwd 2>&1 |"...
- return 0;
- } ## end if ($account eq "root")
- else {
- #actual user
- #push it through passwd cmd stdin
- my @sshcmd = run_ssh_command($node, $identity_keys, "echo $passwd \| /usr/bin/passwd -f $account --stdin", "root");
- foreach my $l (@{$sshcmd[1]}) {
- if ($l =~ /authentication tokens updated successfully/) {
- notify($ERRORS{'OK'}, 0, "successfully changed local password account $account");
- return 1;
- }
- }
-
- } ## end else [ if ($account eq "root")
-} ## end sub changelinuxpassword
-
-#/////////////////////////////////////////////////////////////////////////////
-
=head2 getusergroupmembers
Parameters : usergroupid
@@ -8885,51 +8801,20 @@ sub reservation_being_processed {
$computerloadlog_exists = 0;
}
- # Check for any running processes
- #my $ps_command = "ps -ef";
- #notify($ERRORS{'DEBUG'}, 0, "executing ps -ef command: $ps_command");
- #my ($ps_exit_status, $ps_output) = run_command($ps_command);
- #if (defined $ps_exit_status && $ps_exit_status == 0) {
- # notify($ERRORS{'DEBUG'}, 0, "ps exit status=$ps_exit_status, output:\n@{$ps_output}");
- #
- # my @matching_processes = grep {/VCL::.*:$reservation_id/} @{$ps_output};
- # notify($ERRORS{'DEBUG'}, 0, "matching processes: @matching_processes, count: " . scalar @matching_processes);
- #}
- #else {
- # notify($ERRORS{'WARNING'}, 0, "failed to execute ps command");
- #}
-
- my $process_running = 0;
-
- #my $process_running;
- #if (defined($pgrep_exit_status) && @{$pgrep_output} > 0) {
- # notify($ERRORS{'DEBUG'}, 0, "reservation is being processed by:\n@{$pgrep_output}");
- # $process_running = 1;
- #}
- #elsif (defined($pgrep_exit_status) && @{$pgrep_output} == 0) {
- # notify($ERRORS{'DEBUG'}, 0, "did not find any running processes for reservation");
- # $process_running = 0;
- #}
- #elsif (defined($pgrep_exit_status)) {
- # notify($ERRORS{'WARNING'}, 0, "error occurred running command: $pgrep_command, exit status: $pgrep_exit_status, output:\n@{$pgrep_output}");
- # $process_running = 0;
- #}
- #else {
- # notify($ERRORS{'WARNING'}, 0, "command could not be executed: $pgrep_command");
- # $process_running = 0;
- #}
+ # Check if a vcld process is running matching for this reservation
+ my @processes_running = is_management_node_process_running("$PROCESSNAME [0-9]+:$reservation_id ");
# Check the results and return
- if ($computerloadlog_exists && $process_running) {
- notify($ERRORS{'DEBUG'}, 0, "reservation is currently being processed");
+ if ($computerloadlog_exists && @processes_running) {
+ notify($ERRORS{'DEBUG'}, 0, "reservation is currently being processed, computerloadlog 'begin' entry exists and running process was found: @processes_running");
return 1;
}
- elsif (!$computerloadlog_exists && $process_running) {
- notify($ERRORS{'WARNING'}, 0, "computerloadlog 'begin' entry does NOT exist but running process was found, returning 1");
+ elsif (!$computerloadlog_exists && @processes_running) {
+ notify($ERRORS{'WARNING'}, 0, "computerloadlog 'begin' entry does NOT exist but running process was found: @processes_running, assuming reservation is currently being processed");
return 1;
}
- elsif ($computerloadlog_exists && !$process_running) {
- notify($ERRORS{'WARNING'}, 0, "computerloadlog 'begin' entry exists but running process was NOT found, returning 0");
+ elsif ($computerloadlog_exists && !@processes_running) {
+ notify($ERRORS{'WARNING'}, 0, "computerloadlog 'begin' entry exists but running process was NOT found, assuming reservation is NOT currently being processed");
return 0;
}
else {
@@ -9115,28 +9000,46 @@ sub is_management_node_process_running {
return;
}
- my @pids;
- my $command = "pgrep -fl \"$process_identifier\"";
- my ($exit_status, $output) = run_command($command, 1);
- my @filtered_output;
- @filtered_output = grep(!/sh -c/, @$output) if @$output;
- if (@filtered_output) {
- notify($ERRORS{'DEBUG'}, 0, "process is running, identifier: $process_identifier, pgrep output:\n" . join("\n", @filtered_output));
+ my $command = "pgrep -fl '$process_identifier'";
+ my ($exit_status, $output) = run_command($command, 0);
+ if (!defined($output)) {
+ notify($ERRORS{'WARNING'}, 0, "failed to run command to determine if process is running: $command");
+ return;
+ }
+
+ my @processes_running;
+ for my $line (@$output) {
+ my ($pid) = $line =~ /^(\d+)/;
- for my $pgrep_line (@filtered_output) {
- my ($pid) = $pgrep_line =~ /^(\d+)/;
- push @pids, $pid;
+ if (!defined($pid)) {
+ notify($ERRORS{'DEBUG'}, 0, "ignoring pgrep output line, it does not begin with a number: $line");
+ next;
+ }
+ elsif ($pid eq $PID) {
+ notify($ERRORS{'DEBUG'}, 0, "ignoring pgrep output line for the currently running process: $line");
+ next;
+ }
+ elsif ($line =~ /pgrep -fl/) {
+ notify($ERRORS{'DEBUG'}, 0, "ignoring pgrep output line containing for pgrep command: $line");
+ next;
+ }
+ elsif ($line =~ /sh -c/) {
+ # Ignore lines containing 'sh -c', probably indicating a duplicate process of a command run remotely
+ notify($ERRORS{'DEBUG'}, 0, "ignoring pgrep output line containing 'sh -c': $line");
+ next;
+ }
+ else {
+ notify($ERRORS{'DEBUG'}, 0, "found matching process: $line");
+ push @processes_running, $pid;
}
-
- notify($ERRORS{'DEBUG'}, 0, "returning pid array: @pids");
- return @pids;
}
- elsif (defined($exit_status)) {
- notify($ERRORS{'DEBUG'}, 0, "process is NOT running, identifier: $process_identifier, pgrep output:\n" . join("\n", @$output));
- return ();
+
+ if (@processes_running) {
+ notify($ERRORS{'DEBUG'}, 0, "process is running, identifier: '$process_identifier', returning array containing PIDs: @processes_running");
+ return @processes_running;
}
else {
- notify($ERRORS{'WARNING'}, 0, "failed to run command to determine if process is running");
+ notify($ERRORS{'DEBUG'}, 0, "process is NOT running, identifier: '$process_identifier'");
return;
}
}