/************************************************************************* * Copyright 2009-2014 Eucalyptus Systems, Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 3 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see http://www.gnu.org/licenses/. * * Please contact Eucalyptus Systems, Inc., 6755 Hollister Ave., Goleta * CA 93117, USA or visit http://www.eucalyptus.com/licenses/ if you need * additional information or have any questions. * * This file may incorporate work covered under the following copyright * and permission notice: * * Software License Agreement (BSD License) * * Copyright (c) 2008, Regents of the University of California * All rights reserved. * * Redistribution and use of this software in source and binary forms, * with or without modification, are permitted provided that the * following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. USERS OF THIS SOFTWARE ACKNOWLEDGE * THE POSSIBLE PRESENCE OF OTHER OPEN SOURCE LICENSED MATERIAL, * COPYRIGHTED MATERIAL OR PATENTED MATERIAL IN THIS SOFTWARE, * AND IF ANY SUCH MATERIAL IS DISCOVERED THE PARTY DISCOVERING * IT MAY INFORM DR. RICH WOLSKI AT THE UNIVERSITY OF CALIFORNIA, * SANTA BARBARA WHO WILL THEN ASCERTAIN THE MOST APPROPRIATE REMEDY, * WHICH IN THE REGENTS' DISCRETION MAY INCLUDE, WITHOUT LIMITATION, * REPLACEMENT OF THE CODE SO IDENTIFIED, LICENSING OF THE CODE SO * IDENTIFIED, OR WITHDRAWAL OF THE CODE CAPABILITY TO THE EXTENT * NEEDED TO COMPLY WITH ANY SUCH LICENSES OR RIGHTS. ************************************************************************/ package com.eucalyptus.images; import java.security.PublicKey; import java.util.NoSuchElementException; import javax.annotation.Nonnull; import javax.persistence.EntityTransaction; import javax.persistence.PersistenceException; import com.eucalyptus.compute.common.internal.images.BlockStorageImageInfo; import com.eucalyptus.compute.common.internal.images.BootableImageInfo; import com.eucalyptus.compute.common.internal.images.ImageInfo; import com.eucalyptus.compute.common.internal.images.KernelImageInfo; import com.eucalyptus.compute.common.internal.images.MachineImageInfo; import com.eucalyptus.compute.common.internal.images.RamdiskImageInfo; import com.eucalyptus.compute.common.internal.util.NoSuchImageIdException; import org.apache.log4j.Logger; import com.eucalyptus.compute.common.CloudMetadatas; import com.eucalyptus.compute.common.ImageMetadata; import com.eucalyptus.compute.common.ImageMetadata.Platform; import com.eucalyptus.compute.common.RunInstancesType; import com.eucalyptus.compute.common.StaticDiskImage; import com.eucalyptus.compute.common.internal.util.IllegalMetadataAccessException; import com.eucalyptus.compute.common.internal.util.InvalidMetadataException; import com.eucalyptus.compute.common.internal.util.MetadataException; import com.eucalyptus.compute.common.internal.util.NoSuchMetadataException; import com.eucalyptus.component.Partition; import com.eucalyptus.context.Context; import com.eucalyptus.context.Contexts; import com.eucalyptus.context.IllegalContextAccessException; import com.eucalyptus.entities.Entities; import com.eucalyptus.imaging.manifest.BundleImageManifest; import com.eucalyptus.imaging.manifest.DownloadManifestFactory; import com.eucalyptus.imaging.manifest.ImageManifestFile; import com.eucalyptus.records.Logs; import com.eucalyptus.util.EucalyptusCloudException; import com.eucalyptus.util.Exceptions; import com.eucalyptus.util.NonNullFunction; import com.eucalyptus.util.RestrictedTypes; import com.eucalyptus.util.RestrictedTypes.Resolver; import com.eucalyptus.compute.common.internal.vm.VmInstance; import com.eucalyptus.compute.common.internal.vmtypes.VmType; import com.eucalyptus.vmtypes.VmTypes; import com.google.common.base.Function; import com.google.common.base.Functions; import com.google.common.base.Preconditions; import com.google.common.base.Predicate; import com.google.common.base.Predicates; import com.google.common.base.Strings; import com.eucalyptus.cluster.common.msgs.VmTypeInfo; public class Emis { private static Logger LOG = Logger.getLogger( Emis.class ); enum VBRTypes { MACHINE( "objectstorage://" ), EBS, KERNEL( "objectstorage://" ), RAMDISK( "objectstorage://" ), EPHEMERAL, SWAP; String prefix; private VBRTypes( ) { this( "" ); } private VBRTypes( final String prefix ) { this.prefix = prefix; } } @Resolver( ImageMetadata.class ) public enum LookupImage implements Function<String, ImageInfo> { INSTANCE; @Override public ImageInfo apply( final String input ) { if ( CloudMetadatas.isKernelImageIdentifier( input ) ) { return LookupKernel.INSTANCE.apply( input ); } else if ( CloudMetadatas.isRamdiskImageIdentifier( input ) ) { return LookupRamdisk.INSTANCE.apply( input ); } else if ( CloudMetadatas.isMachineImageIdentifier( input ) ) { try { return LookupMachine.INSTANCE.apply( input ); } catch ( final Exception ex ) { return LookupAvailableBlockStorage.INSTANCE.apply( input ); } } else { throw new NoSuchElementException( "Failed to lookup image: " + input ); } } } public enum LookupBlockStorage implements Function<String, BlockStorageImageInfo> { INSTANCE; @Override public BlockStorageImageInfo apply( final String identifier ) { final EntityTransaction db = Entities.get( BlockStorageImageInfo.class ); try { final BlockStorageImageInfo ret = Entities.uniqueResult( Images.exampleBlockStorageWithImageId( identifier ) ); if ( Platform.windows.name( ).equals( ret.getKernelId( ) ) || ret.getImageName( ).startsWith( Platform.windows.name( ) ) ) { ret.setPlatform( Platform.windows ); } db.rollback( ); return ret; } catch ( final Exception ex ) { Logs.exhaust( ).error( ex, ex ); db.rollback( ); throw new NoSuchElementException( "Failed to lookup image: " + identifier + " because of " + ex.getMessage( ) ); } } } public enum LookupAvailableBlockStorage implements Function<String, BlockStorageImageInfo> { INSTANCE; @Override public BlockStorageImageInfo apply( final String identifier ) { final EntityTransaction db = Entities.get( BlockStorageImageInfo.class ); try { final BlockStorageImageInfo ret = Entities.uniqueResult( Images.exampleBlockStorageWithImageId( identifier ) ); if ( Platform.windows.name( ).equals( ret.getKernelId( ) ) || ret.getImageName( ).startsWith( Platform.windows.name( ) ) ) { ret.setPlatform( Platform.windows ); } if ( !ImageMetadata.State.available.equals( ret.getState( )) && !ImageMetadata.State.pending.equals( ret.getState( )) ) { db.rollback( ); throw new NoSuchElementException( "Unable to start instance with deregistered/failed image : " + ret ); } else { db.rollback( ); return ret; } } catch ( final Exception ex ) { Logs.exhaust( ).error( ex, ex ); db.rollback( ); throw new NoSuchElementException( "Failed to lookup image: " + identifier + " because of " + ex.getMessage( ) ); } } } public enum LookupMachine implements NonNullFunction<String, MachineImageInfo> { INSTANCE; @Nonnull @Override public MachineImageInfo apply( final String identifier ) { final EntityTransaction db = Entities.get( MachineImageInfo.class ); try { final MachineImageInfo ret = Entities.uniqueResult( Images.exampleMachineWithImageId( identifier ) ); if ( !ImageMetadata.State.available.name().equals( ret.getState( ).getExternalStateName() ) ) { db.rollback( ); throw new NoSuchElementException( "Unable to start instance with deregistered/failed image : " + ret ); } else { db.rollback( ); return ret; } } catch ( final Exception ex ) { Logs.exhaust( ).error( ex, ex ); db.rollback( ); throw new NoSuchElementException( "Failed to lookup image: " + identifier + " because of " + ex.getMessage( ) ); } } } public enum LookupKernel implements NonNullFunction<String, KernelImageInfo> { INSTANCE; @Nonnull @Override public KernelImageInfo apply( final String identifier ) { final EntityTransaction db = Entities.get( KernelImageInfo.class ); try { final KernelImageInfo ret = Entities.uniqueResult( Images.exampleKernelWithImageId( identifier ) ); if ( !ImageMetadata.State.available.name().equals( ret.getState( ).getExternalStateName() ) ) { db.rollback( ); throw new NoSuchElementException( "Unable to start instance with deregistered/failed image : " + ret ); } else { db.rollback( ); return ret; } } catch ( final Exception ex ) { Logs.exhaust( ).error( ex, ex ); db.rollback( ); throw new NoSuchElementException( "Failed to lookup image: " + identifier + " because of " + ex.getMessage( ) ); } } } public enum LookupRamdisk implements NonNullFunction<String, RamdiskImageInfo> { INSTANCE; @Nonnull @Override public RamdiskImageInfo apply( final String identifier ) { final EntityTransaction db = Entities.get( RamdiskImageInfo.class ); try { final RamdiskImageInfo ret = Entities.uniqueResult( Images.exampleRamdiskWithImageId( identifier ) ); if ( !ImageMetadata.State.available.name().equals( ret.getState( ).getExternalStateName() ) ) { db.rollback( ); throw new NoSuchElementException( "Unable to start instance with deregistered/failed image : " + ret ); } else { db.rollback( ); return ret; } } catch ( final Exception ex ) { Logs.exhaust( ).error( ex, ex ); db.rollback( ); throw new NoSuchElementException( "Failed to lookup image: " + identifier + " because of " + ex.getMessage( ) ); } } } public static class BootableSet { private final BootableImageInfo disk; private BootableSet( final BootableImageInfo bootableImageInfo ) { this.disk = bootableImageInfo; } public BootableImageInfo getMachine( ) { return this.disk; } public RamdiskImageInfo getRamdisk( ) { throw new NoSuchElementException( "BootableSet:machine=" + this.getMachine( ) + " does not have a ramdisk." ); } public KernelImageInfo getKernel( ) { throw new NoSuchElementException( "BootableSet:machine=" + this.getMachine( ) + " does not have a kernel." ); } public boolean hasKernel( ) { try { this.getKernel( ); return true; } catch ( final NoSuchElementException ex ) { return false; } } public boolean hasRamdisk( ) { try { this.getRamdisk( ); return true; } catch ( final NoSuchElementException ex ) { return false; } } public String getRamdiskDownloadManifest(PublicKey signingKey, String partitionName ) throws MetadataException { throw new NoSuchElementException( "BootableSet:machine=" + this.getMachine( ) + " does not have a ramdisk." ); } public String getKernelDownloadManifest(PublicKey signingKey, String partitionName ) throws MetadataException { throw new NoSuchElementException( "BootableSet:machine=" + this.getMachine( ) + " does not have a kernel." ); } public String getImageDownloadManifest(PublicKey signingKey, String partitionName) throws MetadataException { if(! (this.getMachine() instanceof StaticDiskImage)) { throw new NoSuchElementException("BootableSet:machine=" + this.getMachine() + " does not have a bundled-type image."); } StaticDiskImage img = (StaticDiskImage)this.getMachine(); try { if (!Strings.isNullOrEmpty(img.getManifestHash()) && !img.getManifestHash().equals( ImageManifests.getManifestHash(img.getManifestLocation()))) throw new MetadataException("Image manifest was changed after registration for: " + img.getDisplayName()); return DownloadManifestFactory.generateDownloadManifest( new ImageManifestFile(img.getManifestLocation(), BundleImageManifest.INSTANCE, ImageConfiguration.getInstance().getMaxManifestSizeBytes()), signingKey, img.getDisplayName() + "-" + partitionName, true); } catch (Exception ex){ throw new MetadataException(ex); } } public boolean isBlockStorage( ) { return this.getMachine( ) instanceof BlockStorageImageInfo; } public boolean isLinux( ) { return ImageMetadata.Platform.linux.equals( this.getMachine( ).getPlatform( ) ) || ( this.getMachine( ).getPlatform( ) == null ); } public boolean isHvm(){ return ImageMetadata.VirtualizationType.hvm.equals(this.getMachine().getVirtualizationType()); } @Override public String toString( ) { return String.format( "BootableSet:machine=%s:ramdisk=%s:kernel=%s:isLinux=%s", this.getMachine( ), this.hasRamdisk( ) ? this.getRamdisk( ) : "false", this.hasKernel( ) ? this.getKernel( ) : "false", this.isLinux( ) ); } public VmTypeInfo populateVirtualBootRecord( final VmType vmType, final Partition partition, final String reservationId) throws MetadataException { final VmTypeInfo vmTypeInfo = VmTypes.asVmTypeInfo( vmType, this.getMachine( ) ); try { if ( this.isLinux( ) ) { if ( this.hasKernel( ) ) { String manifestLocation = this.getKernelDownloadManifest(partition.getNodeCertificate().getPublicKey(), partition.getName()); vmTypeInfo.setKernel( this.getKernel().getDisplayName(), manifestLocation, this.getKernel( ).getImageSizeBytes() ); } if ( this.hasRamdisk( ) ) { String manifestLocation = this.getRamdiskDownloadManifest(partition.getNodeCertificate().getPublicKey(), partition.getName()); vmTypeInfo.setRamdisk( this.getRamdisk( ).getDisplayName( ), manifestLocation, this.getRamdisk( ).getImageSizeBytes() ); } } if ( this.getMachine( ) instanceof StaticDiskImage ) { // BootableImage+StaticDiskImage = MachineImageInfo StaticDiskImage diskImage = (StaticDiskImage) this.getMachine( ); if (!Strings.isNullOrEmpty( diskImage.getManifestHash() ) && !diskImage.getManifestHash().equals( ImageManifests.getManifestHash( diskImage.getManifestLocation() )) ) throw new MetadataException("Instance manifest was changed after registration"); String manifestLocation = this.getImageDownloadManifest(partition.getNodeCertificate().getPublicKey(), partition.getName()); vmTypeInfo.setRoot( diskImage.getDisplayName( ), manifestLocation, this.getMachine( ).getImageSizeBytes() ); } } catch (Exception ex){ throw new MetadataException(ex); } return vmTypeInfo; } } static class NoRamdiskBootableSet extends BootableSet { private final KernelImageInfo kernel; private NoRamdiskBootableSet( final BootableImageInfo bootableImageInfo, final KernelImageInfo kernel ) { super( bootableImageInfo ); this.kernel = kernel; } @Override public KernelImageInfo getKernel( ) { return this.kernel; } public String getKernelDownloadManifest(PublicKey signingKey, String partitionName) throws MetadataException { try { if (!Strings.isNullOrEmpty(this.kernel.getManifestHash()) && !kernel.getManifestHash().equals( ImageManifests.getManifestHash(this.kernel.getManifestLocation()))) throw new MetadataException("Image manifest was changed after registration for: " + this.kernel.getDisplayName()); return DownloadManifestFactory.generateDownloadManifest( new ImageManifestFile(this.kernel.getManifestLocation(), BundleImageManifest.INSTANCE, ImageConfiguration.getInstance().getMaxManifestSizeBytes()), signingKey, this.kernel.getDisplayName() + "-" + partitionName, true); } catch (Exception ex){ throw new MetadataException(ex); } } } static class TrifectaBootableSet extends NoRamdiskBootableSet { private final RamdiskImageInfo ramdisk; public TrifectaBootableSet( final BootableImageInfo bootableImageInfo, final KernelImageInfo kernel, final RamdiskImageInfo ramdisk ) { super( bootableImageInfo, kernel ); this.ramdisk = ramdisk; } @Override public RamdiskImageInfo getRamdisk( ) { return this.ramdisk; } public String getRamdiskDownloadManifest(PublicKey signingKey, String partitionName) throws MetadataException { try { if (!Strings.isNullOrEmpty(this.ramdisk.getManifestHash()) && !ramdisk.getManifestHash().equals( ImageManifests.getManifestHash(ramdisk.getManifestLocation()))) throw new MetadataException("Image manifest was changed after registration for: " + ramdisk.getDisplayName()); return DownloadManifestFactory.generateDownloadManifest( new ImageManifestFile(ramdisk.getManifestLocation(), BundleImageManifest.INSTANCE, ImageConfiguration.getInstance().getMaxManifestSizeBytes()), signingKey, this.ramdisk.getDisplayName() + "-" + partitionName, true); } catch (Exception ex){ throw new MetadataException(ex); } } } public static BootableSet recreateBootableSet( final VmInstance vm ) { final BootableImageInfo bootableImageInfo = vm.getBootRecord( ).getMachine( ); final KernelImageInfo kernel = vm.getBootRecord( ).getKernel( ); final RamdiskImageInfo ramdisk = vm.getBootRecord( ).getRamdisk( ); if ( ( kernel != null ) && ( ramdisk != null ) ) { return new TrifectaBootableSet( bootableImageInfo, kernel, ramdisk ); } else if ( kernel != null ) { return new NoRamdiskBootableSet( bootableImageInfo, kernel ); } else { return new BootableSet( bootableImageInfo ); } } public static BootableSet recreateBootableSet( final String imageId, final String kernelId, final String ramdiskId ) throws MetadataException { try { final BootsetBuilder builder = new BootsetBuilder( ).imageId( imageId ); if ( kernelId != null ) { builder.kernelId( kernelId ); if ( ramdiskId != null ) { builder.ramdiskId( ramdiskId ); } } return builder.start( ); } catch ( final MetadataException ex ) { throw ex; } catch ( final Exception ex ) { throw new InvalidMetadataException( "Failed to construct bootset for image id: " + imageId + " because of: " + ex.getMessage( ), ex ); } } public static BootableSet unavailableBootableSet( final Platform platform ) { return new BootableSet( new UnavailableImageInfo( platform ) ); } public static BootableSet newBootableSet( final String imageId ) throws MetadataException { try { return new BootsetBuilder( ).imageId( imageId ).run( ); } catch ( final MetadataException ex ) { throw ex; } catch ( final Exception ex ) { throw new InvalidMetadataException( "Failed to construct bootset for image id: " + imageId + " because of: " + ex.getMessage( ), ex ); } } private static class BootsetBuilder { private String imageId; private String kernelId; private String ramdiskId; public BootsetBuilder imageId( final String imageId ) { this.imageId = imageId; return this; } public BootsetBuilder ramdiskId( final String ramdiskId ) { this.ramdiskId = ramdiskId; return this; } public BootsetBuilder kernelId( final String kernelId ) { this.kernelId = kernelId; return this; } public BootableSet run( ) throws MetadataException { final Function<String, BootableSet> create = Functions.compose( BootsetWithRamdisk.INSTANCE, Functions.compose( BootsetWithKernel.INSTANCE, BootsetFromId.INSTANCE ) ); return this.prepareBootset( create ); } private BootableSet prepareBootset( final Function<String, BootableSet> create ) throws MetadataException { try { final BootableSet bootSet = create.apply( this.imageId ); return bootSet; } catch ( final RuntimeException ex ) { if ( ex.getCause( ) instanceof MetadataException ) { throw ( MetadataException ) ex.getCause( ); } else { throw ex; } } } public BootableSet start( ) throws MetadataException { final Function<String, BootableSet> create = new Function<String, BootableSet>( ) { @Override public BootableSet apply( final String input ) { final BootableSet b = BootsetFromId.INSTANCE.apply( BootsetBuilder.this.imageId ); try { final KernelImageInfo kernel = ( BootsetBuilder.this.kernelId == null ? null : LookupKernel.INSTANCE.apply( BootsetBuilder.this.kernelId ) ); final RamdiskImageInfo ramdisk = ( BootsetBuilder.this.ramdiskId == null ? null : LookupRamdisk.INSTANCE.apply( BootsetBuilder.this.ramdiskId ) ); if ( ( kernel != null ) && ( ramdisk != null ) ) { return new TrifectaBootableSet( b.getMachine( ), kernel, ramdisk ); } else if ( kernel != null ) { return new NoRamdiskBootableSet( b.getMachine( ), kernel ); } else { return b; } } catch ( NoSuchElementException e ) { throw Exceptions.toUndeclared( new NoSuchMetadataException( e.getMessage(), e ) ); } } }; return this.prepareBootset( create ); } } private static <T extends ImageInfo> T resolveDiskImage( final String imageId, final Function<String, T> resolver ) throws IllegalMetadataAccessException { final T img = resolver.apply( imageId ); if ( Contexts.exists( ) ) { final Predicate<T> filter = Predicates.and( Images.FilterPermissions.INSTANCE, RestrictedTypes.filterPrivilegedWithoutOwner( ) ); if ( filter.apply( img ) ) { if( ! Images.FilterImageStates.INSTANCE.apply( img )) throw Exceptions.toUndeclared(new EucalyptusCloudException("Image state is not available")); return img; } else { throw new IllegalMetadataAccessException( imageId + ": permission denied." ); } } else { return img; } } enum BootsetFromId implements Function<String, BootableSet> { INSTANCE; @Override public BootableSet apply( final String input ) { BootableSet bootSet; try { bootSet = new BootableSet( resolveDiskImage( input, LookupMachine.INSTANCE ) ); } catch ( final IllegalContextAccessException ex ) { throw Exceptions.toUndeclared( new IllegalMetadataAccessException( ex ) ); } catch ( final IllegalMetadataAccessException ex ) { throw Exceptions.toUndeclared( ex ); } catch ( final Exception e ) { try { bootSet = new BootableSet( resolveDiskImage( input, LookupAvailableBlockStorage.INSTANCE ) ); } catch ( final IllegalContextAccessException ex ) { throw Exceptions.toUndeclared( new IllegalMetadataAccessException( ex ) ); } catch ( final IllegalMetadataAccessException ex ) { throw Exceptions.toUndeclared( ex ); } catch ( final NoSuchElementException ex ) { throw Exceptions.toUndeclared( new NoSuchImageIdException( "Failed to lookup image named: " + input, ex ) ); } catch ( final PersistenceException ex ) { throw Exceptions.toUndeclared( new InvalidMetadataException( "Error occurred while trying to lookup image named: " + input, ex ) ); } } return bootSet; } } enum BootsetWithRamdisk implements Function<BootableSet, BootableSet> { INSTANCE; @Override public BootableSet apply( final BootableSet input ) { if ( !input.isLinux( ) || input.isHvm()) { return input; } else { String ramdiskId = null; try { ramdiskId = determineRamdiskId( input ); LOG.debug( "Determined the appropriate ramdiskId to be " + ramdiskId + " for " + input.toString( ) ); if ( ramdiskId == null ) { return input; } else { final RamdiskImageInfo ramdisk = RestrictedTypes.doPrivilegedWithoutOwner( ramdiskId, LookupRamdisk.INSTANCE ); return new TrifectaBootableSet( input.getMachine( ), input.getKernel( ), ramdisk ); } } catch ( final InvalidMetadataException ex ) { return input; } catch ( final Exception ex ) { if ( input.isBlockStorage( ) ) { return input; } else { throw Exceptions.toUndeclared( new NoSuchMetadataException( "Failed to lookup ramdisk image information: " + ramdiskId + " because of: " + ex.getMessage( ), ex ) ); } } } } } enum BootsetWithKernel implements Function<BootableSet, BootableSet> { INSTANCE; @Override public BootableSet apply( final BootableSet input ) { if ( !input.isLinux( ) || input.isHvm() ) { return input; } else { String kernelId = "unknown"; try { kernelId = determineKernelId( input ); LOG.debug( "Determined the appropriate kernelId to be " + kernelId + " for " + input.toString( ) ); final KernelImageInfo kernel = RestrictedTypes.doPrivilegedWithoutOwner( kernelId, LookupKernel.INSTANCE ); return new NoRamdiskBootableSet( input.getMachine( ), kernel ); } catch ( final Exception ex ) { if ( input.isBlockStorage( ) ) { return input; } else if (input.isHvm()) { return input; } else { throw Exceptions.toUndeclared( new NoSuchMetadataException( "Failed to lookup kernel image information " + kernelId + " because of: " + ex.getMessage( ), ex ) ); } } } } } private static String determineKernelId( final BootableSet bootSet ) throws MetadataException { final BootableImageInfo disk = bootSet.getMachine( ); String kernelId = null; Context ctx = null; try { ctx = Contexts.lookup( ); if ( ctx.getRequest( ) instanceof RunInstancesType ) { kernelId = ( ( RunInstancesType ) ctx.getRequest( ) ).getKernelId( ); } } catch ( final IllegalContextAccessException ex ) { LOG.debug( "Context not found when determining kernel id:" + ex.getMessage( ) ); } if ( ( kernelId == null ) || "".equals( kernelId ) ) { kernelId = disk.getKernelId( ); } Preconditions.checkNotNull( kernelId, "Attempt to resolve a kerneId for " + bootSet.toString( ) + " during request " + ( ctx != null ? ctx.getRequest( ).toSimpleString( ) : "UNKNOWN" ) ); if ( kernelId == null ) { throw new NoSuchMetadataException( "Unable to determine required kernel image for " + disk.getDisplayName( ) ); } else if ( !CloudMetadatas.isKernelImageIdentifier( kernelId ) ) { throw new InvalidMetadataException( "Image specified is not a kernel: " + kernelId ); } return kernelId; } private static String determineRamdiskId( final BootableSet bootSet ) throws MetadataException { if ( !bootSet.hasKernel( ) ) { throw new InvalidMetadataException( "Image specified does not have a kernel: " + bootSet ); } String ramdiskId = bootSet.getMachine( ).getRamdiskId( );//GRZE: use the ramdisk that is part of the registered image definition to start. try { final Context ctx = Contexts.lookup( ); if ( ctx.getRequest( ) instanceof RunInstancesType ) { final RunInstancesType msg = ( RunInstancesType ) ctx.getRequest( ); if ( ( msg.getRamdiskId( ) != null ) && !"".equals( msg.getRamdiskId( ) ) ) { ramdiskId = msg.getRamdiskId( );//GRZE: maybe update w/ a specific ramdisk user requests } } } catch ( final IllegalContextAccessException ex ) { LOG.debug( "Context not found when determining ramdisk id:" + ex.getMessage( ) ); } //GRZE: perfectly legitimate for there to be no ramdisk, carry on. **/ if ( ramdiskId == null ) { return ramdiskId; } else if ( !CloudMetadatas.isRamdiskImageIdentifier( ramdiskId ) ) { throw new InvalidMetadataException( "Image specified is not a ramdisk: " + ramdiskId ); } else { return ramdiskId; } } }