/************************************************************************* * Copyright 2009-2015 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.compute.common.internal.vm; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.NoSuchElementException; import java.util.concurrent.atomic.AtomicReference; import javax.annotation.Nonnull; import javax.annotation.Nullable; import javax.persistence.EntityTransaction; import org.apache.log4j.Logger; import org.hibernate.Criteria; import org.hibernate.criterion.Criterion; import org.hibernate.criterion.Example; import org.hibernate.criterion.Projection; import org.hibernate.criterion.Restrictions; import com.eucalyptus.compute.common.CloudMetadata; import com.eucalyptus.entities.Entities; import com.eucalyptus.entities.TransactionResource; import com.eucalyptus.records.Logs; import com.eucalyptus.util.CollectionUtils; import com.eucalyptus.auth.principal.OwnerFullName; import com.eucalyptus.util.RestrictedTypes; import com.google.common.base.Function; import com.google.common.base.Functions; import com.google.common.base.Predicate; import com.google.common.base.Predicates; import com.google.common.base.Supplier; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; /** * */ public class VmInstances { private static final Logger LOG = Logger.getLogger( VmInstances.class ); protected static final AtomicReference<String> ebsRootDeviceName = new AtomicReference<String>( "emi" ); public static String getEbsRootDeviceName( ) { return ebsRootDeviceName.get( ); } /** * Lookup a VM instance. * * @param name The instance identifier (display name) * @return The instance. * @throws java.util.NoSuchElementException If the instance is not found */ @Nonnull public static VmInstance lookupAny( final String name ) throws NoSuchElementException { return PersistentLookup.INSTANCE.apply( name ); } /** * Lookup a non-terminated VM instance. * * @param name The instance identifier (display name) * @return The instance. * @throws NoSuchElementException If the instance is not found * @throws TerminatedInstanceException If the instance is terminated. */ @Nonnull public static VmInstance lookup( final String name ) throws NoSuchElementException, TerminatedInstanceException { return lookup( ).apply( name ); } /** * Function for lookup of non-terminated VM instances. * * <p>The function parameter is the instance identifier the return is the * instance. The function will not return null, but may throw * NoSuchElementException or TerminatedInstanceException.</p> * * @return The function. */ public static Function<String,VmInstance> lookup() { return Functions.compose( TerminatedInstanceCheck.INSTANCE, PersistentLookup.INSTANCE ); } /** * Function for lookup of running VM instance by public IP. * * @param ip The public/elastic IP for the instance * @return The instance * @throws NoSuchElementException if an instance was not found with the IP */ @Nonnull public static VmInstance lookupByPublicIp( final String ip ) throws NoSuchElementException { try ( TransactionResource db = Entities.transactionFor( VmInstance.class ) ) { VmInstance vmExample = VmInstance.exampleWithPublicIp( ip ); VmInstance vm = ( VmInstance ) Entities.createCriteriaUnique( VmInstance.class ) .add( Example.create( vmExample ) ) .add( VmInstance.criterion( VmInstance.VmState.RUNNING, VmInstance.VmState.PENDING ) ) .uniqueResult(); if ( vm == null ) { throw new NoSuchElementException( "VmInstance with public ip: " + ip ); } db.commit( ); return vm; } catch ( Exception ex ) { Logs.exhaust( ).error( ex, ex ); throw new NoSuchElementException( ex.getMessage( ) ); } } /** * List instances that are not done and match the given predicate. * * @param predicate The predicate to match * @return The matching instances * @see com.eucalyptus.compute.common.internal.vm.VmInstance.VmStateSet#DONE */ public static List<VmInstance> list( @Nullable Predicate<? super VmInstance> predicate ) { return list( (OwnerFullName) null, predicate ); } /** * List instances that are not done and match the given owner/predicate. * * @param ownerFullName The owning user or account * @param predicate The predicate to match * @return The matching instances * @see com.eucalyptus.compute.common.internal.vm.VmInstance.VmStateSet#DONE */ public static List<VmInstance> list( @Nullable OwnerFullName ownerFullName, @Nullable Predicate<? super VmInstance> predicate ) { return list( ownerFullName, Restrictions.not( VmInstance.criterion( VmInstance.VmStateSet.DONE.array() ) ), Collections.<String,String>emptyMap(), Predicates.and( VmInstance.VmStateSet.DONE.not(), checkPredicate( predicate ) ), false ); } /** * List instances in any state that match the given parameters. */ public static List<VmInstance> list( @Nullable final OwnerFullName ownerFullName, final Criterion criterion, final Map<String,String> aliases, @Nullable final Predicate<? super VmInstance> predicate ) { return list( ownerFullName, criterion, aliases, predicate, false ); } /** * List instances in any state that match the given parameters. */ public static List<VmInstance> list( @Nullable final OwnerFullName ownerFullName, final Criterion criterion, final Map<String,String> aliases, @Nullable final Predicate<? super VmInstance> predicate, final boolean outerJoins ) { return list( new Supplier<List<VmInstance>>( ) { @Override public List<VmInstance> get() { return Entities.query( VmInstance.named( ownerFullName, null ), false, criterion, aliases, outerJoins ); } }, Predicates.<VmInstance>and( RestrictedTypes.filterByOwner( ownerFullName ), checkPredicate( predicate ) ) ); } /** * List instances in any state that match the given parameters. */ public static List<VmInstance> listByClientToken( @Nullable final OwnerFullName ownerFullName, @Nullable final String clientToken, @Nullable Predicate<? super VmInstance> predicate ) { return list( new Supplier<List<VmInstance>>() { @Override public List<VmInstance> get() { return Entities.query( VmInstance.withToken( ownerFullName, clientToken ) ); } }, Predicates.and( CollectionUtils.propertyPredicate( clientToken, VmInstance.clientToken( ) ), RestrictedTypes.filterByOwner( ownerFullName ), checkPredicate( predicate ) ) ); } private static List<VmInstance> list( @Nonnull Supplier<List<VmInstance>> instancesSupplier, @Nullable Predicate<? super VmInstance> predicate ) { predicate = checkPredicate( predicate ); return listPersistent( instancesSupplier, predicate ); } private static List<VmInstance> listPersistent( @Nonnull Supplier<List<VmInstance>> instancesSupplier, @Nonnull Predicate<? super VmInstance> predicate ) { final EntityTransaction db = Entities.get( VmInstance.class ); try { final Iterable<VmInstance> vms = Iterables.filter( instancesSupplier.get(), predicate ); final List<VmInstance> instances = Lists.newArrayList( vms ); db.commit( ); return instances; } catch ( final Exception ex ) { LOG.error( ex ); Logs.extreme().error( ex, ex ); return Lists.newArrayList( ); } finally { if ( db.isActive() ) db.rollback(); } } public interface InstanceProjection<T> { Projection getProjection( ); List<T> results( List<?> listing ); } public static InstanceProjection<String> instanceIdProjection( ) { return StringInstanceProjections.INSTANCE_ID; } public static InstanceProjection<String> instanceUuidProjection( ) { return StringInstanceProjections.INSTANCE_UUID; } private enum StringInstanceProjections implements InstanceProjection<String> { INSTANCE_ID { @Override public Projection getProjection() { return VmInstance.instanceIdProjection( ); } }, INSTANCE_UUID { @Override public Projection getProjection() { return VmInstance.instanceUuidProjection( ); } }, ; @Override public List<String> results( final List<?> listing ) { //noinspection unchecked return ( List<String> ) listing; } } public static <T> List<T> listWithProjection( @Nonnull final InstanceProjection<T> projection, final Criterion... criterions ) { try ( final TransactionResource db = Entities.readOnlyDistinctTransactionFor( VmInstance.class ) ) { final Criteria query = Entities.createCriteria( VmInstance.class ) .setReadOnly( true ) .setFetchSize( 25_000 ) .add( Restrictions.and( criterions ) ) .setProjection( projection.getProjection( ) ); return projection.results( query.list( ) ); } } private static <T> Predicate<T> checkPredicate( Predicate<T> predicate ) { return predicate == null ? Predicates.<T>alwaysTrue() : predicate; } public static VmVolumeAttachment lookupVolumeAttachment( final String volumeId , final List<VmInstance> vms ) { VmVolumeAttachment ret = null; try { for ( VmInstance vm : vms ) { try { ret = vm.lookupVolumeAttachment( volumeId ); if ( ret.getVmInstance( ) == null ) { ret.setVmInstance( vm ); } } catch ( NoSuchElementException ex ) { continue; } } if ( ret == null ) { throw new NoSuchElementException( "VmVolumeAttachment: no volume attachment for " + volumeId ); } return ret; } catch ( Exception ex ) { throw new NoSuchElementException( ex.getMessage( ) ); } } @RestrictedTypes.Resolver( CloudMetadata.VmInstanceMetadata.class ) enum PersistentLookup implements Function<String, VmInstance> { INSTANCE; /** * @see com.google.common.base.Function#apply(java.lang.Object) */ @Nonnull @Override public VmInstance apply( final String name ) { return VmInstance.Lookup.INSTANCE.apply( name ); } } enum TerminatedInstanceCheck implements Function<VmInstance,VmInstance> { INSTANCE; @Nullable @Override public VmInstance apply( final VmInstance instance ) { if ( instance != null && VmInstance.VmStateSet.DONE.apply( instance ) ) { throw new TerminatedInstanceException( instance.getDisplayName( ) ); } return instance; } } public static class TerminatedInstanceException extends NoSuchElementException { /** * */ private static final long serialVersionUID = 1L; TerminatedInstanceException( final String s ) { super( s ); } } }