/*************************************************************************
* 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.
************************************************************************/
package com.eucalyptus.loadbalancing;
import java.util.Date;
import java.util.List;
import java.util.NoSuchElementException;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.PersistenceContext;
import javax.persistence.PostLoad;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Transient;
import org.apache.log4j.Logger;
import com.eucalyptus.component.ComponentIds;
import com.eucalyptus.component.id.Eucalyptus;
import com.eucalyptus.compute.common.RunningInstancesItemType;
import com.eucalyptus.entities.TransactionResource;
import com.eucalyptus.entities.UserMetadata;
import com.eucalyptus.entities.Entities;
import com.eucalyptus.loadbalancing.LoadBalancer.LoadBalancerCoreView;
import com.eucalyptus.loadbalancing.LoadBalancerZone.LoadBalancerZoneCoreView;
import com.eucalyptus.loadbalancing.activities.EucalyptusActivityTasks;
import com.eucalyptus.loadbalancing.service.InternalFailure400Exception;
import com.eucalyptus.loadbalancing.service.InvalidEndPointException;
import com.eucalyptus.loadbalancing.service.LoadBalancingException;
import com.eucalyptus.util.Exceptions;
import com.eucalyptus.auth.principal.FullName;
import com.eucalyptus.util.NonNullFunction;
import com.eucalyptus.auth.principal.OwnerFullName;
import com.eucalyptus.util.TypeMapper;
import com.eucalyptus.util.TypeMappers;
import com.google.common.base.Function;
import com.google.common.collect.Lists;
/**
* @author Sang-Min Park
*
*/
@Entity
@PersistenceContext( name = "eucalyptus_loadbalancing" )
@Table( name = "metadata_backend_instance" )
public class LoadBalancerBackendInstance extends UserMetadata<LoadBalancerBackendInstance.STATE> {
private static Logger LOG = Logger.getLogger( LoadBalancerBackendInstance.class );
@Transient
private static final long serialVersionUID = 1L;
@Transient
private LoadBalancerBackendInstanceRelationView view;
@PostLoad
private void onLoad(){
if(view==null)
view = new LoadBalancerBackendInstanceRelationView(this);
}
public enum STATE {
InService, OutOfService, Unknown, Error
}
@ManyToOne()
@JoinColumn( name = "metadata_loadbalancer_fk" )
private LoadBalancer loadbalancer = null;
@ManyToOne()
@JoinColumn( name = "metadata_zone_fk")
private LoadBalancerZone zone = null;
@Transient
private RunningInstancesItemType vmInstance = null;
@Column( name = "reason_code", nullable=true)
private String reasonCode = null;
@Column( name = "description", nullable=true)
private String description = null;
@Column( name = "ip_address", nullable=true)
private String ipAddress = null;
@Column( name = "partition", nullable=true)
private String partition = null;
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "instance_update_timestamp", nullable=true)
private Date instanceUpdateTimestamp = null;
private LoadBalancerBackendInstance(){
super(null,null);
}
private LoadBalancerBackendInstance(final OwnerFullName userFullName, final LoadBalancer lb, final String vmId)
throws LoadBalancingException
{
super(userFullName, vmId);
this.loadbalancer = lb;
this.setState(STATE.OutOfService);
this.setReasonCode("ELB");
this.setDescription("Instance registration is still in progress.");
this.updateInstanceStateTimestamp();
if(this.getVmInstance() == null)
throw new InvalidEndPointException();
try ( final TransactionResource db = Entities.transactionFor( LoadBalancerZone.class ) ) {
final LoadBalancerZone found = Entities.uniqueResult(LoadBalancerZone.named(lb, this.vmInstance.getPlacement()));
this.setAvailabilityZone(found);
}catch(final NoSuchElementException ex){
}catch(final Exception ex){
throw new InternalFailure400Exception("unable to find the zone");
}finally{
if(this.zone == null)
throw new InternalFailure400Exception("unable to find the instance's zone");
}
}
public static LoadBalancerBackendInstance newInstance(final OwnerFullName userFullName, final LoadBalancer lb, final String vmId)
throws LoadBalancingException
{
return new LoadBalancerBackendInstance(userFullName, lb, vmId);
}
public static LoadBalancerBackendInstance newInstance(final OwnerFullName userFullName, final LoadBalancer lb, final String vmId, STATE state)
throws LoadBalancingException
{
LoadBalancerBackendInstance instance= new LoadBalancerBackendInstance(userFullName, lb, vmId);
instance.setBackendState(state);
return instance;
}
public static LoadBalancerBackendInstance named(final LoadBalancer lb, final String vmId){
LoadBalancerBackendInstance instance = new LoadBalancerBackendInstance();
instance.setOwner(null);
instance.setDisplayName(vmId);
instance.setLoadBalancer(lb);
instance.setState(null);
instance.setStateChangeStack(null);
instance.getUniqueName();
return instance;
}
public static LoadBalancerBackendInstance named(){
return new LoadBalancerBackendInstance();
}
public String getInstanceId(){
return this.getDisplayName();
}
private RunningInstancesItemType getVmInstance(){
try{
if(this.vmInstance==null){
List<RunningInstancesItemType> instanceIds =
EucalyptusActivityTasks.getInstance().describeUserInstances(this.getOwnerAccountNumber(), Lists.newArrayList(this.displayName));
for(RunningInstancesItemType instance : instanceIds ) {
if(instance.getInstanceId().equals(this.getDisplayName()) && instance.getStateName().equals("running")){
this.vmInstance = instance;
this.partition = instance.getPlacement();
if(this.loadbalancer != null) {
if(this.loadbalancer.getVpcId() == null)
this.ipAddress = instance.getIpAddress();
else
this.ipAddress = instance.getPrivateIpAddress();
}
break;
}
}
}
}catch(Exception ex){
;
}
return this.vmInstance;
}
private void setLoadBalancer(final LoadBalancer lb){
this.loadbalancer = lb;
}
public LoadBalancerCoreView getLoadBalancer(){
return this.view.getLoadBalancer();
}
public void setBackendState(final STATE state){
this.setState(state);
}
public STATE getBackendState(){
return this.getState();
}
public String getReasonCode(){
return this.reasonCode;
}
public void setReasonCode(final String reason){
this.reasonCode = reason;
}
public String getDescription(){
return this.description;
}
public void setDescription(final String description){
this.description = description;
}
public void setAvailabilityZone(final LoadBalancerZone zone){
this.zone = zone;
}
public LoadBalancerZoneCoreView getAvailabilityZone(){
return this.view.getZone();
}
public void updateInstanceStateTimestamp(){
final long currentTime = System.currentTimeMillis();
this.instanceUpdateTimestamp = new Date(currentTime);
}
public Date instanceStateLastUpdated(){
return this.instanceUpdateTimestamp;
}
@Override
public String getPartition() {
if(this.partition!=null)
return this.partition;
else{
final RunningInstancesItemType vm = this.getVmInstance();
return vm != null? vm.getPlacement() : null;
}
}
public void setPartition(final String partition) {
this.partition = partition;
}
public String getIpAddress(){
return this.ipAddress;
}
public void setIpAddress(final String ipAddress) {
this.ipAddress = ipAddress;
}
@Override
public FullName getFullName() {
return FullName.create.vendor( "euca" )
.region( ComponentIds.lookup( Eucalyptus.class ).name( ) )
.namespace( this.getOwnerAccountNumber( ) )
.relativeId( "loadbalancer-backend-instance", this.vmInstance.getInstanceId()!=null ? this.vmInstance.getInstanceId() : "");
}
@Override
public boolean equals(Object obj){
if(obj==null)
return false;
if(obj.getClass() != LoadBalancerBackendInstance.class)
return false;
final LoadBalancerBackendInstance other = (LoadBalancerBackendInstance) obj;
if(this.loadbalancer == null){
if(other.loadbalancer!=null)
return false;
}else if(this.loadbalancer.getOwnerUserId() == null){
if(other.loadbalancer.getOwnerUserId()!=null)
return false;
}else if(! this.loadbalancer.getOwnerUserId().equals(other.loadbalancer.getOwnerUserId()))
return false;
if(this.loadbalancer == null){
if(other.loadbalancer!=null)
return false;
}else if(this.loadbalancer.getDisplayName() == null){
if(other.loadbalancer.getDisplayName()!=null)
return false;
}else if(! this.loadbalancer.getDisplayName().equals(other.loadbalancer.getDisplayName()))
return false;
if(this.displayName == null){
if(other.displayName != null)
return false;
}else if(!this.displayName.equals(other.displayName))
return false;
return true;
}
@Override
public int hashCode( ) {
final int prime = 31;
int result = super.hashCode( );
result = prime * result + ( ( this.loadbalancer == null || this.loadbalancer.getOwnerUserId() == null )
? 0
: this.loadbalancer.getOwnerUserId().hashCode());
result = prime * result + ( ( this.loadbalancer == null || this.loadbalancer.getDisplayName() == null )
? 0
: this.loadbalancer.getDisplayName().hashCode());
result = prime * result + ( ( this.displayName == null )
? 0
: this.displayName.hashCode());
return result;
}
@Override
public String toString(){
return String.format("%s backend instance - %s", this.loadbalancer, this.getDisplayName());
}
@Override
protected String createUniqueName( ) {
return ( this.loadbalancer != null && this.getDisplayName( ) != null)
? this.loadbalancer.getOwnerAccountNumber( ) + ":" + this.loadbalancer.getDisplayName()+":"+this.getDisplayName( )
: null;
}
public static class LoadBalancerBackendInstanceCoreView {
private LoadBalancerBackendInstance instance = null;
LoadBalancerBackendInstanceCoreView(LoadBalancerBackendInstance instance){
this.instance = instance;
}
public String getDisplayName(){
return this.instance.getDisplayName();
}
public STATE getState(){
return this.instance.getState();
}
public String getInstanceId(){
return this.instance.getInstanceId();
}
public STATE getBackendState(){
return this.instance.getBackendState();
}
public String getReasonCode(){
return this.instance.getReasonCode();
}
public String getDescription(){
return this.instance.getDescription();
}
public String getIpAddress(){
return this.instance.getIpAddress();
}
public String getPartition(){
return this.instance.getPartition();
}
public Date instanceStateLastUpdated(){
return this.instance.instanceUpdateTimestamp;
}
public Date instanceCreationTimestamp(){
return this.instance.getCreationTimestamp();
}
public static NonNullFunction<LoadBalancerBackendInstanceCoreView,String> instanceId( ) {
return StringPropertyFunctions.InstanceId;
}
private enum StringPropertyFunctions implements NonNullFunction<LoadBalancerBackendInstanceCoreView,String> {
InstanceId {
@Nonnull
@Override
public String apply( final LoadBalancerBackendInstanceCoreView loadBalancerBackendInstanceCoreView ) {
return loadBalancerBackendInstanceCoreView.getInstanceId( );
}
},
}
}
@TypeMapper
public enum LoadBalancerBackendInstanceCoreViewTransform implements Function<LoadBalancerBackendInstance, LoadBalancerBackendInstanceCoreView> {
INSTANCE;
@Override
@Nullable
public LoadBalancerBackendInstanceCoreView apply(
@Nullable LoadBalancerBackendInstance arg0) {
return new LoadBalancerBackendInstanceCoreView(arg0);
}
}
public enum LoadBalancerBackendInstanceEntityTransform implements Function<LoadBalancerBackendInstanceCoreView, LoadBalancerBackendInstance> {
INSTANCE;
@Override
@Nullable
public LoadBalancerBackendInstance apply(
@Nullable LoadBalancerBackendInstanceCoreView arg0) {
try ( final TransactionResource db = Entities.transactionFor( LoadBalancerBackendInstance.class ) ) {
return Entities.uniqueResult(arg0.instance);
}catch(final Exception ex){
throw Exceptions.toUndeclared(ex);
}
}
}
private static class LoadBalancerBackendInstanceRelationView {
private LoadBalancerZoneCoreView zone = null;
private LoadBalancer loadbalancer = null;
LoadBalancerBackendInstanceRelationView(
LoadBalancerBackendInstance instance) {
if(instance.zone!=null)
zone = TypeMappers.transform(instance.zone, LoadBalancerZoneCoreView.class);
if(instance.loadbalancer!=null) {
Entities.initialize( instance.loadbalancer );
loadbalancer = instance.loadbalancer;
}
}
public LoadBalancerZoneCoreView getZone(){
return this.zone;
}
public LoadBalancerCoreView getLoadBalancer(){
return this.loadbalancer.getCoreView( );
}
}
}