/*
* ProActive Parallel Suite(TM):
* The Open Source library for parallel and distributed
* Workflows & Scheduling, Orchestration, Cloud Automation
* and Big Data Analysis on Enterprise Grids & Clouds.
*
* Copyright (c) 2007 - 2017 ActiveEon
* Contact: contact@activeeon.com
*
* This library is free software: you can redistribute it and/or
* modify it under the terms of the GNU Affero 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* If needed, contact us to obtain a release under GPL Version 2 or 3
* or a different license than the AGPL.
*/
package org.ow2.proactive.scheduler.core;
import static org.ow2.proactive.scheduler.core.SchedulerFrontendState.YOU_DO_NOT_HAVE_PERMISSIONS_TO_GET_THE_LOGS_OF_THIS_JOB;
import static org.ow2.proactive.scheduler.core.SchedulerFrontendState.YOU_DO_NOT_HAVE_PERMISSION_TO_FINISH_THIS_TASK;
import static org.ow2.proactive.scheduler.core.SchedulerFrontendState.YOU_DO_NOT_HAVE_PERMISSION_TO_FREEZE_THE_SCHEDULER;
import static org.ow2.proactive.scheduler.core.SchedulerFrontendState.YOU_DO_NOT_HAVE_PERMISSION_TO_GET_THE_RESULT_OF_THIS_JOB;
import static org.ow2.proactive.scheduler.core.SchedulerFrontendState.YOU_DO_NOT_HAVE_PERMISSION_TO_GET_THE_TASK_LOGS_OF_THIS_JOB;
import static org.ow2.proactive.scheduler.core.SchedulerFrontendState.YOU_DO_NOT_HAVE_PERMISSION_TO_GET_THE_TASK_RESULT_OF_THIS_JOB;
import static org.ow2.proactive.scheduler.core.SchedulerFrontendState.YOU_DO_NOT_HAVE_PERMISSION_TO_KILL_THE_SCHEDULER;
import static org.ow2.proactive.scheduler.core.SchedulerFrontendState.YOU_DO_NOT_HAVE_PERMISSION_TO_KILL_THIS_JOB;
import static org.ow2.proactive.scheduler.core.SchedulerFrontendState.YOU_DO_NOT_HAVE_PERMISSION_TO_KILL_THIS_TASK;
import static org.ow2.proactive.scheduler.core.SchedulerFrontendState.YOU_DO_NOT_HAVE_PERMISSION_TO_LISTEN_THE_LOG_OF_THIS_JOB;
import static org.ow2.proactive.scheduler.core.SchedulerFrontendState.YOU_DO_NOT_HAVE_PERMISSION_TO_LIST_THIRD_PARTY_CREDENTIALS_IN_THE_SCHEDULER;
import static org.ow2.proactive.scheduler.core.SchedulerFrontendState.YOU_DO_NOT_HAVE_PERMISSION_TO_PAUSE_THE_SCHEDULER;
import static org.ow2.proactive.scheduler.core.SchedulerFrontendState.YOU_DO_NOT_HAVE_PERMISSION_TO_PAUSE_THIS_JOB;
import static org.ow2.proactive.scheduler.core.SchedulerFrontendState.YOU_DO_NOT_HAVE_PERMISSION_TO_PREEMPT_THIS_TASK;
import static org.ow2.proactive.scheduler.core.SchedulerFrontendState.YOU_DO_NOT_HAVE_PERMISSION_TO_PUT_THIRD_PARTY_CREDENTIALS_IN_THE_SCHEDULER;
import static org.ow2.proactive.scheduler.core.SchedulerFrontendState.YOU_DO_NOT_HAVE_PERMISSION_TO_RELOAD_POLICY_CONFIGURATION;
import static org.ow2.proactive.scheduler.core.SchedulerFrontendState.YOU_DO_NOT_HAVE_PERMISSION_TO_REMOVE_THIRD_PARTY_CREDENTIALS_FROM_THE_SCHEDULER;
import static org.ow2.proactive.scheduler.core.SchedulerFrontendState.YOU_DO_NOT_HAVE_PERMISSION_TO_REMOVE_THIS_JOB;
import static org.ow2.proactive.scheduler.core.SchedulerFrontendState.YOU_DO_NOT_HAVE_PERMISSION_TO_RESTART_IN_ERROR_TASKS_IN_THIS_JOB;
import static org.ow2.proactive.scheduler.core.SchedulerFrontendState.YOU_DO_NOT_HAVE_PERMISSION_TO_RESTART_THIS_TASK;
import static org.ow2.proactive.scheduler.core.SchedulerFrontendState.YOU_DO_NOT_HAVE_PERMISSION_TO_RESUME_THE_SCHEDULER;
import static org.ow2.proactive.scheduler.core.SchedulerFrontendState.YOU_DO_NOT_HAVE_PERMISSION_TO_RESUME_THIS_JOB;
import static org.ow2.proactive.scheduler.core.SchedulerFrontendState.YOU_DO_NOT_HAVE_PERMISSION_TO_SHUTDOWN_THE_SCHEDULER;
import static org.ow2.proactive.scheduler.core.SchedulerFrontendState.YOU_DO_NOT_HAVE_PERMISSION_TO_START_THE_SCHEDULER;
import static org.ow2.proactive.scheduler.core.SchedulerFrontendState.YOU_DO_NOT_HAVE_PERMISSION_TO_STOP_THE_SCHEDULER;
import static org.ow2.proactive.scheduler.core.SchedulerFrontendState.YOU_DO_NOT_HAVE_PERMISSION_TO_SUBMIT_A_JOB;
import java.net.URI;
import java.security.KeyException;
import java.security.PublicKey;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import org.apache.log4j.Logger;
import org.objectweb.proactive.Body;
import org.objectweb.proactive.InitActive;
import org.objectweb.proactive.RunActive;
import org.objectweb.proactive.Service;
import org.objectweb.proactive.annotation.ImmediateService;
import org.objectweb.proactive.api.PAActiveObject;
import org.objectweb.proactive.core.UniqueID;
import org.objectweb.proactive.core.body.request.Request;
import org.objectweb.proactive.extensions.annotation.ActiveObject;
import org.objectweb.proactive.utils.NamedThreadFactory;
import org.ow2.proactive.authentication.crypto.Credentials;
import org.ow2.proactive.authentication.crypto.HybridEncryptionUtil;
import org.ow2.proactive.db.DatabaseManagerException;
import org.ow2.proactive.db.SortParameter;
import org.ow2.proactive.policy.ClientsPolicy;
import org.ow2.proactive.resourcemanager.frontend.RMConnection;
import org.ow2.proactive.scheduler.authentication.SchedulerAuthentication;
import org.ow2.proactive.scheduler.common.JobFilterCriteria;
import org.ow2.proactive.scheduler.common.JobSortParameter;
import org.ow2.proactive.scheduler.common.Page;
import org.ow2.proactive.scheduler.common.Scheduler;
import org.ow2.proactive.scheduler.common.SchedulerConnection;
import org.ow2.proactive.scheduler.common.SchedulerConstants;
import org.ow2.proactive.scheduler.common.SchedulerEvent;
import org.ow2.proactive.scheduler.common.SchedulerEventListener;
import org.ow2.proactive.scheduler.common.SchedulerState;
import org.ow2.proactive.scheduler.common.SchedulerStatus;
import org.ow2.proactive.scheduler.common.SortSpecifierContainer;
import org.ow2.proactive.scheduler.common.exception.AlreadyConnectedException;
import org.ow2.proactive.scheduler.common.exception.JobAlreadyFinishedException;
import org.ow2.proactive.scheduler.common.exception.JobCreationException;
import org.ow2.proactive.scheduler.common.exception.NotConnectedException;
import org.ow2.proactive.scheduler.common.exception.PermissionException;
import org.ow2.proactive.scheduler.common.exception.SubmissionClosedException;
import org.ow2.proactive.scheduler.common.exception.TaskCouldNotRestartException;
import org.ow2.proactive.scheduler.common.exception.TaskCouldNotStartException;
import org.ow2.proactive.scheduler.common.exception.TaskSkippedException;
import org.ow2.proactive.scheduler.common.exception.UnknownJobException;
import org.ow2.proactive.scheduler.common.exception.UnknownTaskException;
import org.ow2.proactive.scheduler.common.job.Job;
import org.ow2.proactive.scheduler.common.job.JobId;
import org.ow2.proactive.scheduler.common.job.JobInfo;
import org.ow2.proactive.scheduler.common.job.JobPriority;
import org.ow2.proactive.scheduler.common.job.JobResult;
import org.ow2.proactive.scheduler.common.job.JobState;
import org.ow2.proactive.scheduler.common.job.TaskFlowJob;
import org.ow2.proactive.scheduler.common.task.SimpleTaskLogs;
import org.ow2.proactive.scheduler.common.task.TaskId;
import org.ow2.proactive.scheduler.common.task.TaskInfo;
import org.ow2.proactive.scheduler.common.task.TaskResult;
import org.ow2.proactive.scheduler.common.task.TaskState;
import org.ow2.proactive.scheduler.common.usage.JobUsage;
import org.ow2.proactive.scheduler.common.util.logforwarder.AppenderProvider;
import org.ow2.proactive.scheduler.core.account.SchedulerAccountsManager;
import org.ow2.proactive.scheduler.core.db.RecoveredSchedulerState;
import org.ow2.proactive.scheduler.core.db.SchedulerDBManager;
import org.ow2.proactive.scheduler.core.db.SchedulerStateRecoverHelper;
import org.ow2.proactive.scheduler.core.jmx.SchedulerJMXHelper;
import org.ow2.proactive.scheduler.core.properties.PASchedulerProperties;
import org.ow2.proactive.scheduler.core.rmproxies.RMProxiesManager;
import org.ow2.proactive.scheduler.job.IdentifiedJob;
import org.ow2.proactive.scheduler.job.InternalJob;
import org.ow2.proactive.scheduler.job.JobIdImpl;
import org.ow2.proactive.scheduler.job.SchedulerUserInfo;
import org.ow2.proactive.scheduler.job.UserIdentificationImpl;
import org.ow2.proactive.scheduler.task.TaskResultImpl;
import org.ow2.proactive.scheduler.util.JobLogger;
import org.ow2.proactive.scheduler.util.SchedulerPortalConfiguration;
import org.ow2.proactive.scheduler.util.ServerJobAndTaskLogs;
import org.ow2.proactive.utils.Tools;
/**
* Scheduler Front-end. This is the API to talk to when you want to managed a
* scheduler core. Creating this class can only be done by using
* <code>SchedulerFactory</code>. You can join this front-end by using the
* <code>join()</code> method in {@link SchedulerConnection}.
*
* @author The ProActive Team
* @since ProActive Scheduling 0.9
*/
@ActiveObject
public class SchedulerFrontend implements InitActive, Scheduler, RunActive {
/**
* Delay to wait for between getting a job result and removing the job
* concerned
*/
private static final long SCHEDULER_REMOVED_JOB_DELAY = PASchedulerProperties.SCHEDULER_REMOVED_JOB_DELAY.getValueAsInt() *
1000;
private static final Logger logger = Logger.getLogger(SchedulerFrontend.class);
private static final JobLogger jlogger = JobLogger.getInstance();
/**
* Temporary rmURL at starting process
*/
private URI rmURL;
/**
* Authentication Interface
*/
private SchedulerAuthentication authentication;
/**
* Full name of the policy class
*/
private String policyFullName;
/**
* JMX Helper reference
*/
private SchedulerJMXHelper jmxHelper;
private SchedulingService schedulingService;
private SchedulerDBManager dbManager;
private SchedulerFrontendState frontendState;
private SchedulerSpacesSupport spacesSupport;
private PublicKey corePublicKey;
private SchedulerPortalConfiguration schedulerPortalConfiguration = SchedulerPortalConfiguration.getConfiguration();
/*
* ######################################################################### ##################
*/
/* */
/*
* ################################## SCHEDULER CONSTRUCTION #################################
*/
/* */
/*
* ######################################################################### ##################
*/
/**
* ProActive empty constructor
*/
public SchedulerFrontend() {
}
/**
* Mainly there for testing purposes.
*
* It allows to create a SchedulerFrontend instance without breaking
* encapsulation.
*
* @param schedulerSpacesSupport
*/
SchedulerFrontend(SchedulerFrontendState schedulerFrontendState, SchedulerSpacesSupport schedulerSpacesSupport) {
this.frontendState = schedulerFrontendState;
this.spacesSupport = schedulerSpacesSupport;
}
/**
* Scheduler Front-end constructor.
*
* @param rmURL
* a started Resource Manager URL which be able to managed the
* resource used by scheduler.
* @param policyFullClassName
* the full class name of the policy to use.
*/
public SchedulerFrontend(URI rmURL, String policyFullClassName) {
this.dbManager = SchedulerDBManager.createUsingProperties();
SchedulerAccountsManager accountsManager = new SchedulerAccountsManager(dbManager);
this.jmxHelper = new SchedulerJMXHelper(accountsManager, dbManager);
logger.debug("Creating scheduler Front-end...");
this.rmURL = rmURL;
this.policyFullName = policyFullClassName;
logger.debug("Policy used is " + policyFullClassName);
}
/**
* @see org.objectweb.proactive.InitActive#initActivity(org.objectweb.proactive.Body)
*/
@Override
public void initActivity(Body body) {
try {
// setting up the policy
logger.debug("Setting up scheduler security policy");
ClientsPolicy.init();
// creating the scheduler authentication interface.
// if this fails then it will not continue.
logger.debug("Creating scheduler authentication interface...");
authentication = PAActiveObject.newActive(SchedulerAuthentication.class,
new Object[] { PAActiveObject.getStubOnThis() });
// creating scheduler core
DataSpaceServiceStarter dsServiceStarter = DataSpaceServiceStarter.getDataSpaceServiceStarter();
dsServiceStarter.startNamingService();
ExecutorService clientThreadPool = Executors.newFixedThreadPool(PASchedulerProperties.SCHEDULER_CLIENT_POOL_NBTHREAD.getValueAsInt(),
new NamedThreadFactory("ClientRequestsThreadPool"));
ExecutorService internalThreadPool = Executors.newFixedThreadPool(PASchedulerProperties.SCHEDULER_INTERNAL_POOL_NBTHREAD.getValueAsInt(),
new NamedThreadFactory("InternalOperationsThreadPool"));
ExecutorService taskPingerThreadPool = Executors.newFixedThreadPool(PASchedulerProperties.SCHEDULER_TASK_PINGER_POOL_NBTHREAD.getValueAsInt(),
new NamedThreadFactory("TaskPingerThreadPool"));
ScheduledExecutorService scheduledThreadPool = new ScheduledThreadPoolExecutor(PASchedulerProperties.SCHEDULER_SCHEDULED_POOL_NBTHREAD.getValueAsInt(),
new NamedThreadFactory("SchedulingServiceTimerThread"));
// at this point we must wait the resource manager
RMConnection.waitAndJoin(rmURL.toString());
RMProxiesManager rmProxiesManager = RMProxiesManager.createRMProxiesManager(rmURL);
rmProxiesManager.getRmProxy();
long loadJobPeriod = -1;
if (PASchedulerProperties.SCHEDULER_DB_LOAD_JOB_PERIOD.isSet()) {
String periodStr = PASchedulerProperties.SCHEDULER_DB_LOAD_JOB_PERIOD.getValueAsString();
if (periodStr != null && !periodStr.isEmpty()) {
try {
loadJobPeriod = Tools.parsePeriod(periodStr);
} catch (IllegalArgumentException e) {
logger.warn("Invalid load job period string: " + periodStr + ", this setting is ignored", e);
}
}
}
logger.debug("Booting jmx...");
this.jmxHelper.boot(authentication);
RecoveredSchedulerState recoveredState = new SchedulerStateRecoverHelper(dbManager).recover(loadJobPeriod);
this.frontendState = new SchedulerFrontendState(recoveredState.getSchedulerState(), jmxHelper);
SchedulingInfrastructure infrastructure = new SchedulingInfrastructureImpl(dbManager,
rmProxiesManager,
dsServiceStarter,
clientThreadPool,
internalThreadPool,
taskPingerThreadPool,
scheduledThreadPool);
this.spacesSupport = infrastructure.getSpacesSupport();
this.corePublicKey = Credentials.getPublicKey(PASchedulerProperties.getAbsolutePath(PASchedulerProperties.SCHEDULER_AUTH_PUBKEY_PATH.getValueAsString()));
this.schedulingService = new SchedulingService(infrastructure,
frontendState,
recoveredState,
policyFullName,
null);
logger.debug("Registering scheduler...");
PAActiveObject.registerByName(authentication, SchedulerConstants.SCHEDULER_DEFAULT_NAME);
authentication.setActivated(true);
Tools.logAvailableScriptEngines(logger);
// run !!
} catch (Exception e) {
logger.error("Failed to start Scheduler", e);
e.printStackTrace();
System.exit(1);
}
}
/*
* ######################################################################### ##################
*/
/* */
/*
* ################################### SCHEDULING MANAGEMENT #################################
*/
/* */
/*
* ######################################################################### ##################
*/
/**
* Connect a new user on the scheduler. This user can interact with the
* scheduler according to his right.
*
* @param sourceBodyID
* the source ID of the connected object representing a user
* @param identification
* the identification of the connected user
* @param cred
* the credentials of the user
* @throws AlreadyConnectedException
* if the user is already connected
*/
public void connect(UniqueID sourceBodyID, UserIdentificationImpl identification, Credentials cred)
throws AlreadyConnectedException {
this.frontendState.connect(sourceBodyID, identification, cred);
this.spacesSupport.registerUserSpace(identification.getUsername());
}
/**
* {@inheritDoc}
*/
@Override
public JobId submit(Job userJob)
throws NotConnectedException, PermissionException, SubmissionClosedException, JobCreationException {
if (logger.isDebugEnabled()) {
logger.debug("New job submission requested : " + userJob.getName());
}
// check if the scheduler is stopped
if (!schedulingService.isSubmitPossible()) {
String msg = "Scheduler is stopped, cannot submit job";
logger.info(msg);
throw new SubmissionClosedException(msg);
}
UserIdentificationImpl ident = frontendState.checkPermission("submit",
YOU_DO_NOT_HAVE_PERMISSION_TO_SUBMIT_A_JOB);
InternalJob job = frontendState.createJob(userJob, ident);
schedulingService.submitJob(job);
frontendState.jobSubmitted(job, ident);
return job.getId();
}
/**
* {@inheritDoc}
*/
@Override
public List<String> getUserSpaceURIs() throws NotConnectedException, PermissionException {
UserIdentificationImpl ident = frontendState.checkPermission("getUserSpaceURIs",
"You don't have permissions to read the USER Space URIs");
return this.spacesSupport.getUserSpaceURIs(ident.getUsername());
}
/**
* {@inheritDoc}
*/
@Override
public List<String> getGlobalSpaceURIs() throws NotConnectedException, PermissionException {
frontendState.checkPermission("getGlobalSpaceURIs", "You don't have permissions to read the GLOBAL Space URI");
return this.spacesSupport.getGlobalSpaceURIs();
}
/**
* {@inheritDoc}
*/
@Override
@ImmediateService
public JobResult getJobResult(final JobId jobId)
throws NotConnectedException, PermissionException, UnknownJobException {
// checking permissions
IdentifiedJob ij = frontendState.getIdentifiedJob(jobId);
frontendState.checkPermissions("getJobResult", ij, YOU_DO_NOT_HAVE_PERMISSION_TO_GET_THE_RESULT_OF_THIS_JOB);
if (!ij.isFinished()) {
jlogger.info(jobId, "is not finished");
jlogger.info(jobId, "Job state: " + frontendState.getJobState(jobId).getStatus());
return null;
}
jlogger.info(jobId, "trying to get the job result");
JobResult result = dbManager.loadJobResult(jobId);
if (result == null) {
throw new UnknownJobException(jobId);
}
if (!result.getJobInfo().isToBeRemoved() && SCHEDULER_REMOVED_JOB_DELAY > 0) {
// remember that this job is to be removed
dbManager.jobSetToBeRemoved(jobId);
schedulingService.scheduleJobRemove(jobId, System.currentTimeMillis() + SCHEDULER_REMOVED_JOB_DELAY);
jlogger.info(jobId, "will be removed in " + (SCHEDULER_REMOVED_JOB_DELAY / 1000) + "sec");
}
return result;
}
/**
* {@inheritDoc}
*/
@Override
@ImmediateService
public JobResult getJobResult(String jobId) throws NotConnectedException, PermissionException, UnknownJobException {
return this.getJobResult(JobIdImpl.makeJobId(jobId));
}
/**
* {@inheritDoc}
*/
@Override
@ImmediateService
public TaskResult getTaskResult(JobId jobId, String taskName)
throws NotConnectedException, UnknownJobException, UnknownTaskException, PermissionException {
return this.getTaskResultFromIncarnation(jobId, taskName, 0);
}
/**
* {@inheritDoc}
*/
@Override
@ImmediateService
public TaskResult getTaskResult(String jobId, String taskName)
throws NotConnectedException, UnknownJobException, UnknownTaskException, PermissionException {
return this.getTaskResult(JobIdImpl.makeJobId(jobId), taskName);
}
@Override
@ImmediateService
public List<TaskResult> getTaskResultsByTag(JobId jobId, String taskTag)
throws NotConnectedException, UnknownJobException, PermissionException {
frontendState.checkPermission("getTaskResultByTag",
YOU_DO_NOT_HAVE_PERMISSION_TO_GET_THE_TASK_RESULT_OF_THIS_JOB);
List<TaskState> taskStates = getJobState(jobId).getTasksByTag(taskTag);
ArrayList<TaskResult> results = new ArrayList<TaskResult>(taskStates.size());
for (TaskState currentState : taskStates) {
String taskName = currentState.getTaskInfo().getName();
try {
TaskResult currentResult = getTaskResult(jobId, taskName);
results.add(currentResult);
} catch (UnknownTaskException ex) {
// never occurs because tasks are filtered by tag so they cannot
// be unknown.
logger.warn("Unknown task.", ex);
}
}
return results;
}
@Override
@ImmediateService
public List<TaskResult> getTaskResultsByTag(String jobId, String taskTag)
throws NotConnectedException, UnknownJobException, PermissionException {
return this.getTaskResultsByTag(JobIdImpl.makeJobId(jobId), taskTag);
}
/**
* {@inheritDoc}
*/
@Override
@ImmediateService
public TaskResult getTaskResultFromIncarnation(String jobId, String taskName, int inc)
throws NotConnectedException, UnknownJobException, UnknownTaskException, PermissionException {
return this.getTaskResultFromIncarnation(JobIdImpl.makeJobId(jobId), taskName, inc);
}
/**
* {@inheritDoc}
*/
@Override
@ImmediateService
public TaskResult getTaskResultFromIncarnation(JobId jobId, String taskName, int inc)
throws NotConnectedException, UnknownJobException, UnknownTaskException, PermissionException {
// checking permissions
frontendState.checkPermissions("getTaskResultFromIncarnation",
frontendState.getIdentifiedJob(jobId),
YOU_DO_NOT_HAVE_PERMISSION_TO_GET_THE_TASK_RESULT_OF_THIS_JOB);
if (inc < 0) {
throw new IllegalArgumentException("Incarnation must be 0 or greater.");
}
jlogger.debug(jobId, "trying to get the task result, incarnation " + inc);
if (inc < 0) {
throw new IllegalArgumentException("Incarnation must be 0 or greater.");
}
try {
TaskResult result = dbManager.loadTaskResult(jobId, taskName, inc);
// handling special statuses
TaskState ts = frontendState.getTaskState(jobId, taskName);
switch (ts.getStatus()) {
case NOT_STARTED:
if (result == null) {
return new TaskResultImpl(frontendState.getTaskId(jobId, taskName),
new TaskCouldNotStartException(),
new SimpleTaskLogs("",
"The task could not start due to dependency failure"),
0);
} else {
Throwable newException = new TaskCouldNotStartException("The task could not start due to dependency failure",
result.getException());
((TaskResultImpl) result).setException(newException);
}
break;
case NOT_RESTARTED:
if (result == null) {
return new TaskResultImpl(frontendState.getTaskId(jobId, taskName),
new TaskCouldNotRestartException(),
new SimpleTaskLogs("",
"The task could not be restarted after an error during the previous execution"),
0);
} else {
Throwable newException = new TaskCouldNotRestartException("The task could not be restarted after an error during the previous execution",
result.getException());
((TaskResultImpl) result).setException(newException);
}
break;
case SKIPPED:
// result should always be null
return new TaskResultImpl(frontendState.getTaskId(jobId, taskName),
new TaskSkippedException(),
new SimpleTaskLogs("", "The task was skipped in the workflow"),
0);
}
if (result == null) {
// otherwise the task is not finished
jlogger.info(jobId, taskName + " is not finished");
return null;
} else {
return result;
}
} catch (DatabaseManagerException e) {
throw new UnknownTaskException("Unknown task " + taskName + ", job: " + jobId);
}
}
/**
* {@inheritDoc}
*/
@Override
@ImmediateService
public boolean killTask(JobId jobId, String taskName)
throws NotConnectedException, UnknownJobException, UnknownTaskException, PermissionException {
// checking permissions
frontendState.checkPermissions("killTask",
frontendState.getIdentifiedJob(jobId),
YOU_DO_NOT_HAVE_PERMISSION_TO_KILL_THIS_TASK);
return schedulingService.killTask(jobId, taskName);
}
/**
* {@inheritDoc}
*/
@Override
@ImmediateService
public boolean killTask(String jobId, String taskName)
throws NotConnectedException, UnknownJobException, UnknownTaskException, PermissionException {
return killTask(JobIdImpl.makeJobId(jobId), taskName);
}
/**
* {@inheritDoc}
*/
@Override
@ImmediateService
public boolean restartTask(JobId jobId, String taskName, int restartDelay)
throws NotConnectedException, UnknownJobException, UnknownTaskException, PermissionException {
// checking permissions
frontendState.checkPermissions("restartTask",
frontendState.getIdentifiedJob(jobId),
YOU_DO_NOT_HAVE_PERMISSION_TO_RESTART_THIS_TASK);
return schedulingService.restartTask(jobId, taskName, restartDelay);
}
/**
* {@inheritDoc}
*/
@Override
@ImmediateService
public boolean restartTask(String jobId, String taskName, int restartDelay)
throws NotConnectedException, UnknownJobException, UnknownTaskException, PermissionException {
return restartTask(JobIdImpl.makeJobId(jobId), taskName, restartDelay);
}
/**
* {@inheritDoc}
*/
@Override
@ImmediateService
public boolean finishInErrorTask(String jobId, String taskName)
throws NotConnectedException, UnknownJobException, UnknownTaskException, PermissionException {
// checking permissions
final JobId jobIdObject = JobIdImpl.makeJobId(jobId);
frontendState.checkJobOwner("finishTaskInError",
frontendState.getIdentifiedJob(jobIdObject),
"You do not have permission to finish this task!");
frontendState.checkPermissions("finishTaskInError",
frontendState.getIdentifiedJob(jobIdObject),
YOU_DO_NOT_HAVE_PERMISSION_TO_FINISH_THIS_TASK);
return schedulingService.finishInErrorTask(jobIdObject, taskName);
}
/**
* {@inheritDoc}
*/
@Override
@ImmediateService
public boolean restartInErrorTask(String jobId, String taskName)
throws NotConnectedException, UnknownJobException, UnknownTaskException, PermissionException {
// checking permissions
final JobId jobIdObject = JobIdImpl.makeJobId(jobId);
frontendState.checkPermissions("restartTaskOnError",
frontendState.getIdentifiedJob(jobIdObject),
YOU_DO_NOT_HAVE_PERMISSION_TO_RESTART_THIS_TASK);
return schedulingService.restartInErrorTask(jobIdObject, taskName);
}
/**
* {@inheritDoc}
*/
@Override
@ImmediateService
public boolean preemptTask(JobId jobId, String taskName, int restartDelay)
throws NotConnectedException, UnknownJobException, UnknownTaskException, PermissionException {
// checking permissions
frontendState.checkPermissions("preemptTask",
frontendState.getIdentifiedJob(jobId),
YOU_DO_NOT_HAVE_PERMISSION_TO_PREEMPT_THIS_TASK);
return schedulingService.preemptTask(jobId, taskName, restartDelay);
}
/**
* {@inheritDoc}
*/
@Override
@ImmediateService
public boolean preemptTask(String jobId, String taskName, int restartDelay)
throws NotConnectedException, UnknownJobException, UnknownTaskException, PermissionException {
return preemptTask(JobIdImpl.makeJobId(jobId), taskName, restartDelay);
}
/**
* {@inheritDoc}
*/
@Override
public boolean removeJob(JobId jobId) throws NotConnectedException, UnknownJobException, PermissionException {
// checking permissions
frontendState.checkPermissions("removeJob",
frontendState.getIdentifiedJob(jobId),
YOU_DO_NOT_HAVE_PERMISSION_TO_REMOVE_THIS_JOB);
// asking the scheduler for the result
return schedulingService.removeJob(jobId);
}
/**
* {@inheritDoc}
*/
@Override
public void listenJobLogs(JobId jobId, AppenderProvider appenderProvider)
throws NotConnectedException, UnknownJobException, PermissionException {
// checking permissions
frontendState.checkPermissions("listenJobLogs",
frontendState.getIdentifiedJob(jobId),
YOU_DO_NOT_HAVE_PERMISSION_TO_LISTEN_THE_LOG_OF_THIS_JOB);
if (!schedulingService.getListenJobLogsSupport().isEnabled()) {
throw new PermissionException("Listening to job logs is disabled by administrator");
}
schedulingService.listenJobLogs(jobId, appenderProvider);
}
/**
* {@inheritDoc}
*/
@Override
public void listenJobLogs(String jobId, AppenderProvider appenderProvider)
throws NotConnectedException, UnknownJobException, PermissionException {
this.listenJobLogs(JobIdImpl.makeJobId(jobId), appenderProvider);
}
/**
* {@inheritDoc}
*/
@Override
public SchedulerStatus getStatus() throws NotConnectedException, PermissionException {
return frontendState.getStatus();
}
/**
* {@inheritDoc}
*/
@Override
public SchedulerState getState() throws NotConnectedException, PermissionException {
return getState(false);
}
/**
* {@inheritDoc}
*/
@Override
public SchedulerState getState(boolean myJobsOnly) throws NotConnectedException, PermissionException {
return frontendState.getState(myJobsOnly);
}
/**
* {@inheritDoc}
*/
@Override
public void addEventListener(SchedulerEventListener sel, boolean myEventsOnly, SchedulerEvent... events)
throws NotConnectedException, PermissionException {
addEventListener(sel, myEventsOnly, false, events);
}
/**
* {@inheritDoc}
*/
@Override
public SchedulerState addEventListener(SchedulerEventListener sel, boolean myEventsOnly, boolean getCurrentState,
SchedulerEvent... events) throws NotConnectedException, PermissionException {
return frontendState.addEventListener(sel, myEventsOnly, getCurrentState, events);
}
/**
* {@inheritDoc}
*/
@Override
public void removeEventListener() throws NotConnectedException, PermissionException {
frontendState.removeEventListener();
}
/*
* ######################################################################### ##################
*/
/* */
/*
* ##################################### SCHEDULER ORDERS ####################################
*/
/* */
/*
* ######################################################################### ##################
*/
/**
* {@inheritDoc}
*/
@Override
public boolean start() throws NotConnectedException, PermissionException {
frontendState.checkPermission("start", YOU_DO_NOT_HAVE_PERMISSION_TO_START_THE_SCHEDULER);
return schedulingService.start();
}
/**
* {@inheritDoc}
*/
@Override
public boolean stop() throws NotConnectedException, PermissionException {
frontendState.checkPermission("stop", YOU_DO_NOT_HAVE_PERMISSION_TO_STOP_THE_SCHEDULER);
return schedulingService.stop();
}
/**
* {@inheritDoc}
*/
@Override
public boolean pause() throws NotConnectedException, PermissionException {
frontendState.checkPermission("pause", YOU_DO_NOT_HAVE_PERMISSION_TO_PAUSE_THE_SCHEDULER);
return schedulingService.pause();
}
/**
* {@inheritDoc}
*/
@Override
public boolean freeze() throws NotConnectedException, PermissionException {
frontendState.checkPermission("freeze", YOU_DO_NOT_HAVE_PERMISSION_TO_FREEZE_THE_SCHEDULER);
return schedulingService.freeze();
}
/**
* {@inheritDoc}
*/
@Override
public boolean resume() throws NotConnectedException, PermissionException {
frontendState.checkPermission("resume", YOU_DO_NOT_HAVE_PERMISSION_TO_RESUME_THE_SCHEDULER);
return schedulingService.resume();
}
/**
* {@inheritDoc}
*/
@Override
public boolean shutdown() throws NotConnectedException, PermissionException {
frontendState.checkPermission("shutdown", YOU_DO_NOT_HAVE_PERMISSION_TO_SHUTDOWN_THE_SCHEDULER);
return schedulingService.shutdown();
}
/**
* {@inheritDoc}
*/
@Override
public boolean kill() throws NotConnectedException, PermissionException {
frontendState.checkPermission("kill", YOU_DO_NOT_HAVE_PERMISSION_TO_KILL_THE_SCHEDULER);
return schedulingService.kill();
}
/**
* {@inheritDoc}
*/
@Override
public void disconnect() throws NotConnectedException, PermissionException {
frontendState.disconnect();
}
/**
* {@inheritDoc}
*/
@Override
@ImmediateService
public boolean isConnected() {
return frontendState.isConnected();
}
/**
* {@inheritDoc}
*/
@Override
@ImmediateService
public void renewSession() throws NotConnectedException {
frontendState.renewSession();
}
/**
* {@inheritDoc}
*/
@Override
public boolean pauseJob(JobId jobId) throws NotConnectedException, UnknownJobException, PermissionException {
frontendState.checkPermissions("pauseJob",
frontendState.getIdentifiedJob(jobId),
YOU_DO_NOT_HAVE_PERMISSION_TO_PAUSE_THIS_JOB);
return schedulingService.pauseJob(jobId);
}
/**
* {@inheritDoc}
*/
@Override
public boolean resumeJob(JobId jobId) throws NotConnectedException, UnknownJobException, PermissionException {
frontendState.checkPermissions("resumeJob",
frontendState.getIdentifiedJob(jobId),
YOU_DO_NOT_HAVE_PERMISSION_TO_RESUME_THIS_JOB);
return schedulingService.resumeJob(jobId);
}
/**
* {@inheritDoc}
*/
@Override
public boolean killJob(JobId jobId) throws NotConnectedException, UnknownJobException, PermissionException {
frontendState.checkPermissions("killJob",
frontendState.getIdentifiedJob(jobId),
YOU_DO_NOT_HAVE_PERMISSION_TO_KILL_THIS_JOB);
return schedulingService.killJob(jobId);
}
/**
* {@inheritDoc}
*/
@Override
public void changeJobPriority(JobId jobId, JobPriority priority)
throws NotConnectedException, UnknownJobException, PermissionException, JobAlreadyFinishedException {
frontendState.checkChangeJobPriority(jobId, priority);
schedulingService.changeJobPriority(jobId, priority);
}
/**
* {@inheritDoc}
*/
@Override
@ImmediateService
public JobState getJobState(JobId jobId) throws NotConnectedException, UnknownJobException, PermissionException {
return frontendState.getJobState(jobId);
}
/**
* {@inheritDoc}
*/
@Override
public boolean killJob(String jobId) throws NotConnectedException, UnknownJobException, PermissionException {
return this.killJob(JobIdImpl.makeJobId(jobId));
}
/**
* {@inheritDoc}
*/
@Override
public boolean pauseJob(String jobId) throws NotConnectedException, UnknownJobException, PermissionException {
return this.pauseJob(JobIdImpl.makeJobId(jobId));
}
/**
* {@inheritDoc}
*/
@Override
public boolean removeJob(String jobId) throws NotConnectedException, UnknownJobException, PermissionException {
return this.removeJob(JobIdImpl.makeJobId(jobId));
}
@Override
public boolean restartAllInErrorTasks(String jobId)
throws NotConnectedException, UnknownJobException, PermissionException {
final JobId jobIdObject = JobIdImpl.makeJobId(jobId);
frontendState.checkPermissions("restartAllInErrorTasks",
frontendState.getIdentifiedJob(jobIdObject),
YOU_DO_NOT_HAVE_PERMISSION_TO_RESTART_IN_ERROR_TASKS_IN_THIS_JOB);
return schedulingService.restartAllInErrorTasks(jobIdObject);
}
/**
* {@inheritDoc}
*/
@Override
public boolean resumeJob(String jobId) throws NotConnectedException, UnknownJobException, PermissionException {
return this.resumeJob(JobIdImpl.makeJobId(jobId));
}
/**
* {@inheritDoc}
*/
@Override
public void changeJobPriority(String jobId, JobPriority priority)
throws NotConnectedException, UnknownJobException, PermissionException, JobAlreadyFinishedException {
this.changeJobPriority(JobIdImpl.makeJobId(jobId), priority);
}
/**
* {@inheritDoc}
*/
@Override
public JobState getJobState(String jobId) throws NotConnectedException, UnknownJobException, PermissionException {
return this.getJobState(JobIdImpl.makeJobId(jobId));
}
/**
* {@inheritDoc}
*/
@Override
public boolean changePolicy(String newPolicyClassname) throws NotConnectedException, PermissionException {
frontendState.checkChangePolicy();
policyFullName = newPolicyClassname;
return schedulingService.changePolicy(newPolicyClassname);
}
/**
* {@inheritDoc}
*/
@Override
public boolean linkResourceManager(String rmURL) throws NotConnectedException, PermissionException {
frontendState.checkLinkResourceManager();
return schedulingService.linkResourceManager(rmURL);
}
/**
* {@inheritDoc}
*/
@Override
public boolean reloadPolicyConfiguration() throws NotConnectedException, PermissionException {
frontendState.checkPermission("reloadPolicyConfiguration",
YOU_DO_NOT_HAVE_PERMISSION_TO_RELOAD_POLICY_CONFIGURATION);
return schedulingService.reloadPolicyConfiguration();
}
/**
* Terminate the schedulerConnexion active object and then this object.
*
* @return always true;
*/
public boolean terminate() {
logger.debug("Closing Scheduler database");
dbManager.close();
if (authentication != null) {
authentication.terminate();
}
ClientRequestHandler.terminate();
PAActiveObject.terminateActiveObject(false);
logger.info("Scheduler frontend is now shutdown !");
return true;
}
/**
* Method controls the execution of every request. Tries to keep this active
* object alive in case of any exception.
*/
@Override
public void runActivity(Body body) {
Service service = new Service(body);
while (body.isActive()) {
try {
Request request = service.blockingRemoveOldest();
if (request != null) {
try {
service.serve(request);
} catch (Throwable e) {
logger.error("Cannot serve request: " + request, e);
}
}
} catch (InterruptedException e) {
logger.warn("SchedulerFrontend runActivity interrupted", e);
}
}
}
@Override
@ImmediateService
public String getJobServerLogs(String jobId)
throws UnknownJobException, NotConnectedException, PermissionException {
JobId id = JobIdImpl.makeJobId(jobId);
frontendState.checkPermissions("getJobServerLogs",
frontendState.getIdentifiedJob(id),
YOU_DO_NOT_HAVE_PERMISSIONS_TO_GET_THE_LOGS_OF_THIS_JOB);
return ServerJobAndTaskLogs.getJobLog(JobIdImpl.makeJobId(jobId), frontendState.getJobTasks(id));
}
@Override
@ImmediateService
public String getTaskServerLogs(String jobId, String taskName)
throws UnknownJobException, UnknownTaskException, NotConnectedException, PermissionException {
JobId id = JobIdImpl.makeJobId(jobId);
frontendState.checkPermissions("getTaskServerLogs",
frontendState.getIdentifiedJob(id),
YOU_DO_NOT_HAVE_PERMISSION_TO_GET_THE_TASK_LOGS_OF_THIS_JOB);
for (TaskId taskId : frontendState.getJobTasks(id)) {
if (taskId.getReadableName().equals(taskName)) {
return ServerJobAndTaskLogs.getTaskLog(taskId);
}
}
throw new UnknownTaskException("Unknown task " + taskName + " in job " + jobId);
}
@Override
@ImmediateService
public String getTaskServerLogsByTag(String jobId, String taskTag)
throws UnknownJobException, NotConnectedException, PermissionException {
JobId id = JobIdImpl.makeJobId(jobId);
frontendState.checkPermissions("getTaskServerLogsByTag",
frontendState.getIdentifiedJob(id),
YOU_DO_NOT_HAVE_PERMISSION_TO_GET_THE_TASK_LOGS_OF_THIS_JOB);
List<TaskState> lTaskState = frontendState.getJobState(id).getTasksByTag(taskTag);
Set<TaskId> tasksIds = new HashSet<>(lTaskState.size());
for (TaskState taskState : lTaskState) {
tasksIds.add(taskState.getId());
}
return ServerJobAndTaskLogs.getJobLog(id, tasksIds);
}
/**
* {@inheritDoc}
*/
@Override
@ImmediateService
public Page<JobInfo> getJobs(int offset, int limit, JobFilterCriteria filterCriteria,
List<SortParameter<JobSortParameter>> sortParameters) throws NotConnectedException, PermissionException {
UserIdentificationImpl ident = frontendState.checkPermission("getJobs",
"You don't have permissions to load jobs");
boolean myJobsOnly = filterCriteria.isMyJobsOnly();
String user;
if (myJobsOnly) {
user = ident.getUsername();
} else {
user = null;
}
return dbManager.getJobs(offset,
limit,
user,
filterCriteria.isPending(),
filterCriteria.isRunning(),
filterCriteria.isFinished(),
sortParameters);
}
/**
* {@inheritDoc}
*/
@Override
@ImmediateService
public List<SchedulerUserInfo> getUsers() throws NotConnectedException, PermissionException {
frontendState.checkPermission("getUsers", "You don't have permissions to get users");
return frontendState.getUsers();
}
/**
* {@inheritDoc}
*/
@Override
@ImmediateService
public List<SchedulerUserInfo> getUsersWithJobs() throws NotConnectedException, PermissionException {
frontendState.checkPermission("getUsersWithJobs", "You don't have permissions to get users with jobs");
return dbManager.loadUsersWithJobs();
}
/**
* {@inheritDoc}
*/
@Override
@ImmediateService
public List<JobUsage> getMyAccountUsage(Date startDate, Date endDate)
throws NotConnectedException, PermissionException {
UserIdentificationImpl ident = frontendState.checkPermission("getMyAccountUsage",
"You don't have permissions to get usage data for your account");
return dbManager.getUsage(ident.getUsername(), startDate, endDate);
}
/**
* {@inheritDoc}
*/
@Override
@ImmediateService
public List<JobUsage> getAccountUsage(String user, Date startDate, Date endDate)
throws NotConnectedException, PermissionException {
try {
frontendState.checkPermission("getAccountUsage", "You don't have permissions to get usage data of " + user);
return dbManager.getUsage(user, startDate, endDate);
} catch (PermissionException e) {
// try to fallback on my account usage if user is the caller
UserIdentificationImpl ident = frontendState.checkPermission("getMyAccountUsage",
"You don't have permissions to get usage data of " +
user);
if (user != null && user.equals(ident.getUsername())) {
return dbManager.getUsage(ident.getUsername(), startDate, endDate);
}
throw e;
}
}
@Override
public void putThirdPartyCredential(String key, String value)
throws NotConnectedException, PermissionException, KeyException {
UserIdentificationImpl ident = frontendState.checkPermission("putThirdPartyCredential",
YOU_DO_NOT_HAVE_PERMISSION_TO_PUT_THIRD_PARTY_CREDENTIALS_IN_THE_SCHEDULER);
HybridEncryptionUtil.HybridEncryptedData encryptedData = HybridEncryptionUtil.encryptString(value,
corePublicKey);
dbManager.putThirdPartyCredential(ident.getUsername(), key, encryptedData);
}
@Override
public Set<String> thirdPartyCredentialsKeySet() throws NotConnectedException, PermissionException {
UserIdentificationImpl ident = frontendState.checkPermission("thirdPartyCredentialsKeySet",
YOU_DO_NOT_HAVE_PERMISSION_TO_LIST_THIRD_PARTY_CREDENTIALS_IN_THE_SCHEDULER);
return dbManager.thirdPartyCredentialsKeySet(ident.getUsername());
}
@Override
public void removeThirdPartyCredential(String key) throws NotConnectedException, PermissionException {
UserIdentificationImpl ident = frontendState.checkPermission("removeThirdPartyCredential",
YOU_DO_NOT_HAVE_PERMISSION_TO_REMOVE_THIRD_PARTY_CREDENTIALS_FROM_THE_SCHEDULER);
dbManager.removeThirdPartyCredential(ident.getUsername(), key);
}
@Override
public Page<TaskId> getTaskIds(String taskTag, long from, long to, boolean mytasks, boolean running,
boolean pending, boolean finished, int offset, int limit)
throws NotConnectedException, PermissionException {
RestPageParameters params = new RestPageParameters(frontendState,
"getTaskIds",
from,
to,
mytasks,
running,
pending,
finished,
offset,
limit,
taskTag,
SortSpecifierContainer.EMPTY_CONTAINER);
Page<TaskInfo> pTaskInfo;
pTaskInfo = dbManager.getTasks(params.getFrom(),
params.getTo(),
params.getTag(),
params.getOffset(),
params.getLimit(),
params.getUserName(),
params.isPending(),
params.isRunning(),
params.isFinished());
List<TaskId> lTaskId = new ArrayList<TaskId>(pTaskInfo.getList().size());
for (TaskInfo taskInfo : pTaskInfo.getList()) {
lTaskId.add(taskInfo.getTaskId());
}
return new Page<TaskId>(lTaskId, pTaskInfo.getSize());
}
@Override
public Page<TaskState> getTaskStates(String taskTag, long from, long to, boolean mytasks, boolean running,
boolean pending, boolean finished, int offset, int limit, SortSpecifierContainer sortParams)
throws NotConnectedException, PermissionException {
RestPageParameters params = new RestPageParameters(frontendState,
"getTaskStates",
from,
to,
mytasks,
running,
pending,
finished,
offset,
limit,
taskTag,
sortParams);
Page<TaskState> pTasks;
pTasks = dbManager.getTaskStates(params.getFrom(),
params.getTo(),
params.getTag(),
params.getOffset(),
params.getLimit(),
params.getUserName(),
params.isPending(),
params.isRunning(),
params.isFinished(),
params.getSortParams());
return pTasks;
}
@Override
public JobInfo getJobInfo(String jobId) throws UnknownJobException, NotConnectedException, PermissionException {
return getJobState(JobIdImpl.makeJobId(jobId)).getJobInfo();
}
/**
* {@inheritDoc}
*/
@Override
public boolean changeStartAt(JobId jobId, String startAt)
throws NotConnectedException, UnknownJobException, PermissionException {
return schedulingService.changeStartAt(jobId, startAt);
}
@Override
public JobId copyJobAndResubmitWithGeneralInfo(JobId jobId, Map<String, String> generalInfo)
throws NotConnectedException, UnknownJobException, PermissionException, SubmissionClosedException,
JobCreationException {
TaskFlowJob job = (TaskFlowJob) dbManager.loadInitalJobContent(jobId);
for (Entry<String, String> entry : generalInfo.entrySet()) {
job.addGenericInformation(entry.getKey(), entry.getValue());
}
return submit(job);
}
@Override
public Map<Object, Object> getPortalConfiguration() {
return schedulerPortalConfiguration.getProperties();
}
@Override
public String getCurrentUser() throws NotConnectedException {
return frontendState.getCurrentUser();
}
}