[Bps-public-commit] r15771 - Shipwright/trunk/bin

alexmv at bestpractical.com alexmv at bestpractical.com
Thu Sep 4 20:18:50 EDT 2008


Author: alexmv
Date: Thu Sep  4 20:18:27 2008
New Revision: 15771

Added:
   Shipwright/trunk/bin/jeos-build   (contents, props changed)

Log:
 * Add JEOS build system to creating JEOS images from a vessel

Added: Shipwright/trunk/bin/jeos-build
==============================================================================
--- (empty file)
+++ Shipwright/trunk/bin/jeos-build	Thu Sep  4 20:18:27 2008
@@ -0,0 +1,354 @@
+#!/usr/bin/perl
+use strict;
+use warnings;
+use File::Slurp;
+use File::Temp qw/tempdir/;
+
+use Getopt::Long;
+
+my ($image, $store, $vessel, $base, $flags, $skiptest, $partial, $rcfile);
+GetOptions(
+    "image=s" => \$image,
+    "store=s" => \$store,
+    "vessel=s" => \$vessel,
+    "base=s" => \$base,
+    "flags=s" => \$flags,
+    "skip-test" => \$skiptest,
+    "partial" => \$partial,
+    "rcfile=s" => \$rcfile,
+) or die "Option parsing failure";
+
+die "No image specified" unless $image;
+my @datastores = VMware::Vix::Host->datastore;
+$store = $datastores[0] if @datastores == 1 and not $store;
+die "No datastore specified, and can't intuit it" unless $store;
+die "No vessel specified" unless $vessel;
+$base = $image . "-base" unless $base;
+$flags = "--flags $flags" if $flags;
+$skiptest = $skiptest ? "--skip-test" : "";
+
+my $passwd = read_file('.passwd');
+chomp $passwd;
+
+# Connect to the host
+my $host = VMware::Vix::Host->new( password => $passwd )
+    or die VMware::Vix::Host->error;
+
+# Connect to VM
+my $vm = $host->open( store => $store, name => $image )
+    or die VMware::Vix::Host->error;
+die "VM is @{[$vm->power_state]}!\n" if $vm->power_state ne "powered off";
+
+# Find the path to the store
+my $path = $host->datastore($store);
+die "Can't find store $store" unless $path;
+
+# Explode if either path is mounted
+my $mounted = qx(/usr/bin/vmware-mount -L);
+die "Disk is already mounted; please unmount before continuing.\n"
+    if $mounted =~ m{$path/($image|$base)};
+
+# Clone from image if base doesn't exist
+unless ( -e "$path/$base" ) {
+    unless ( -e "$path/$image" ) {
+        die "Can't find image in $path/$image to clone from";
+    }
+    !system( '/usr/bin/rsync', "-az", "$path/$image/", "$path/$base/" )
+        or die "rsync failed";
+}
+
+unless ($partial) {
+    # Rsync to clean it up
+    warn "Cloning image...\n";
+    !system(
+        '/usr/bin/rsync',   "-az", "--delete",
+        "$path/$base/", "$path/$image/"
+    ) or die "rsync failed";
+}
+
+# Mount the disk image
+my $mountpoint = "disk-image";
+$vm->mount($mountpoint);
+
+# Copy files over
+warn "Installing source...\n";
+system( '/usr/bin/rm', '-rf', "$mountpoint/opt/build", "$mountpoint/opt/install" )
+    if $partial;
+!system( '/usr/bin/svn', 'co', '-q', $vessel, "$mountpoint/opt/build" )
+    or die "svn co failed";
+
+# Write init file
+open( RC, ">", "$mountpoint/etc/rc.local" ) or die "Can't write rc.init: $!";
+print RC <<EOT;
+#!/bin/sh
+aptitude install build-essential autoconf libtool -y
+cd /opt/build/
+export CFLAGS="-ggdb -g3"
+./bin/shipwright-builder --install-base /opt/install $flags $skiptest 2>&1 | tee /opt/build/complete.log 
+halt
+EOT
+close RC;
+
+# Unmount
+$vm->unmount;
+
+# Start 'er up!
+warn "Starting build...\n";
+$vm->power_on;
+
+# Wait for it to finish
+my $laststate = "";
+{
+    sleep 10;
+    my $state = $vm->power_state;
+    warn ucfirst($state) . "...\n" if $laststate ne $state;
+    $laststate = $state;
+    redo unless $state =~ "powered off";
+}
+sleep 10;
+
+# Check if it succeeded
+$vm->mount($mountpoint);
+!system( "cp", "$mountpoint/opt/build/complete.log", "complete.log" )
+    or warn "(Copy of log failed?)\n";
+!system( 'cp', $rcfile, "$mountpoint/etc/rc.local" )
+    or warn "(Copy of rc.local failed?)\n" if $rcfile;
+die "Build failure!  See complete.log\n"
+    unless -e "$mountpoint/opt/install/bin-wrapped";
+
+# If we want a partial build, don't clone into a clean image, just
+# stop now
+exit if $partial;
+
+# Copy out of the image
+warn "Successfully built!  Copying out of image...\n";
+!system(
+    "/usr/bin/rsync", "-az",
+    "--delete",       "$mountpoint/opt/install/",
+    "installed-image/"
+) or die "rsync extract failed";
+$vm->unmount;
+
+# Rsync a clean copy over
+warn "Cloning a clean image...\n";
+!system(
+    "/usr/bin/rsync",   "-az", "--delete",
+    "$path/$base/", "$path/$image/"
+) or die "rsync failed";
+
+# Mount it again, and copy the built version
+warn "Installing binaries...\n";
+$vm->mount($mountpoint);
+!system(
+    "/usr/bin/rsync", "-az",
+    "installed-image/", "$mountpoint/opt/shipwright/"
+) or die "rsync placement failed";
+!system( 'cp', $rcfile, "$mountpoint/etc/rc.local" )
+    or die "run rc.init copy failed" if $rcfile;
+
+# Unmount
+$vm->unmount;
+
+# Snapshot in a clean state, then power it on to take it for a test ride
+$vm->power_on;
+warn "Image started!\n";
+
+
+package VMware::Vix::Host;
+use VMware::Vix::Simple;
+use VMware::Vix::API::Constants;
+use Carp;
+
+use XML::Simple;
+our %DATASTORES;
+
+BEGIN {
+    my $stores
+        = XMLin( "/etc/vmware/hostd/datastores.xml", ForceArray => ["e"] );
+    if ($stores) {
+        for my $k ( keys %{ $stores->{LocalDatastores}{e} } ) {
+            $DATASTORES{$k} = $stores->{LocalDatastores}{e}{$k}{path};
+        }
+    }
+}
+
+sub new {
+    my $class = shift;
+    my %args  = @_;
+    my ( $err, $hostHandle ) = HostConnect( VIX_API_VERSION,
+        VIX_SERVICEPROVIDER_VMWARE_VI_SERVER,
+        $args{host} || "https://localhost:8333/sdk",
+        0,
+        $args{user} || $ENV{USER},
+        $args{password},
+        0,
+        VIX_INVALID_HANDLE
+    );
+    croak "VMware::Vix::Host->new: " . GetErrorText($err) if $err != VIX_OK;
+    return bless \$hostHandle, $class;
+}
+
+sub vms {
+    my $self = shift;
+    my ( $err, @vms ) = FindItems( $$self, VIX_FIND_REGISTERED_VMS, 0 );
+    croak "VMware::Vix::Host->vms: " . GetErrorText($err) if $err != VIX_OK;
+    return @vms;
+}
+
+sub open {
+    my $self = shift;
+    return VMware::Vix::VM->new( @_, host => $self );
+}
+
+sub disconnect {
+    my $self = shift;
+    HostDisconnect($$self);
+}
+
+sub datastore {
+    my $class = shift;
+    return keys %DATASTORES unless @_;
+    my $name  = shift;
+    return $DATASTORES{$name};
+}
+
+sub DESTROY {
+    shift->disconnect;
+}
+
+package VMware::Vix::VM;
+use VMware::Vix::Simple;
+use VMware::Vix::API::Constants;
+use Scalar::Util qw/dualvar/;
+use Carp;
+
+our %PROPERTY;
+our %POWERSTATE;
+our %MOUNTS;
+
+BEGIN {
+    %PROPERTY = (
+        power_state   => VIX_PROPERTY_VM_POWER_STATE,
+        pathname      => VIX_PROPERTY_VM_VMX_PATHNAME,
+        team_pathname => VIX_PROPERTY_VM_VMTEAM_PATHNAME,
+    );
+    %POWERSTATE = (
+        VIX_POWERSTATE_POWERING_OFF()   => "powering off",
+        VIX_POWERSTATE_POWERED_OFF()    => "powered off",
+        VIX_POWERSTATE_POWERING_ON()    => "powering on",
+        VIX_POWERSTATE_POWERED_ON()     => "powered on",
+        VIX_POWERSTATE_SUSPENDING()     => "suspending",
+        VIX_POWERSTATE_SUSPENDED()      => "suspended",
+        VIX_POWERSTATE_TOOLS_RUNNING()  => "tools running",
+        VIX_POWERSTATE_RESETTING()      => "resetting",
+        VIX_POWERSTATE_BLOCKED_ON_MSG() => "blocked on message",
+        VIX_POWERSTATE_PAUSED()         => "paused",
+#       0x0400                          ,  "??",
+        VIX_POWERSTATE_RESUMING()       => "resuming",
+    );
+}
+
+sub new {
+    my $class = shift;
+    my %args  = @_;
+    croak "No host given"
+        unless $args{host} and $args{host}->isa("VMware::Vix::Host");
+    if ( $args{image} ) {
+    } elsif ( $args{store} and ( $args{path} || $args{name} ) ) {
+        croak "Datastore $args{store} not known" unless $args{host}->datastore( $args{store} );
+        $args{image}
+            = $args{path}
+            ? "[$args{store}] $args{path}"
+            : "[$args{store}] $args{name}/$args{name}.vmx";
+    } else {
+        croak "Must specify either an 'image' or a 'store' and 'path'";
+    }
+    my ( $err, $vmHandle ) = VMOpen( ${ $args{host} }, $args{image} );
+    croak "VMware::Vix::VM->new: " . GetErrorText($err) if $err != VIX_OK;
+    return bless \$vmHandle, $class;
+}
+
+sub get_property {
+    my $self = shift;
+    my %args = @_;
+    croak "No name provided" unless $args{name};
+    croak "No lookup value for $args{name}"
+        unless exists $PROPERTY{ $args{name} };
+    my ( $err, $value ) = GetProperties( $$self, $PROPERTY{ $args{name} } );
+    croak "VMware::Vix::VM->get_property: " . GetErrorText($err)
+        if $err != VIX_OK;
+    return $value;
+}
+
+sub power_state {
+    my $self = shift;
+    my $num = $self->get_property( name => "power_state" );
+    my @flags
+        = map { $POWERSTATE{$_} } grep { $num & $_ } sort {$a <=> $b} keys %POWERSTATE;
+    return dualvar( $num, join( ", ", @flags ) || "??" );
+}
+
+sub power_on {
+    my $self = shift;
+    my %args = @_;
+    my $err  = VMPowerOn( $$self, VIX_VMPOWEROP_NORMAL, VIX_INVALID_HANDLE );
+    croak "VMware::Vix::VM->power_on: " . GetErrorText($err)
+        if $err != VIX_OK;
+    return 1;
+}
+
+sub absolute {
+    my $self = shift;
+    my $path = shift;
+    $path =~ s{^\[(.*?)\] }{VMware::Vix::Host->datastore($1)."/"}e and defined VMware::Vix::Host->datastore($1)
+        or return undef;
+    return $path;
+}
+
+sub path {
+    my $self = shift;
+    return $self->get_property( name => "pathname" );
+}
+
+sub disk {
+    my $self = shift;
+    my $path = $self->get_property( name => "pathname" );
+    $path =~ s/\.vmx$/.vmdk/;
+    return $path;
+}
+
+sub mount {
+    my $self = shift;
+    my $path = shift;
+    !system( '/usr/bin/vmware-mount', $self->absolute( $self->disk ), $path )
+        or croak "mount failed: $@";
+    $MOUNTS{"$self"} = $path;
+    return 1;
+}
+
+sub unmount {
+    my $self = shift;
+    return unless $MOUNTS{"$self"};
+    !system( '/usr/bin/vmware-mount', '-d', delete $MOUNTS{"$self"} )
+        or croak "unmount failed: $@";
+    return 1;
+}
+
+sub snapshot {
+    my $self = shift;
+    my ( $err, $snapHandle ) = VMCreateSnapshot(
+        $$self,
+        undef,    # name
+        undef,    #description
+        VIX_SNAPSHOT_INCLUDE_MEMORY,
+        VIX_INVALID_HANDLE
+    );
+    croak "VMware::Vix::VM->snapshot: " . GetErrorText($err)
+        if $err != VIX_OK;
+    return $snapHandle;
+}
+
+DESTROY {
+    my $self = shift;
+    $self->unmount;
+}



More information about the Bps-public-commit mailing list