/*******************************************************************************
*Copyright (c) 2009 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, only version 3 of the License.
*
*
* This file 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., 130 Castilian
* Dr., Goleta, CA 93101 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.
*******************************************************************************/
/*
* Author: chris grzegorczyk <grze@eucalyptus.com>
*/
package com.eucalyptus.cluster;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.NavigableSet;
import java.util.NoSuchElementException;
import java.util.concurrent.ConcurrentSkipListSet;
import org.apache.log4j.Logger;
import org.mule.RequestContext;
import org.mule.api.MuleException;
import org.mule.api.lifecycle.Startable;
import com.eucalyptus.address.Address;
import com.eucalyptus.address.Addresses;
import com.eucalyptus.bootstrap.Bootstrap;
import com.eucalyptus.cluster.callback.ConfigureNetworkCallback;
import com.eucalyptus.component.Components;
import com.eucalyptus.entities.VmType;
import com.eucalyptus.sla.ClusterAllocator;
import com.eucalyptus.util.EucalyptusCloudException;
import com.eucalyptus.ws.client.ServiceDispatcher;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import edu.emory.mathcs.backport.java.util.Collections;
import edu.ucsb.eucalyptus.cloud.Network;
import edu.ucsb.eucalyptus.cloud.NodeInfo;
import edu.ucsb.eucalyptus.cloud.ResourceToken;
import edu.ucsb.eucalyptus.cloud.VmAllocationInfo;
import edu.ucsb.eucalyptus.cloud.entities.SystemConfiguration;
import edu.ucsb.eucalyptus.msgs.ClusterInfoType;
import edu.ucsb.eucalyptus.msgs.DescribeAvailabilityZonesResponseType;
import edu.ucsb.eucalyptus.msgs.DescribeAvailabilityZonesType;
import edu.ucsb.eucalyptus.msgs.DescribeRegionsResponseType;
import edu.ucsb.eucalyptus.msgs.DescribeRegionsType;
import edu.ucsb.eucalyptus.msgs.NodeCertInfo;
import edu.ucsb.eucalyptus.msgs.NodeLogInfo;
import edu.ucsb.eucalyptus.msgs.PacketFilterRule;
import edu.ucsb.eucalyptus.msgs.RegionInfoType;
public class ClusterEndpoint implements Startable {
private static Logger LOG = Logger.getLogger( ClusterEndpoint.class );
public void start() throws MuleException {
Clusters.getInstance();
}
public void networkChange( Network net ) {
try {
Network existingNet = Networks.getInstance().lookup( net.getName() );
List<PacketFilterRule> rules = Lists.newArrayList( );
if ( net.getRules().isEmpty() ) {
for ( PacketFilterRule pf : existingNet.getRules() )
rules.add( PacketFilterRule.revoke( pf ) );
existingNet.setRules( net.getRules() );
} else {
existingNet.setRules( net.getRules() );
rules.addAll( existingNet.getRules() );
}
ConfigureNetworkCallback configureNetwork = new ConfigureNetworkCallback( existingNet.getUserName( ), rules );
for ( Cluster c : Clusters.getInstance( ).listValues( ) ) {
configureNetwork.newInstance( ).dispatch( c );
}
} catch ( NoSuchElementException e ) {
LOG.error( "Changed network rules not applied to inactive network: " + net.getName() );
}
}
public void enqueue( VmAllocationInfo vmAllocInfo ) {
for( ResourceToken t : vmAllocInfo.getAllocationTokens( ) ) {
ClusterAllocator.create( t, vmAllocInfo );
}
RequestContext.getEventContext().setStopFurtherProcessing( true );
}
public DescribeAvailabilityZonesResponseType DescribeAvailabilityZones( DescribeAvailabilityZonesType request ) {
DescribeAvailabilityZonesResponseType reply = ( DescribeAvailabilityZonesResponseType ) request.getReply();
if ( request.isAdministrator() && request.getAvailabilityZoneSet().lastIndexOf( "help" ) == 0 ) {
reply.getAvailabilityZoneInfo().addAll( this.addHelpInfo() );
return reply;
}
List<String> args = request.getAvailabilityZoneSet( );
if( args.isEmpty( ) || args.contains( "verbose" ) || args.contains( "certs" ) || args.contains( "logs" ) || args.contains( "keys" ) ) {
for( Cluster c : Clusters.getInstance( ).listValues( ) ) {
this.getDescriptionEntry( reply, c, request );
}
} else {
for( String clusterName : request.getAvailabilityZoneSet( ) ) {
try {
Cluster c = Clusters.getInstance( ).lookup( clusterName );
this.getDescriptionEntry( reply, c, request );
} catch ( NoSuchElementException e ) {
if ( clusterName.equals( "coredump" ) ) {
reply.getAvailabilityZoneInfo().addAll( this.dumpState() );
}
}
}
}
return reply;
}
private void getDescriptionEntry( DescribeAvailabilityZonesResponseType reply, Cluster c, DescribeAvailabilityZonesType request ) {
boolean admin = request.isAdministrator( );
List<String> args = request.getAvailabilityZoneSet( );
String clusterName = c.getName( );
reply.getAvailabilityZoneInfo( ).add( new ClusterInfoType( c.getConfiguration( ).getName( ), c.getConfiguration( ).getHostName( ) ) );
NavigableSet<String> tagList = new ConcurrentSkipListSet<String>( );
if ( tagList.size() == 1 ) tagList = c.getNodeTags();
else
tagList.retainAll( c.getNodeTags() );
if( admin ) {
if ( args.contains( "verbose" ) ) {
reply.getAvailabilityZoneInfo().addAll( this.addSystemInfo( c ) );
} else if ( args.contains( "certs" ) ) {
for ( String tag : tagList ) {
reply.getAvailabilityZoneInfo( ).addAll( this.addCertInfo( tag, c ) );
}
} else if ( args.contains( "logs" ) ) {
for ( String tag : tagList ) {
reply.getAvailabilityZoneInfo().addAll( this.addLogInfo( tag, c ) );
}
}
}
}
private static String INFO_FSTRING = "|- %s";
private static String HEADER_STRING = "free / max cpu ram disk";
private static String STATE_FSTRING = "%04d / %04d %2d %4d %4d";
private static ClusterInfoType t( String left, String right ) { return new ClusterInfoType( left, right ); }
private static ClusterInfoType s( String left, String right ) { return new ClusterInfoType( String.format( INFO_FSTRING, left ), right );}
private List<ClusterInfoType> dumpState() {
List<ClusterInfoType> retList = Lists.newArrayList();
retList.add( new ClusterInfoType( "================== Addresses", "" ) );
for ( Address addr : Addresses.getInstance().listValues() ) {
String val = addr.toString();
retList.add( new ClusterInfoType( val, "" ) );
LOG.info( val );
}
retList.add( new ClusterInfoType( "================== Disabled Addresses", "" ) );
for ( Address addr : Addresses.getInstance().listDisabledValues() ) {
String val = addr.toString();
retList.add( new ClusterInfoType( val, "" ) );
LOG.info( val );
}
retList.add( new ClusterInfoType( "================== VMs", "" ) );
for ( VmInstance vm : VmInstances.getInstance().listValues() ) {
String val = vm.toString();
retList.add( new ClusterInfoType( val, "" ) );
LOG.info( val );
}
retList.add( new ClusterInfoType( "================== Disabled VMs", "" ) );
for ( VmInstance vm : VmInstances.getInstance().listDisabledValues() ) {
String val = vm.toString();
retList.add( new ClusterInfoType( val, "" ) );
LOG.info( val );
}
retList.add( new ClusterInfoType( "================== Clusters", "" ) );
for ( Cluster cluster : Clusters.getInstance().listValues() ) {
String val = cluster.toString();
retList.add( new ClusterInfoType( val, "" ) );
LOG.info( val );
}
retList.add( new ClusterInfoType( "================== Networks", "" ) );
for ( Network network : Networks.getInstance().listValues() ) {
String val = network.toString();
retList.add( new ClusterInfoType( val, "" ) );
LOG.info( val );
}
retList.add( new ClusterInfoType( "================== Configurations", "" ) );
for( String val : Iterables.transform( Components.list( ), Components.configurationToString( ) ) ) {
retList.add( new ClusterInfoType( val, "" ) );
LOG.info( val );
}
retList.add( new ClusterInfoType( "================== Components", "" ) );
for( String val : Iterables.transform( Components.list( ), Components.componentToString( ) ) ) {
retList.add( new ClusterInfoType( val, "" ) );
LOG.info( val );
}
retList.add( new ClusterInfoType( "================== Dispatchers", "" ) );
for( String val : Iterables.transform( ServiceDispatcher.values( ), Components.dispatcherToString( ) ) ) {
retList.add( new ClusterInfoType( val, "" ) );
LOG.info( val );
}
retList.add( new ClusterInfoType( "================== Bootstrappers", "" ) );
for( Bootstrap.Stage stage : Bootstrap.Stage.values( ) ) {
retList.add( new ClusterInfoType( stage.name( ), stage.describe( ).replaceAll( "\n", "" ).replaceAll( "^\\w* ", "" ) ) );
LOG.info( stage.describe( ) );
}
return retList;
}
private Collection<ClusterInfoType> addHelpInfo() {
List<ClusterInfoType> helpInfo = new ArrayList<ClusterInfoType>();
helpInfo.add( t( "sub-command", "effect & arguments" ) );
helpInfo.add( s( "logs [SERVICE_TAGS...]", "get log files from the system." ) );
helpInfo.add( s( "certs [SERVICE_TAGS...]", "get log files from the system." ) );
helpInfo.add( s( "verbose", "get log files from the system." ) );
return helpInfo;
}
private List<ClusterInfoType> addSystemInfo( final Cluster cluster ) {
List<ClusterInfoType> info = new ArrayList<ClusterInfoType>();
try {
info.add( new ClusterInfoType( String.format( INFO_FSTRING, "vm types" ), HEADER_STRING ) );
for ( VmType v : VmTypes.list() ) {
VmTypeAvailability va = cluster.getNodeState().getAvailability( v.getName() );
info.add( s( v.getName(), String.format( STATE_FSTRING, va.getAvailable(), va.getMax(), v.getCpu(), v.getMemory(), v.getDisk() ) ) );
}
}
catch ( Exception e ) {
LOG.error( e, e );
}
return info;
}
private List<ClusterInfoType> addLogInfo( final String serviceTag, final Cluster cluster ) {
List<ClusterInfoType> info = new ArrayList<ClusterInfoType>();
NodeInfo node = cluster.getNode( serviceTag );
NodeLogInfo logInfo = node.getLogs();
info.add( t( node.getName(), "last-seen=" + node.getLastSeen() ) );
if ( !logInfo.getNcLog().isEmpty() )
info.add( s( "nc.log\n", logInfo.getNcLog() ) );
if ( !logInfo.getNcLog().isEmpty() )
info.add( s( "cc.log\n", logInfo.getCcLog() ) );
info.add( t( node.getName(), "last-seen=" + node.getLastSeen() ) );
info.add( s( "axis2.log\n", logInfo.getAxis2Log() ) );
info.add( t( node.getName(), "last-seen=" + node.getLastSeen() ) );
info.add( s( "httpd.log\n", logInfo.getHttpdLog() ) );
return info;
}
private Collection<ClusterInfoType> addCertInfo( final String serviceTag, final Cluster c ) {
List<ClusterInfoType> info = new ArrayList<ClusterInfoType>();
NodeInfo node = c.getNode( serviceTag );
info.add( t( node.getName(), "last-seen=" + node.getLastSeen() ) );
NodeCertInfo certInfo = node.getCerts();
info.add( s( "CC cert\n", certInfo.getCcCert() ) );
info.add( s( "NC cert\n", certInfo.getCcCert() ) );
return info;
}
public DescribeRegionsResponseType DescribeRegions(DescribeRegionsType request) {
DescribeRegionsResponseType reply = ( DescribeRegionsResponseType ) request.getReply( );
try {
SystemConfiguration config = SystemConfiguration.getSystemConfiguration( );
reply.getRegionInfo( ).add( new RegionInfoType( "Eucalyptus", SystemConfiguration.getCloudUrl( ) ) );
reply.getRegionInfo( ).add( new RegionInfoType( "Walrus", SystemConfiguration.getWalrusUrl( ) ) );
} catch ( EucalyptusCloudException e ) {}
return reply;
}
}