/*************************************************************************
* Copyright 2009-2016 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.workflow;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import com.amazonaws.services.simpleworkflow.model.UnknownResourceException;
import org.apache.log4j.Logger;
import com.amazonaws.services.simpleworkflow.model.WorkflowExecutionAlreadyStartedException;
import com.eucalyptus.loadbalancing.common.LoadBalancing;
import com.eucalyptus.loadbalancing.common.msgs.Listener;
import com.eucalyptus.loadbalancing.common.msgs.LoadBalancerAttributes;
import com.eucalyptus.system.Threads;
import com.eucalyptus.util.Exceptions;
import com.google.common.base.Supplier;
/**
* @author Sang-Min Park (sangmin.park@hpe.com)
*
*/
/// facade for workflows
public class LoadBalancingWorkflows {
private static Logger LOG = Logger.getLogger( LoadBalancingWorkflows.class );
public static void createLoadBalancerSync(final String accountId, final String loadbalancer, final List<String> availabilityZones)
throws Exception {
final Future<LoadBalancingWorkflowException> task =
Threads.enqueue(LoadBalancing.class, LoadBalancingWorkflows.class, createLoadBalancerImpl(accountId, loadbalancer, availabilityZones ));
final LoadBalancingWorkflowException ex = task.get();
if (ex != null) {
throw ex;
}
}
public static void createLoadBalancerAsync(final String accountId, final String loadbalancer, final List<String> availabilityZones) {
Threads.enqueue(LoadBalancing.class, LoadBalancingWorkflows.class, createLoadBalancerImpl(accountId, loadbalancer, availabilityZones ));
}
private static Callable<LoadBalancingWorkflowException> createLoadBalancerImpl(final String accountId, final String loadbalancer, final List<String> availabilityZones) {
return new Callable<LoadBalancingWorkflowException>() {
@Override
public LoadBalancingWorkflowException call() throws Exception {
final CreateLoadBalancerWorkflowClientExternal workflow =
WorkflowClients.getCreateLbWorkflow();
workflow.createLoadBalancer(accountId, loadbalancer, availabilityZones.toArray(new String[availabilityZones.size()]));
try {
waitForException(new Supplier<ElbWorkflowState>() {
@Override
public ElbWorkflowState get() {
return workflow.getState();
}
});
} catch (final LoadBalancingWorkflowException ex) {
return ex;
} catch (final Exception ex) {
return new LoadBalancingWorkflowException(null, ex);
}
return null;
}
};
}
public static boolean deleteLoadBalancerSync(final String accountId, final String loadbalancer) {
final Future<Boolean> task = Threads.enqueue(LoadBalancing.class, LoadBalancingWorkflows.class, deleteLoadBalancerImpl(accountId, loadbalancer));
try{
return task.get();
}catch(final Exception ex) {
return false;
}
}
public static void deleteLoadBalancerAsync(final String accountId, final String loadbalancer) {
Threads.enqueue(LoadBalancing.class, LoadBalancingWorkflows.class, deleteLoadBalancerImpl(accountId, loadbalancer));
}
private static Callable<Boolean> deleteLoadBalancerImpl(final String accountId, final String loadbalancer) {
return new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
final DeleteLoadBalancerWorkflowClientExternal workflow =
WorkflowClients.getDeleteLbWorkflow(accountId, loadbalancer);
workflow.deleteLoadBalancer(accountId, loadbalancer);
return waitFor(new Supplier<ElbWorkflowState>() {
@Override
public ElbWorkflowState get() {
return workflow.getState();
}
});
}
};
}
public static boolean createListenersSync(final String accountId, final String loadbalancer, final List<Listener> listeners) {
final Future<Boolean> task = Threads.enqueue(LoadBalancing.class, LoadBalancingWorkflows.class, createListenersImpl(accountId, loadbalancer, listeners ));
try{
return task.get();
}catch(final Exception ex) {
return false;
}
}
public static void createListenersAsync(final String accountId, final String loadbalancer, final List<Listener> listeners) {
Threads.enqueue(LoadBalancing.class, LoadBalancingWorkflows.class, createListenersImpl(accountId, loadbalancer, listeners ));
}
private static Callable<Boolean> createListenersImpl(final String accountId, final String loadbalancer, final List<Listener> listeners) {
return new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
final CreateLoadBalancerListenersWorkflowClientExternal workflow =
WorkflowClients.getCreateListenersWorkflow(accountId, loadbalancer);
workflow.createLoadBalancerListeners(accountId, loadbalancer,
listeners.toArray(new Listener[listeners.size()]));
return waitFor(new Supplier<ElbWorkflowState>() {
@Override
public ElbWorkflowState get() {
return workflow.getState();
}
});
}
};
}
public static Boolean deleteListenersSync(final String accountId, final String loadbalancer, final List<Integer> ports) {
final Future<Boolean> task = Threads.enqueue(LoadBalancing.class, LoadBalancingWorkflows.class,
deleteListenersImpl(accountId, loadbalancer, ports ));
try{
return task.get();
}catch(final Exception ex) {
return false;
}
}
public static void deleteListenersAsync(final String accountId, final String loadbalancer, final List<Integer> ports) {
Threads.enqueue(LoadBalancing.class, LoadBalancingWorkflows.class,
deleteListenersImpl(accountId, loadbalancer, ports ));
}
private static Callable<Boolean> deleteListenersImpl(final String accountId, final String loadbalancer, final List<Integer> ports) {
return new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
final DeleteLoadBalancerListenersWorkflowClientExternal workflow =
WorkflowClients.getDeleteListenersWorkflow(accountId, loadbalancer);
workflow.deleteLoadBalancerListeners(accountId, loadbalancer, ports.toArray(new Integer[ports.size()]));
return waitFor(new Supplier<ElbWorkflowState>() {
@Override
public ElbWorkflowState get() {
return workflow.getState();
}
});
}
};
}
public static boolean enableZonesSync(final String accountId, final String loadbalancer,
final List<String> availabilityZones, final Map<String,String> zoneToSubnetIdMap) {
final Future<Boolean> task = Threads.enqueue(LoadBalancing.class, LoadBalancingWorkflows.class, enableZonesImpl(accountId, loadbalancer, availabilityZones, zoneToSubnetIdMap ));
try{
return task.get();
}catch(final Exception ex) {
return false;
}
}
public static void enableZonesAsync(final String accountId, final String loadbalancer,
final List<String> availabilityZones, final Map<String,String> zoneToSubnetIdMap) {
Threads.enqueue(LoadBalancing.class, LoadBalancingWorkflows.class, enableZonesImpl(accountId, loadbalancer, availabilityZones, zoneToSubnetIdMap ));
}
private static Callable<Boolean> enableZonesImpl(final String accountId, final String loadbalancer,
final List<String> availabilityZones, final Map<String,String> zoneToSubnetIdMap) {
return new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
// TODO Auto-generated method stub
final EnableAvailabilityZoneWorkflowClientExternal workflow =
WorkflowClients.getEnableAvailabilityZoneClient(accountId,loadbalancer);
workflow.enableAvailabilityZone(accountId, loadbalancer,
availabilityZones,
zoneToSubnetIdMap);
return waitFor(new Supplier<ElbWorkflowState>() {
@Override
public ElbWorkflowState get() {
return workflow.getState();
}
});
}
};
}
public static Boolean disableZonesSync(final String accountId, final String loadbalancer,
final List<String> availabilityZones) {
final Future<Boolean> task = Threads.enqueue(LoadBalancing.class, LoadBalancingWorkflows.class, disableZonesImpl(accountId, loadbalancer, availabilityZones ));
try{
return task.get();
}catch(final Exception ex) {
return false;
}
}
public static void disableZonesAsync(final String accountId, final String loadbalancer,
final List<String> availabilityZones) {
Threads.enqueue(LoadBalancing.class, LoadBalancingWorkflows.class, disableZonesImpl(accountId, loadbalancer, availabilityZones ));
}
private static Callable<Boolean> disableZonesImpl(final String accountId, final String loadbalancer,
final List<String> availabilityZones) {
return new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
final DisableAvailabilityZoneWorkflowClientExternal workflow =
WorkflowClients.getDisableAvailabilityZoneClient(accountId, loadbalancer);
workflow.disableAvailabilityZone(accountId, loadbalancer, availabilityZones);
return waitFor(new Supplier<ElbWorkflowState>() {
@Override
public ElbWorkflowState get() {
return workflow.getState();
}
});
}
};
}
public static Boolean modifyLoadBalancerAttributesSync(final String accountId, final String loadbalancer,
final LoadBalancerAttributes attributes) {
final Future<Boolean> task =
Threads.enqueue(LoadBalancing.class, LoadBalancingWorkflows.class, modifyLoadBalancerAttributesImpl(accountId, loadbalancer, attributes ));
try{
return task.get();
}catch(final Exception ex) {
return false;
}
}
public static void modifyLoadBalancerAttributesASync(final String accountId, final String loadbalancer,
final LoadBalancerAttributes attributes) {
Threads.enqueue(LoadBalancing.class, LoadBalancingWorkflows.class, modifyLoadBalancerAttributesImpl(accountId, loadbalancer, attributes ));
}
private static Callable<Boolean> modifyLoadBalancerAttributesImpl(final String accountId, final String loadbalancer,
final LoadBalancerAttributes attributes) {
return new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
final ModifyLoadBalancerAttributesWorkflowClientExternal workflow =
WorkflowClients.getModifyLoadBalancerAttributesClient(accountId, loadbalancer);
workflow.modifyLoadBalancerAttributes(accountId, loadbalancer, attributes);
return waitFor(new Supplier<ElbWorkflowState>() {
@Override
public ElbWorkflowState get() {
return workflow.getState();
}
});
}
};
}
public static Boolean applySecurityGroupsSync(final String accountId, final String loadbalancer,
final Map<String,String> groupIdToNameMap) {
final Future<Boolean> task =
Threads.enqueue(LoadBalancing.class, LoadBalancingWorkflows.class,
applySecurityGroupsImpl(accountId, loadbalancer, groupIdToNameMap ));
try{
return task.get();
}catch(final Exception ex) {
return false;
}
}
public static void applySecurityGroupsAsync(final String accountId, final String loadbalancer,
final Map<String,String> groupIdToNameMap) {
Threads.enqueue(LoadBalancing.class, LoadBalancingWorkflows.class,
applySecurityGroupsImpl(accountId, loadbalancer, groupIdToNameMap ));
}
private static Callable<Boolean> applySecurityGroupsImpl(final String accountId, final String loadbalancer,
final Map<String,String> groupIdToNameMap) {
return new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
final ApplySecurityGroupsWorkflowClientExternal workflow =
WorkflowClients.getApplySecurityGroupsClient(accountId, loadbalancer);
workflow.applySecurityGroups(accountId, loadbalancer, groupIdToNameMap);
return waitFor(new Supplier<ElbWorkflowState>() {
@Override
public ElbWorkflowState get() {
return workflow.getState();
}
});
}
};
}
public static Boolean modifyServicePropertiesSync(final String emi, final String instanceType,
final String keyname, final String initScript ) {
final Future<Boolean> task =
Threads.enqueue(LoadBalancing.class, LoadBalancingWorkflows.class,
modifyServicePropertiesImpl( emi, instanceType, keyname, initScript ));
try{
return task.get();
}catch(final Exception ex) {
LOG.error("Failed run property modification workflow", ex);
return false;
}
}
public static void modifyServicePropertiesAsync( final String emi, final String instanceType,
final String keyname, final String initScript ) {
Threads.enqueue(LoadBalancing.class, LoadBalancingWorkflows.class,
modifyServicePropertiesImpl( emi, instanceType, keyname, initScript ));
}
private static Callable<Boolean> modifyServicePropertiesImpl( final String emi, final String instanceType,
final String keyname, final String initScript ) {
return new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
final ModifyServicePropertiesWorkflowClientExternal workflow =
WorkflowClients.getModifyServicePropertiesClient();
workflow.modifyServiceProperties(emi, instanceType, keyname, initScript);
return waitFor(new Supplier<ElbWorkflowState>() {
@Override
public ElbWorkflowState get() {
return workflow.getState();
}
});
}
};
}
private static Boolean waitFor(Supplier<ElbWorkflowState> supplier) {
ElbWorkflowState state = ElbWorkflowState.WORKFLOW_RUNNING;
do {
try{
Thread.sleep(500);
}catch(final Exception ex){
;
}
state = supplier.get();
} while (state == null || state == ElbWorkflowState.WORKFLOW_RUNNING );
return state == ElbWorkflowState.WORKFLOW_SUCCESS;
}
private static void waitForException(Supplier<ElbWorkflowState> supplier) throws LoadBalancingWorkflowException{
ElbWorkflowState state = ElbWorkflowState.WORKFLOW_RUNNING;
do {
try{
Thread.sleep(500);
}catch(final Exception ex){
;
}
state = supplier.get();
} while (state == null || state == ElbWorkflowState.WORKFLOW_RUNNING );
if (ElbWorkflowState.WORKFLOW_FAILED.equals(state)) {
final int statusCode = state.getStatusCode();
final String reason = state.getReason();
throw new LoadBalancingWorkflowException(reason, statusCode);
} else if (ElbWorkflowState.WORKFLOW_CANCELLED.equals(state)) {
throw new LoadBalancingWorkflowException("Cancelled workflow");
}
}
private static String getUpdateLoadBalancerWorkflowId(final String accountId, final String loadbalancer) {
return String.format("update-loadbalancer-%s-%s", accountId, loadbalancer);
}
public static void runUpdateLoadBalancer(final String accountId, final String loadbalancer) {
final String workflowId = getUpdateLoadBalancerWorkflowId(accountId, loadbalancer);
try{
final UpdateLoadBalancerWorkflowClientExternal workflow =
WorkflowClients.getUpdateLoadBalancerWorkflowClient(accountId, loadbalancer, workflowId);
workflow.updateLoadBalancer(accountId, loadbalancer);
}catch(final WorkflowExecutionAlreadyStartedException ex ) {
;
}catch(final Exception ex) {
throw Exceptions.toUndeclared("Failed to start update-loadbalancer workflow", ex);
}
}
public static void cancelUpdateLoadBalancer(final String accountId, final String loadbalancer) {
final String workflowId = getUpdateLoadBalancerWorkflowId(accountId, loadbalancer);
try{
final UpdateLoadBalancerWorkflowClientExternal workflow =
WorkflowClients.getUpdateLoadBalancerWorkflowClient(accountId, loadbalancer, workflowId);
workflow.requestCancelWorkflowExecution();
LOG.debug(String.format("Cancelled update-loadbalancer workflow for %s-%s",
accountId, loadbalancer));
}catch(final Exception ex) {
LOG.error("Failed to cancel update-loadbalancer workflow", ex);
}
}
public static void updateLoadBalancer(final String accountId, final String loadbalancer) {
final String workflowId = getUpdateLoadBalancerWorkflowId(accountId, loadbalancer);
try{
final UpdateLoadBalancerWorkflowClientExternal workflow =
WorkflowClients.getUpdateLoadBalancerWorkflowClient(accountId, loadbalancer, workflowId);
workflow.updateImmediately();
}catch(final UnknownResourceException ex) {
;
}catch(final Exception ex) {
LOG.error("Failed to signal update-loadbalancer workflow", ex);
}
}
private static String getInstanceStatusWorkflowId(final String accountId, final String loadbalancer) {
return String.format("instance-status-%s-%s", accountId, loadbalancer);
}
public static void pollInstanceStatus(final String accountId, final String loadbalancer) {
final String workflowId = getInstanceStatusWorkflowId(accountId, loadbalancer);
try{
final InstanceStatusWorkflowClientExternal workflow =
WorkflowClients.getinstanceStatusWorkflowClient(accountId, loadbalancer, workflowId);
workflow.pollImmediately();
}catch(final UnknownResourceException ex) {
;
}catch(final Exception ex) {
LOG.error("Failed to signal PollInstanceStatus workflow", ex);
}
}
public static void runInstanceStatusPolling(final String accountId, final String loadbalancer) {
final String workflowId = getInstanceStatusWorkflowId(accountId, loadbalancer);
try{
final InstanceStatusWorkflowClientExternal workflow =
WorkflowClients.getinstanceStatusWorkflowClient(accountId, loadbalancer, workflowId);
workflow.pollInstanceStatus(accountId, loadbalancer); // instances);
}catch(final WorkflowExecutionAlreadyStartedException ex ) {
;
}catch(final Exception ex) {
throw Exceptions.toUndeclared("Failed to start instance status polling workflow", ex);
}
}
public static void cancelInstanceStatusPolling(final String accountId, final String loadbalancer) {
final String workflowId = getInstanceStatusWorkflowId(accountId, loadbalancer);
try{
final InstanceStatusWorkflowClientExternal workflow =
WorkflowClients.getinstanceStatusWorkflowClient(accountId, loadbalancer, workflowId);
workflow.requestCancelWorkflowExecution();
LOG.debug(String.format("Cancelled instance polling workflow for %s-%s",
accountId, loadbalancer));
}catch(final Exception ex) {
LOG.error("Failed to cancel instance-polling workflow", ex);
}
}
private static String getCloudWatchPutMetricWorkflowId(final String accountId, final String loadbalancer) {
return String.format("cloudwatch-put-metric-%s-%s", accountId, loadbalancer);
}
public static void runCloudWatchPutMetric(final String accountId, final String loadbalancer) {
final String workflowId = getCloudWatchPutMetricWorkflowId(accountId, loadbalancer);
try{
final CloudWatchPutMetricWorkflowClientExternal workflow =
WorkflowClients.getPutMetricWorkflowClient(accountId, loadbalancer, workflowId);
workflow.putCloudWatchMetric(accountId, loadbalancer);
}catch(final WorkflowExecutionAlreadyStartedException ex ) {
;
}catch(final Exception ex) {
throw Exceptions.toUndeclared("Failed to start cloud-watch put-metric workflow", ex);
}
}
public static void cancelCloudWatchPutMetric(final String accountId, final String loadbalancer) {
final String workflowId = getCloudWatchPutMetricWorkflowId(accountId, loadbalancer);
if(workflowId != null) {
try{
final CloudWatchPutMetricWorkflowClientExternal workflow =
WorkflowClients.getPutMetricWorkflowClient(accountId, loadbalancer, workflowId);
workflow.requestCancelWorkflowExecution();
LOG.debug(String.format("Cancelled put-metric workflow for %s-%s",
accountId, loadbalancer));
}catch(final Exception ex) {
LOG.error("Failed to cancel put-metric workflow", ex);
}
}
}
}