/** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.airavata.orchestrator.server; import org.apache.airavata.common.exception.AiravataException; import org.apache.airavata.common.exception.ApplicationSettingsException; import org.apache.airavata.common.logging.MDCConstants; import org.apache.airavata.common.logging.MDCUtil; import org.apache.airavata.common.utils.AiravataUtils; import org.apache.airavata.common.utils.ServerSettings; import org.apache.airavata.common.utils.ThriftUtils; import org.apache.airavata.common.utils.ZkConstants; import org.apache.airavata.gfac.core.GFacUtils; import org.apache.airavata.gfac.core.scheduler.HostScheduler; import org.apache.airavata.messaging.core.*; import org.apache.airavata.model.appcatalog.appdeployment.ApplicationDeploymentDescription; import org.apache.airavata.model.appcatalog.appinterface.ApplicationInterfaceDescription; import org.apache.airavata.model.appcatalog.computeresource.ComputeResourceDescription; import org.apache.airavata.model.appcatalog.gatewayprofile.ComputeResourcePreference; import org.apache.airavata.model.appcatalog.gatewayprofile.GatewayResourceProfile; import org.apache.airavata.model.application.io.DataType; import org.apache.airavata.model.commons.ErrorModel; import org.apache.airavata.model.data.replica.DataProductModel; import org.apache.airavata.model.data.replica.DataReplicaLocationModel; import org.apache.airavata.model.data.replica.ReplicaLocationCategory; import org.apache.airavata.model.error.LaunchValidationException; import org.apache.airavata.model.error.ValidationResults; import org.apache.airavata.model.experiment.ExperimentModel; import org.apache.airavata.model.experiment.ExperimentType; import org.apache.airavata.model.messaging.event.*; import org.apache.airavata.model.process.ProcessModel; import org.apache.airavata.model.status.ExperimentState; import org.apache.airavata.model.status.ExperimentStatus; import org.apache.airavata.orchestrator.core.exception.OrchestratorException; import org.apache.airavata.orchestrator.cpi.OrchestratorService; import org.apache.airavata.orchestrator.cpi.impl.SimpleOrchestratorImpl; import org.apache.airavata.orchestrator.cpi.orchestrator_cpiConstants; import org.apache.airavata.orchestrator.util.OrchestratorServerThreadPoolExecutor; import org.apache.airavata.orchestrator.util.OrchestratorUtils; import org.apache.airavata.registry.core.app.catalog.resources.AppCatAbstractResource; import org.apache.airavata.registry.core.experiment.catalog.impl.RegistryFactory; import org.apache.airavata.registry.core.experiment.catalog.resources.AbstractExpCatResource; import org.apache.airavata.registry.cpi.*; import org.apache.commons.lang.StringUtils; import org.apache.curator.RetryPolicy; import org.apache.curator.framework.CuratorFramework; import org.apache.curator.framework.CuratorFrameworkFactory; import org.apache.curator.retry.ExponentialBackoffRetry; import org.apache.curator.utils.ZKPaths; import org.apache.thrift.TBase; import org.apache.thrift.TException; import org.apache.zookeeper.data.Stat; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.slf4j.MDC; import java.util.*; public class OrchestratorServerHandler implements OrchestratorService.Iface { private static Logger log = LoggerFactory.getLogger(OrchestratorServerHandler.class); private SimpleOrchestratorImpl orchestrator = null; private ExperimentCatalog experimentCatalog; private AppCatalog appCatalog; private static Integer mutex = new Integer(-1); private String airavataUserName; private String gatewayName; private Publisher publisher; private final Subscriber statusSubscribe; private final Subscriber experimentSubscriber; private CuratorFramework curatorClient; /** * Query orchestrator server to fetch the CPI version */ public String getOrchestratorCPIVersion() throws TException { return orchestrator_cpiConstants.ORCHESTRATOR_CPI_VERSION; } public OrchestratorServerHandler() throws OrchestratorException{ // orchestrator init try { // first constructing the monitorManager and orchestrator, then fill // the required properties setAiravataUserName(ServerSettings.getDefaultUser()); orchestrator = new SimpleOrchestratorImpl(); experimentCatalog = RegistryFactory.getDefaultExpCatalog(); appCatalog = RegistryFactory.getAppCatalog(); publisher = MessagingFactory.getPublisher(Type.STATUS); orchestrator.initialize(); orchestrator.getOrchestratorContext().setPublisher(this.publisher); statusSubscribe = getStatusSubscriber(); experimentSubscriber = getExperimentSubscriber(); startCurator(); } catch (OrchestratorException | RegistryException | AppCatalogException | AiravataException e) { log.error(e.getMessage(), e); throw new OrchestratorException("Error while initializing orchestrator service", e); } } private Subscriber getStatusSubscriber() throws AiravataException { List<String> routingKeys = new ArrayList<>(); // routingKeys.add("*"); // listen for gateway level messages // routingKeys.add("*.*"); // listen for gateway/experiment level messages routingKeys.add("*.*.*"); // listen for gateway/experiment/process level messages return MessagingFactory.getSubscriber(new ProcessStatusHandler(),routingKeys, Type.STATUS); } private Subscriber getExperimentSubscriber() throws AiravataException { List<String> routingKeys = new ArrayList<>(); routingKeys.add(ServerSettings.getRabbitmqExperimentLaunchQueueName()); return MessagingFactory.getSubscriber(new ExperimentHandler(), routingKeys, Type.EXPERIMENT_LAUNCH); } /** * * After creating the experiment Data user have the * experimentID as the * handler to the experiment, during the launchProcess * We just have to * give the experimentID * * @param experimentID * @return sucess/failure * * * * * @param experimentId */ public boolean launchExperiment(String experimentId, String gatewayId) throws TException { ExperimentModel experiment = null; try { String experimentNodePath = GFacUtils.getExperimentNodePath (experimentId); ZKPaths.mkdirs(curatorClient.getZookeeperClient().getZooKeeper(), experimentNodePath); String experimentCancelNode = ZKPaths.makePath(experimentNodePath, ZkConstants.ZOOKEEPER_CANCEL_LISTENER_NODE); ZKPaths.mkdirs(curatorClient.getZookeeperClient().getZooKeeper(), experimentCancelNode); experiment = (ExperimentModel) experimentCatalog.get(ExperimentCatalogModelType.EXPERIMENT, experimentId); if (experiment == null) { log.error("Error retrieving the Experiment by the given experimentID: {} ", experimentId); return false; } ComputeResourcePreference computeResourcePreference = appCatalog.getGatewayProfile(). getComputeResourcePreference(gatewayId, experiment.getUserConfigurationData().getComputationalResourceScheduling().getResourceHostId()); String token = computeResourcePreference.getResourceSpecificCredentialStoreToken(); if (token == null || token.isEmpty()){ // try with gateway profile level token GatewayResourceProfile gatewayProfile = appCatalog.getGatewayProfile().getGatewayProfile(gatewayId); token = gatewayProfile.getCredentialStoreToken(); } // still the token is empty, then we fail the experiment if (token == null || token.isEmpty()){ log.error("You have not configured credential store token at gateway profile or compute resource preference." + " Please provide the correct token at gateway profile or compute resource preference."); return false; } ExperimentType executionType = experiment.getExperimentType(); if (executionType == ExperimentType.SINGLE_APPLICATION) { //its an single application execution experiment List<ProcessModel> processes = orchestrator.createProcesses(experimentId, gatewayId); for (ProcessModel processModel : processes){ //FIXME Resolving replica if available. This is a very crude way of resolving input replicas. A full featured //FIXME replica resolving logic should come here ReplicaCatalog replicaCatalog = RegistryFactory.getReplicaCatalog(); processModel.getProcessInputs().stream().forEach(pi -> { if (pi.getType().equals(DataType.URI) && pi.getValue().startsWith("airavata-dp://")) { try { DataProductModel dataProductModel = replicaCatalog.getDataProduct(pi.getValue()); Optional<DataReplicaLocationModel> rpLocation = dataProductModel.getReplicaLocations() .stream().filter(rpModel -> rpModel.getReplicaLocationCategory(). equals(ReplicaLocationCategory.GATEWAY_DATA_STORE)).findFirst(); if (rpLocation.isPresent()) { pi.setValue(rpLocation.get().getFilePath()); pi.setStorageResourceId(rpLocation.get().getStorageResourceId()); } else { log.error("Could not find a replica for the URI " + pi.getValue()); } } catch (ReplicaCatalogException e) { log.error(e.getMessage(), e); } } else if (pi.getType().equals(DataType.URI_COLLECTION) && pi.getValue().contains("airavata-dp://")) { try { String[] uriList = pi.getValue().split(","); final ArrayList<String> filePathList = new ArrayList<>(); for (String uri : uriList) { if (uri.startsWith("airavata-dp://")) { DataProductModel dataProductModel = replicaCatalog.getDataProduct(uri); Optional<DataReplicaLocationModel> rpLocation = dataProductModel.getReplicaLocations() .stream().filter(rpModel -> rpModel.getReplicaLocationCategory(). equals(ReplicaLocationCategory.GATEWAY_DATA_STORE)).findFirst(); if (rpLocation.isPresent()) { filePathList.add(rpLocation.get().getFilePath()); } else { log.error("Could not find a replica for the URI " + pi.getValue()); } } else { // uri is in file path format filePathList.add(uri); } } pi.setValue(StringUtils.join(filePathList, ',')); } catch (ReplicaCatalogException e) { log.error(e.getMessage(), e); } } }); String taskDag = orchestrator.createAndSaveTasks(gatewayId, processModel, experiment.getUserConfigurationData().isAiravataAutoSchedule()); processModel.setTaskDag(taskDag); experimentCatalog.update(ExperimentCatalogModelType.PROCESS, processModel, processModel.getProcessId()); } if (!validateProcess(experimentId, processes)) { log.error("Validating process fails for given experiment Id : {}", experimentId); return false; } log.debug(experimentId, "Launching single application experiment {}.", experimentId); ExperimentStatus status = new ExperimentStatus(ExperimentState.LAUNCHED); status.setReason("submitted all processes"); status.setTimeOfStateChange(AiravataUtils.getCurrentTimestamp().getTime()); OrchestratorUtils.updageAndPublishExperimentStatus(experimentId, status, publisher, gatewayId); log.info("expId: {}, Launched experiment ", experimentId); OrchestratorServerThreadPoolExecutor.getCachedThreadPool().execute(MDCUtil.wrapWithMDC(new SingleAppExperimentRunner(experimentId, token, gatewayId))); } else if (executionType == ExperimentType.WORKFLOW) { //its a workflow execution experiment log.debug(experimentId, "Launching workflow experiment {}.", experimentId); launchWorkflowExperiment(experimentId, token, gatewayId); } else { log.error(experimentId, "Couldn't identify experiment type, experiment {} is neither single application nor workflow.", experimentId); throw new TException("Experiment '" + experimentId + "' launch failed. Unable to figureout execution type for application " + experiment.getExecutionId()); } } catch (LaunchValidationException launchValidationException) { ExperimentStatus status = new ExperimentStatus(ExperimentState.FAILED); status.setReason("Validation failed: " + launchValidationException.getErrorMessage()); status.setTimeOfStateChange(AiravataUtils.getCurrentTimestamp().getTime()); OrchestratorUtils.updageAndPublishExperimentStatus(experimentId, status, publisher, gatewayId); throw new TException("Experiment '" + experimentId + "' launch failed. Experiment failed to validate: " + launchValidationException.getErrorMessage(), launchValidationException); } catch (Exception e) { throw new TException("Experiment '" + experimentId + "' launch failed. Unable to figureout execution type for application " + experiment.getExecutionId(), e); } return true; } /** * This method will validate the experiment before launching, if is failed * we do not run the launch in airavata thrift service (only if validation * is enabled * * @param experimentId * @return * @throws TException */ public boolean validateExperiment(String experimentId) throws TException, LaunchValidationException { try { ExperimentModel experimentModel = (ExperimentModel)experimentCatalog.get(ExperimentCatalogModelType.EXPERIMENT, experimentId); return orchestrator.validateExperiment(experimentModel).isValidationState(); } catch (OrchestratorException e) { log.error(experimentId, "Error while validating experiment", e); throw new TException(e); } catch (RegistryException e) { log.error(experimentId, "Error while validating experiment", e); throw new TException(e); } } @Override public boolean validateProcess(String experimentId, List<ProcessModel> processes) throws LaunchValidationException, TException { try { ExperimentModel experimentModel = (ExperimentModel) experimentCatalog.get(ExperimentCatalogModelType.EXPERIMENT, experimentId); for (ProcessModel processModel : processes) { boolean state = orchestrator.validateProcess(experimentModel, processModel).isSetValidationState(); if (!state) { return false; } } return true; } catch (LaunchValidationException lve) { // If a process failed to validate, also add an error message at the experiment level ErrorModel details = new ErrorModel(); details.setActualErrorMessage(lve.getErrorMessage()); details.setCreationTime(Calendar.getInstance().getTimeInMillis()); try { experimentCatalog.add(ExpCatChildDataType.EXPERIMENT_ERROR, details, experimentId); } catch (RegistryException e) { log.error("Failed to add EXPERIMENT_ERROR regarding LaunchValidationException to experiment " + experimentId, e); } throw lve; } catch (OrchestratorException e) { log.error(experimentId, "Error while validating process", e); throw new TException(e); } catch (RegistryException e) { log.error(experimentId, "Error while validating process", e); throw new TException(e); } } /** * This can be used to cancel a running experiment and store the status to * terminated in registry * * @param experimentId * @return * @throws TException */ public boolean terminateExperiment(String experimentId, String gatewayId) throws TException { log.info(experimentId, "Experiment: {} is cancelling !!!!!", experimentId); try { return validateStatesAndCancel(experimentId, gatewayId); } catch (Exception e) { log.error("expId : " + experimentId + " :- Error while cancelling experiment", e); return false; } } private String getAiravataUserName() { return airavataUserName; } private String getGatewayName() { return gatewayName; } public void setAiravataUserName(String airavataUserName) { this.airavataUserName = airavataUserName; } public void setGatewayName(String gatewayName) { this.gatewayName = gatewayName; } @Override public boolean launchProcess(String processId, String airavataCredStoreToken, String gatewayId) throws TException { try { ProcessModel processModel = (ProcessModel) experimentCatalog.get( ExperimentCatalogModelType.PROCESS, processId); String applicationId = processModel.getApplicationInterfaceId(); if (applicationId == null) { log.error(processId, "Application interface id shouldn't be null."); throw new OrchestratorException("Error executing the job, application interface id shouldn't be null."); } // set application deployment id to process model ApplicationDeploymentDescription applicationDeploymentDescription = getAppDeployment(processModel, applicationId); processModel.setApplicationDeploymentId(applicationDeploymentDescription.getAppDeploymentId()); // set compute resource id to process model, default we set the same in the user preferred compute host id processModel.setComputeResourceId(processModel.getProcessResourceSchedule().getResourceHostId()); experimentCatalog.update(ExperimentCatalogModelType.PROCESS, processModel,processModel.getProcessId()); return orchestrator.launchProcess(processModel, airavataCredStoreToken); } catch (Exception e) { log.error(processId, "Error while launching process ", e); throw new TException(e); } } private ApplicationDeploymentDescription getAppDeployment(ProcessModel processModel, String applicationId) throws AppCatalogException, OrchestratorException, ClassNotFoundException, ApplicationSettingsException, InstantiationException, IllegalAccessException { String selectedModuleId = getModuleId(appCatalog, applicationId); return getAppDeploymentForModule(processModel, selectedModuleId); } private ApplicationDeploymentDescription getAppDeploymentForModule(ProcessModel processModel, String selectedModuleId) throws AppCatalogException, ClassNotFoundException, ApplicationSettingsException, InstantiationException, IllegalAccessException { Map<String, String> moduleIdFilter = new HashMap<String, String>(); moduleIdFilter.put(AppCatAbstractResource.ApplicationDeploymentConstants.APP_MODULE_ID, selectedModuleId); if (processModel.getProcessResourceSchedule() != null && processModel.getProcessResourceSchedule().getResourceHostId() != null) { moduleIdFilter.put(AppCatAbstractResource.ApplicationDeploymentConstants.COMPUTE_HOST_ID, processModel.getProcessResourceSchedule().getResourceHostId()); } List<ApplicationDeploymentDescription> applicationDeployements = appCatalog.getApplicationDeployment().getApplicationDeployements(moduleIdFilter); Map<ComputeResourceDescription, ApplicationDeploymentDescription> deploymentMap = new HashMap<ComputeResourceDescription, ApplicationDeploymentDescription>(); ComputeResource computeResource = appCatalog.getComputeResource(); for (ApplicationDeploymentDescription deploymentDescription : applicationDeployements) { deploymentMap.put(computeResource.getComputeResource(deploymentDescription.getComputeHostId()), deploymentDescription); } List<ComputeResourceDescription> computeHostList = Arrays.asList(deploymentMap.keySet().toArray(new ComputeResourceDescription[]{})); Class<? extends HostScheduler> aClass = Class.forName( ServerSettings.getHostScheduler()).asSubclass( HostScheduler.class); HostScheduler hostScheduler = aClass.newInstance(); ComputeResourceDescription ComputeResourceDescription = hostScheduler.schedule(computeHostList); return deploymentMap.get(ComputeResourceDescription); } private String getModuleId(AppCatalog appCatalog, String applicationId) throws AppCatalogException, OrchestratorException { ApplicationInterfaceDescription applicationInterface = appCatalog.getApplicationInterface().getApplicationInterface(applicationId); List<String> applicationModules = applicationInterface.getApplicationModules(); if (applicationModules.size()==0){ throw new OrchestratorException( "No modules defined for application " + applicationId); } // AiravataAPI airavataAPI = getAiravataAPI(); String selectedModuleId=applicationModules.get(0); return selectedModuleId; } private boolean validateStatesAndCancel(String experimentId, String gatewayId) throws Exception { ExperimentStatus experimentStatus = OrchestratorUtils.getExperimentStatus(experimentId); switch (experimentStatus.getState()) { case COMPLETED: case CANCELED: case FAILED: case CANCELING: log.warn("Can't terminate already {} experiment", experimentStatus.getState().name()); return false; case CREATED: log.warn("Experiment termination is only allowed for launched experiments."); return false; default: String expCancelNodePath = ZKPaths.makePath(ZKPaths.makePath(ZkConstants.ZOOKEEPER_EXPERIMENT_NODE, experimentId), ZkConstants.ZOOKEEPER_CANCEL_LISTENER_NODE); Stat stat = curatorClient.checkExists().forPath(expCancelNodePath); if (stat != null) { curatorClient.setData().withVersion(-1).forPath(expCancelNodePath, ZkConstants.ZOOKEEPER_CANCEL_REQEUST .getBytes()); ExperimentStatus status = new ExperimentStatus(ExperimentState.CANCELING); status.setReason("Experiment cancel request processed"); status.setTimeOfStateChange(AiravataUtils.getCurrentTimestamp().getTime()); OrchestratorUtils.updageAndPublishExperimentStatus(experimentId, status, publisher, gatewayId); log.info("expId : " + experimentId + " :- Experiment status updated to " + status.getState()); return true; } return false; } } private void launchWorkflowExperiment(String experimentId, String airavataCredStoreToken, String gatewayId) throws TException { // FIXME // try { // WorkflowEnactmentService.getInstance(). // submitWorkflow(experimentId, airavataCredStoreToken, getGatewayName(), getRabbitMQProcessPublisher()); // } catch (Exception e) { // log.error("Error while launching workflow", e); // } } private void startCurator() throws ApplicationSettingsException { String connectionSting = ServerSettings.getZookeeperConnection(); RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 5); curatorClient = CuratorFrameworkFactory.newClient(connectionSting, retryPolicy); curatorClient.start(); } private class SingleAppExperimentRunner implements Runnable { String experimentId; String airavataCredStoreToken; String gatewayId; public SingleAppExperimentRunner(String experimentId,String airavataCredStoreToken, String gatewayId){ this.experimentId = experimentId; this.airavataCredStoreToken = airavataCredStoreToken; this.gatewayId = gatewayId; } @Override public void run() { try { launchSingleAppExperiment(); } catch (TException e) { log.error("Unable to launch experiment..", e); } catch (AiravataException e) { log.error("Unable to publish experiment status..", e); } } private boolean launchSingleAppExperiment() throws TException, AiravataException { try { List<String> processIds = experimentCatalog.getIds(ExperimentCatalogModelType.PROCESS, AbstractExpCatResource.ProcessConstants.EXPERIMENT_ID, experimentId); for (String processId : processIds) { launchProcess(processId, airavataCredStoreToken, gatewayId); } // ExperimentStatus status = new ExperimentStatus(ExperimentState.LAUNCHED); // status.setReason("submitted all processes"); // status.setTimeOfStateChange(AiravataUtils.getCurrentTimestamp().getTime()); // OrchestratorUtils.updageAndPublishExperimentStatus(experimentId, status); // log.info("expId: {}, Launched experiment ", experimentId); } catch (Exception e) { ExperimentStatus status = new ExperimentStatus(ExperimentState.FAILED); status.setReason("Error while updating task status"); OrchestratorUtils.updageAndPublishExperimentStatus(experimentId, status, publisher, gatewayId); log.error("expId: " + experimentId + ", Error while updating task status, hence updated experiment status to " + ExperimentState.FAILED, e); ExperimentStatusChangeEvent event = new ExperimentStatusChangeEvent(ExperimentState.FAILED, experimentId, gatewayId); String messageId = AiravataUtils.getId("EXPERIMENT"); MessageContext messageContext = new MessageContext(event, MessageType.EXPERIMENT, messageId, gatewayId); messageContext.setUpdatedTime(AiravataUtils.getCurrentTimestamp()); publisher.publish(messageContext); throw new TException(e); } return true; } } private class ProcessStatusHandler implements MessageHandler { /** * This method only handle MessageType.PROCESS type messages. * @param message */ @Override public void onMessage(MessageContext message) { if (message.getType().equals(MessageType.PROCESS)) { try { ProcessStatusChangeEvent processStatusChangeEvent = new ProcessStatusChangeEvent(); TBase event = message.getEvent(); byte[] bytes = ThriftUtils.serializeThriftObject(event); ThriftUtils.createThriftFromBytes(bytes, processStatusChangeEvent); ExperimentStatus status = new ExperimentStatus(); ProcessIdentifier processIdentity = processStatusChangeEvent.getProcessIdentity(); log.info("expId: {}, processId: {} :- Process status changed event received for status {}", processIdentity.getExperimentId(), processIdentity.getProcessId(), processStatusChangeEvent.getState().name()); switch (processStatusChangeEvent.getState()) { // case CREATED: // case VALIDATED: case STARTED: try { ExperimentStatus stat = OrchestratorUtils.getExperimentStatus(processIdentity .getExperimentId()); if (stat.getState() == ExperimentState.CANCELING) { status.setState(ExperimentState.CANCELING); status.setReason("Process started but experiment cancelling is triggered"); } else { status.setState(ExperimentState.EXECUTING); status.setReason("process started"); } } catch (RegistryException e) { status.setState(ExperimentState.EXECUTING); status.setReason("process started"); } break; // case PRE_PROCESSING: // break; // case CONFIGURING_WORKSPACE: // case INPUT_DATA_STAGING: // case EXECUTING: // case MONITORING: // case OUTPUT_DATA_STAGING: // case POST_PROCESSING: // case CANCELLING: // break; case COMPLETED: try { ExperimentStatus stat = OrchestratorUtils.getExperimentStatus(processIdentity .getExperimentId()); if (stat.getState() == ExperimentState.CANCELING) { status.setState(ExperimentState.CANCELED); status.setReason("Process competed but experiment cancelling is triggered"); } else { status.setState(ExperimentState.COMPLETED); status.setReason("process completed"); } } catch (RegistryException e) { status.setState(ExperimentState.COMPLETED); status.setReason("process completed"); } break; case FAILED: try { ExperimentStatus stat = OrchestratorUtils.getExperimentStatus(processIdentity .getExperimentId()); if (stat.getState() == ExperimentState.CANCELING) { status.setState(ExperimentState.CANCELED); status.setReason("Process failed but experiment cancelling is triggered"); } else { status.setState(ExperimentState.FAILED); status.setReason("process failed"); } } catch (RegistryException e) { status.setState(ExperimentState.FAILED); status.setReason("process failed"); } break; case CANCELED: // TODO if experiment have more than one process associated with it, then this should be changed. status.setState(ExperimentState.CANCELED); status.setReason("process cancelled"); break; default: // ignore other status changes, thoes will not affect for experiment status changes return; } if (status.getState() != null) { status.setTimeOfStateChange(AiravataUtils.getCurrentTimestamp().getTime()); OrchestratorUtils.updageAndPublishExperimentStatus(processIdentity.getExperimentId(), status, publisher, processIdentity.getGatewayId()); log.info("expId : " + processIdentity.getExperimentId() + " :- Experiment status updated to " + status.getState()); } } catch (TException e) { log.error("Message Id : " + message.getMessageId() + ", Message type : " + message.getType() + "Error" + " while prcessing process status change event"); } } else { System.out.println("Message Recieved with message id " + message.getMessageId() + " and with message " + "type " + message.getType().name()); } } } private class ExperimentHandler implements MessageHandler { @Override public void onMessage(MessageContext messageContext) { MDC.put(MDCConstants.GATEWAY_ID, messageContext.getGatewayId()); switch (messageContext.getType()) { case EXPERIMENT: launchExperiment(messageContext); break; case EXPERIMENT_CANCEL: cancelExperiment(messageContext); break; default: experimentSubscriber.sendAck(messageContext.getDeliveryTag()); log.error("Orchestrator got un-support message type : " + messageContext.getType()); break; } MDC.clear(); } private void cancelExperiment(MessageContext messageContext) { try { byte[] bytes = ThriftUtils.serializeThriftObject(messageContext.getEvent()); ExperimentSubmitEvent expEvent = new ExperimentSubmitEvent(); ThriftUtils.createThriftFromBytes(bytes, expEvent); log.info("Cancelling experiment with experimentId: {} gateway Id: {}", expEvent.getExperimentId(), expEvent.getGatewayId()); terminateExperiment(expEvent.getExperimentId(), expEvent.getGatewayId()); } catch (TException e) { log.error("Experiment cancellation failed due to Thrift conversion error", e); }finally { experimentSubscriber.sendAck(messageContext.getDeliveryTag()); } } } private void launchExperiment(MessageContext messageContext) { ExperimentSubmitEvent expEvent = new ExperimentSubmitEvent(); try { byte[] bytes = ThriftUtils.serializeThriftObject(messageContext.getEvent()); ThriftUtils.createThriftFromBytes(bytes, expEvent); MDC.put(MDCConstants.EXPERIMENT_ID, expEvent.getExperimentId()); log.info("Launching experiment with experimentId: {} gateway Id: {}", expEvent.getExperimentId(), expEvent.getGatewayId()); if (messageContext.isRedeliver()) { ExperimentModel experimentModel = (ExperimentModel) experimentCatalog. get(ExperimentCatalogModelType.EXPERIMENT, expEvent.getExperimentId()); MDC.put(MDCConstants.EXPERIMENT_NAME, experimentModel.getExperimentName()); if (experimentModel.getExperimentStatus().get(0).getState() == ExperimentState.CREATED) { launchExperiment(expEvent.getExperimentId(), expEvent.getGatewayId()); } } else { launchExperiment(expEvent.getExperimentId(), expEvent.getGatewayId()); } } catch (TException e) { String logMessage = expEvent.getExperimentId() != null && expEvent.getGatewayId() != null ? String.format("Experiment launch failed due to Thrift conversion error, experimentId: %s, gatewayId: %s", expEvent.getExperimentId(), expEvent.getGatewayId()): "Experiment launch failed due to Thrift conversion error"; log.error(logMessage, e); } catch (RegistryException e) { String logMessage = expEvent.getExperimentId() != null && expEvent.getGatewayId() != null ? String.format("Experiment launch failed due to registry access issue, experimentId: %s, gatewayId: %s", expEvent.getExperimentId(), expEvent.getGatewayId()): "Experiment launch failed due to registry access issue"; log.error(logMessage, e); }finally { experimentSubscriber.sendAck(messageContext.getDeliveryTag()); MDC.clear(); } } }