Author: eelco
Date: Tue Jun 21 16:46:18 2011
New Revision: 27513
URL: https://svn.nixos.org/websvn/nix/?rev=27513&sc=1

Log:
* Support EC2 (Nova) machines that are only reachable via IPv6.
* After starting an instance, wait until its reachable via SSH.

Modified:
   cloud/trunk/src/nixos-deploy-network.pl

Modified: cloud/trunk/src/nixos-deploy-network.pl
==============================================================================
--- cloud/trunk/src/nixos-deploy-network.pl     Tue Jun 21 11:47:09 2011        
(r27512)
+++ cloud/trunk/src/nixos-deploy-network.pl     Tue Jun 21 16:46:18 2011        
(r27513)
@@ -1,4 +1,4 @@
-#! /var/run/current-system/sw/bin/perl -w
+#! /var/run/current-system/sw/bin/perl -w 
-I/home/eelco/nixpkgs/Net-Amazon-EC2-0.14/lib
 
 use strict;
 use utf8;
@@ -42,6 +42,8 @@
 # specification.
 my $killObsolete = 0;
 
+my $debug = 0;
+
 
 sub main {
     my $op;
@@ -53,6 +55,7 @@
         "destroy" => sub { $op = \&opDestroy; },
         "deploy" => sub { $op = \&opDeploy; },
         "kill-obsolete|k!" => \$killObsolete,
+        "debug" => \$debug,
         );
 
     die "$0: You must specify an operation.\n" unless defined $op;
@@ -79,7 +82,9 @@
                   ? ($r->{vmsPath} eq $state->{vmsPath}
                      ? "Up"
                      : "Incomplete")
-                  : "Started")
+                  : defined $r->{pinged}
+                     ? "Started"
+                     : "Starting")
                : "New")
             : "Obsolete";
         push @lines,
@@ -106,6 +111,25 @@
 }
 
 
+# Figure out how to connect to a machine via SSH.  Use the public IPv6
+# address if available, then the public IPv4 address, and then the
+# host name.
+sub sshName {
+    my ($name, $machine) = @_;
+    return $machine->{ipv6} || $machine->{ipv4} || $machine->{targetHost} || 
die "don't know how to reach ‘$name’";
+}
+
+
+# Check whether the given machine is reachable via SSH.
+sub pingSSH {
+    my ($name, $machine) = @_;
+    my $sshName = sshName($name, $machine);
+    # !!! fix, just check whether the port is open
+    system "ssh -o StrictHostKeyChecking=no root\@$sshName true < /dev/null 
2>/dev/null";
+    return $? == 0;
+}
+
+
 # ‘--check’ checks whether every machine is reachable via SSH.  It
 # also prints the load on every machine.
 sub opCheck {
@@ -116,7 +140,8 @@
         next if $machine->{obsolete};
         print STDERR "$name... ";
 
-        my $load = `ssh -o StrictHostKeyChecking=no root\@$machine->{sshName} 
cat /proc/loadavg 2>/dev/null`;
+        my $sshName = sshName($name, $machine);
+        my $load = `ssh -o StrictHostKeyChecking=no root\@$sshName cat 
/proc/loadavg 2>/dev/null`;
         if ($? == 0) {
             my @load = split / /, $load;
             print STDERR "ok [$load[0] $load[1] $load[2]]\n";
@@ -229,11 +254,11 @@
 sub openEC2 {
     my ($name, $machine) = @_;
     return Net::Amazon::EC2->new
-        ( AWSAccessKeyId => ($ENV{'AWS_ACCESS_KEY_ID'} || die "please set 
\$AWS_ACCESS_KEY_ID\n")
-        , SecretAccessKey => ($ENV{'AWS_SECRET_ACCESS_KEY'} || die "please set 
\$AWS_SECRET_ACCESS_KEY\n")
+        ( AWSAccessKeyId => ($ENV{'EC2_ACCESS_KEY'} || 
$ENV{'AWS_ACCESS_KEY_ID'} || die "please set \$EC2_ACCESS_KEY or 
\$AWS_ACCESS_KEY_ID\n")
+        , SecretAccessKey => ($ENV{'EC2_SECRET_KEY'} || 
$ENV{'AWS_SECRET_ACCESS_KEY'} || die "please set \$EC2_SECRET_KEY or 
\$AWS_SECRET_ACCESS_KEY\n")
         , # !!! This assumes that all machines have the same controller/zone.
           base_url => $machine->{ec2}->{controller}
-        #, debug => 1
+        , debug => $debug
         );
 }
 
@@ -298,12 +323,6 @@
         if ($machine->{targetEnv} eq "none") {
             # Not much to do here.
 
-            print STDERR "checking whether machine ‘$name’ is reachable via 
SSH...\n";
-
-            # !!! should use sshName.
-            system "ssh -o StrictHostKeyChecking=no 
root\@$machine->{targetHost} true < /dev/null 2> /dev/null";
-            die "cannot SSH to machine: $?" unless $? == 0;
-
             $state->{machines}->{$name} =
                 { targetEnv => $machine->{targetEnv}
                 , targetHost => $machine->{targetHost}
@@ -373,14 +392,13 @@
             # have finished booting, but later down we wait for the
             # SSH port to open.)
             print STDERR "waiting for IP address... ";
-            my $n = 0;
             while (1) {
                 my $state = $instance->instance_state->name;
                 print STDERR "[$state] ";
                 die "EC2 instance ‘$vmId’ didn't start; it went to state 
‘$state’\n"
                     if $state ne "pending" && $state ne "running" &&
                        $state ne "scheduling" && $state ne "launching";
-                last if defined $instance->ip_address;
+                last if defined $instance->dns_name_v6 || defined 
$instance->ip_address;
                 sleep 5;
                 my $reservations = $ec2->describe_instances(InstanceId => 
$vmId);
                 die "could not query EC2 instance: “" . 
@{$reservations->errors}[0]->message . "”\n"
@@ -389,13 +407,11 @@
             }
             print STDERR "\n";
 
-            my $ipv4 = $instance->ip_address;
-            print STDERR "got IP address ‘$ipv4’\n";
-                
             $state->{machines}->{$name} =
                 { targetEnv => $machine->{targetEnv}
                 , vmId => $vmId
-                , ipv4 => $ipv4
+                , ipv4 => $instance->ip_address
+                , ipv6 => $instance->dns_name_v6 # actually its public IPv6 
address
                 , reservation => $reservation->reservation_id
                 , privateIpv4 => $instance->private_ip_address
                 , dnsName => $instance->dns_name
@@ -404,12 +420,10 @@
                 , ec2 => $machine->{ec2}
                 };
 
-            writeState;
-            
-            print STDERR "checking whether VM ‘$name’ is reachable via 
SSH...\n";
-
-            system "ssh -o StrictHostKeyChecking=no root\@$ipv4 true < 
/dev/null 2> /dev/null";
-            die "cannot SSH to VM: $?" unless $? == 0;
+            my $addr = $instance->dns_name_v6 || $instance->ip_address || die 
"don't know how to reach ‘$name’";
+            print STDERR "started instance with IP address $addr\n";
+                
+            writeState;            
         }
     }
 
@@ -428,10 +442,21 @@
         }
     }
     
-    # Figure out how we're gonna SSH to each machine.  Prefer IPv6
-    # addresses over hostnames.
-    while (my ($name, $machine) = each %{$state->{machines}}) {
-        $machine->{sshName} = $machine->{ipv6} || $machine->{ipv4} || 
$machine->{targetHost} || die "don't know how to reach ‘$name’";
+    foreach my $name (keys %{$spec->{machines}}) {
+        my $machine = $state->{machines}->{$name};
+        unless (defined $machine->{pinged}) {
+            print STDERR "checking whether machine ‘$name’ is reachable via 
SSH...";
+            my $n = 0;
+            while (1) {
+                last if pingSSH($name, $machine);
+                print STDERR ".";
+                die "machine ‘$name’ cannot be reached via SSH" if $n++ == 40;
+                sleep 5;
+            }
+            print STDERR " yes\n";
+            $machine->{pinged} = 1;
+            writeState;
+        }
     }
     
     # So now that we know the hostnames / IP addresses of all
@@ -441,8 +466,8 @@
     my $hosts = "";
     foreach my $name (keys %{$spec->{machines}}) {
         my $machine = $state->{machines}->{$name};
-        $hosts .= "$machine->{ipv6} $name\\n" if defined $machine->{ipv6};
-        $hosts .= "$machine->{ipv4} $name\\n" if defined $machine->{ipv4};
+        $hosts .= "$machine->{ipv6} $name\\n" if $machine->{ipv6};
+        $hosts .= "$machine->{ipv4} $name\\n" if $machine->{ipv4};
     }
     
     open STATE, ">physical.nix" or die;
@@ -487,7 +512,8 @@
         my $machine = $state->{machines}->{$name};
         my $toplevel = readlink "$vmsPath/$name" or die;
         $machine->{lastCopied} = $toplevel; # !!! rewrite state file?
-        system "nix-copy-closure --gzip --to root\@$machine->{sshName} 
$toplevel";
+        my $sshName = sshName($name, $machine);
+        system "nix-copy-closure --gzip --to root\@$sshName $toplevel";
         die "unable to copy closure to machine ‘$name’" unless $? == 0;
     }
 }
@@ -506,7 +532,8 @@
         my $machine = $state->{machines}->{$name};
 
         my $toplevel = readlink "$vmsPath/$name" or die;
-        system "ssh -o StrictHostKeyChecking=no root\@$machine->{sshName} 
nix-env -p /nix/var/nix/profiles/system --set $toplevel \\; 
/nix/var/nix/profiles/system/bin/switch-to-configuration switch";
+        my $sshName = sshName($name, $machine);
+        system "ssh -o StrictHostKeyChecking=no root\@$sshName nix-env -p 
/nix/var/nix/profiles/system --set $toplevel \\; 
/nix/var/nix/profiles/system/bin/switch-to-configuration switch";
         if ($? != 0) {
             # !!! do a rollback
             die "unable to activate new configuration on machine ‘$name’";
_______________________________________________
nix-commits mailing list
[email protected]
http://mail.cs.uu.nl/mailman/listinfo/nix-commits

Reply via email to