diff --git a/build.gradle b/build.gradle index 33379b228..9e61e45e2 100644 --- a/build.gradle +++ b/build.gradle @@ -29,7 +29,7 @@ buildscript { } group 'org.nrg' -version '2.0.0.15-radiologics' +version '2.0.0.16-radiologics' apply plugin: 'java' apply plugin: 'idea' @@ -42,8 +42,8 @@ apply plugin: "com.github.zhurlik.swagger" sourceCompatibility = 1.7 targetCompatibility = 1.7 -def vXnat = '1.7.5-SNAPSHOT' -def vXnatDev = '1.7.5-SNAPSHOT' +def vXnat = '1.7.5' +def vXnatDev = '1.7.5' def vMockito = '1.10.19' def vJavassist = '3.21.0-GA' def vAwaitility = '2.0.0' diff --git a/src/main/java/org/nrg/containers/events/DockerStatusUpdater.java b/src/main/java/org/nrg/containers/events/DockerStatusUpdater.java index 7b5178b71..f078abdd5 100644 --- a/src/main/java/org/nrg/containers/events/DockerStatusUpdater.java +++ b/src/main/java/org/nrg/containers/events/DockerStatusUpdater.java @@ -13,9 +13,13 @@ import org.nrg.containers.services.DockerServerService; import org.nrg.containers.utils.ContainerUtils; import org.nrg.framework.exceptions.NotFoundException; +import org.nrg.framework.task.XnatTask; +import org.nrg.framework.task.services.XnatTaskService; import org.nrg.xdat.turbine.utils.AdminUtils; import org.nrg.xft.event.persist.PersistentWorkflowUtils; import org.nrg.xft.schema.XFTManager; +import org.nrg.xnat.services.XnatAppInfo; +import org.nrg.xnat.task.AbstractXnatTask; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -26,12 +30,13 @@ @Slf4j @Component -public class DockerStatusUpdater implements Runnable { +public class DockerStatusUpdater implements Runnable { private ContainerControlApi controlApi; private DockerServerService dockerServerService; private ContainerService containerService; - + final XnatAppInfo xnatAppInfo; + private boolean haveLoggedDockerConnectFailure = false; private boolean haveLoggedNoServerInDb = false; private boolean haveLoggedXftInitFailure = false; @@ -40,88 +45,95 @@ public class DockerStatusUpdater implements Runnable { @SuppressWarnings("SpringJavaAutowiringInspection") public DockerStatusUpdater(final ContainerControlApi controlApi, final DockerServerService dockerServerService, - final ContainerService containerService) { + final ContainerService containerService, + final XnatAppInfo xnatAppInfo) { this.controlApi = controlApi; this.dockerServerService = dockerServerService; this.containerService = containerService; + this.xnatAppInfo=xnatAppInfo; } @Override public void run() { - log.trace("-----------------------------------------------------------------------------"); - log.trace("Attempting to update status with docker."); - - final String skipMessage = "Skipping attempt to update status."; - - if (!XFTManager.isInitialized()) { - if (!haveLoggedXftInitFailure) { - log.info("XFT is not initialized. " + skipMessage); - haveLoggedXftInitFailure = true; - } - return; - } - - // Since XFT is up, we should be able to connect to the database and read the docker server - DockerServer dockerServer = null; - try { - dockerServer = dockerServerService.getServer(); - } catch (NotFoundException e) { - log.error("Docker server not found"); - } - if (dockerServer == null) { - log.trace("Docker server is null"); - if (!haveLoggedNoServerInDb) { - log.info("No docker server has been defined (or enabled) in the database. " + skipMessage); - haveLoggedNoServerInDb = true; - haveLoggedXftInitFailure = false; - } - log.trace("haveLoggedNoServerInDb "+ haveLoggedNoServerInDb + " about to return "); - return; - } - - if (!controlApi.canConnect()) { - log.info("Cannot connect to docker server " + dockerServer.name() + ". " + skipMessage); - if (!haveLoggedDockerConnectFailure) { - log.info("Cannot ping docker server " + dockerServer.name() + ". " + skipMessage); - haveLoggedDockerConnectFailure = true; - haveLoggedXftInitFailure = false; - haveLoggedNoServerInDb = false; - } - log.trace("haveLoggedDockerConnectFailure: " + haveLoggedDockerConnectFailure + " about to return"); - return; - } - - // Now we should be able to check the status - final UpdateReport updateReport = dockerServer.swarmMode() ? updateServices(dockerServer) : updateContainers(dockerServer); - if (updateReport.successful == null) { - // This means some, but not all, of the services didn't update properly. Which ones? - for (final UpdateReportEntry entry : updateReport.updateReports) { - if (!entry.successful) { - log.error("Could not update status for {}. Message: {}", entry.id, entry.message); - } else { - log.debug("Updated successfully for {}.", entry.id); - } - } - - // Reset failure flags - haveLoggedDockerConnectFailure = false; - haveLoggedXftInitFailure = false; - haveLoggedNoServerInDb = false; - } else if (updateReport.successful) { - if (updateReport.updateReports.size() > 0) { - log.debug("Updated status successfully."); - } - // Reset failure flags - haveLoggedDockerConnectFailure = false; - haveLoggedXftInitFailure = false; - haveLoggedNoServerInDb = false; - } else { - log.info("Did not update status successfully."); - } - log.trace("-----------------------------------------------------------------------------"); - log.trace("DOCKERSTATUSUPDATER: RUN COMPLETE"); - log.trace("-----------------------------------------------------------------------------"); - + if(!xnatAppInfo.isPrimaryNode()) { + log.trace("Not the Primary node: skipping update status with docker."); return; + } + log.trace("-----------------------------------------------------------------------------"); + + log.trace("Primary node: Attempting to update status with docker."); + + final String skipMessage = "Skipping attempt to update status."; + + if (!XFTManager.isInitialized()) { + if (!haveLoggedXftInitFailure) { + log.info("XFT is not initialized. " + skipMessage); + haveLoggedXftInitFailure = true; + } + return; + } + + // Since XFT is up, we should be able to connect to the database and read the docker server + DockerServer dockerServer = null; + try { + dockerServer = dockerServerService.getServer(); + } catch (NotFoundException e) { + log.error("Docker server not found"); + } + if (dockerServer == null) { + log.trace("Docker server is null"); + if (!haveLoggedNoServerInDb) { + log.info("No docker server has been defined (or enabled) in the database. " + skipMessage); + haveLoggedNoServerInDb = true; + haveLoggedXftInitFailure = false; + } + log.trace("haveLoggedNoServerInDb "+ haveLoggedNoServerInDb + " about to return "); + return; + } + + if (!controlApi.canConnect()) { + log.info("Cannot connect to docker server " + dockerServer.name() + ". " + skipMessage); + if (!haveLoggedDockerConnectFailure) { + log.info("Cannot ping docker server " + dockerServer.name() + ". " + skipMessage); + haveLoggedDockerConnectFailure = true; + haveLoggedXftInitFailure = false; + haveLoggedNoServerInDb = false; + } + log.trace("haveLoggedDockerConnectFailure: " + haveLoggedDockerConnectFailure + " about to return"); + return; + } + + + // Now we should be able to check the status + final UpdateReport updateReport = dockerServer.swarmMode() ? updateServices(dockerServer) : updateContainers(dockerServer); + if (updateReport.successful == null) { + // This means some, but not all, of the services didn't update properly. Which ones? + for (final UpdateReportEntry entry : updateReport.updateReports) { + if (!entry.successful) { + log.error("Could not update status for {}. Message: {}", entry.id, entry.message); + } else { + log.debug("Updated successfully for {}.", entry.id); + } + } + + // Reset failure flags + haveLoggedDockerConnectFailure = false; + haveLoggedXftInitFailure = false; + haveLoggedNoServerInDb = false; + } else if (updateReport.successful) { + if (updateReport.updateReports.size() > 0) { + log.debug("Updated status successfully."); + } + // Reset failure flags + haveLoggedDockerConnectFailure = false; + haveLoggedXftInitFailure = false; + haveLoggedNoServerInDb = false; + } else { + log.info("Did not update status successfully."); + } + log.trace("-----------------------------------------------------------------------------"); + log.trace("DOCKERSTATUSUPDATER: RUN COMPLETE"); + log.trace("-----------------------------------------------------------------------------"); + } @Nonnull @@ -243,4 +255,6 @@ public static UpdateReportEntry failure(final String id, return updateReportEntry; } } + + } diff --git a/src/main/java/org/nrg/containers/initialization/tasks/ResetContainersInOrphanedFinalizingState.java b/src/main/java/org/nrg/containers/initialization/tasks/ResetContainersInOrphanedFinalizingState.java index fad423faf..8a31823ef 100644 --- a/src/main/java/org/nrg/containers/initialization/tasks/ResetContainersInOrphanedFinalizingState.java +++ b/src/main/java/org/nrg/containers/initialization/tasks/ResetContainersInOrphanedFinalizingState.java @@ -3,6 +3,7 @@ import org.nrg.containers.services.ContainerService; import org.nrg.xnat.initialization.tasks.AbstractInitializingTask; import org.nrg.xnat.initialization.tasks.InitializingTaskException; +import org.nrg.xnat.services.XnatAppInfo; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -19,8 +20,9 @@ public class ResetContainersInOrphanedFinalizingState extends AbstractInitializi @Autowired - public ResetContainersInOrphanedFinalizingState(final ContainerService containerService) { + public ResetContainersInOrphanedFinalizingState(final ContainerService containerService, final XnatAppInfo appInfo) { this.containerService = containerService; + this._appInfo=appInfo; } @Override @@ -30,12 +32,22 @@ public String getTaskName() { @Override protected void callImpl() throws InitializingTaskException { - log.debug("Checking if any containers exist in orphaned Finalizing state in database. If they do, resetting them to Waiting/Failed"); - //MR: 10/30/2018 - If this is the first time the DockerStatusUpdater is running - //Look for all containers which are in Finalizing state - //These are probably in "hung" state - //Change the state of these to Waiting - containerService.resetFinalizingStatusToWaitingOrFailed(); + if(!_appInfo.isPrimaryNode()) { + log.debug("This is not the primary node. Skippping Reset Containers In Orphaned Finalizing State"); + return; + } + log.debug("This is the primary node. Checking if any containers exist in orphaned Finalizing state in database. If they do, resetting them to Waiting/Failed"); + //MR: 10/30/2018 - If this is the first time the DockerStatusUpdater is running + //Look for all containers which are in Finalizing state + //These are probably in "hung" state + //Change the state of these to Waiting + containerService.resetFinalizingStatusToWaitingOrFailed(); log.debug("Reset Complete Orphaned Finalizing states to Waiting/Failed State"); + } + + private final XnatAppInfo _appInfo; + + + } diff --git a/src/main/java/org/nrg/containers/model/container/auto/Container.java b/src/main/java/org/nrg/containers/model/container/auto/Container.java index 2e7df400d..34b69afc7 100644 --- a/src/main/java/org/nrg/containers/model/container/auto/Container.java +++ b/src/main/java/org/nrg/containers/model/container/auto/Container.java @@ -1,15 +1,13 @@ package org.nrg.containers.model.container.auto; -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonGetter; -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.google.auto.value.AutoValue; -import com.google.common.base.Function; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; +import java.util.Collection; +import java.util.Collections; +import java.util.Date; +import java.util.List; +import java.util.Map; + +import javax.annotation.Nullable; + import org.nrg.containers.events.model.ContainerEvent; import org.nrg.containers.events.model.DockerContainerEvent; import org.nrg.containers.model.command.auto.ResolvedCommand; @@ -21,13 +19,22 @@ import org.nrg.containers.model.container.entity.ContainerEntityMount; import org.nrg.containers.model.container.entity.ContainerEntityOutput; import org.nrg.containers.model.container.entity.ContainerMountFilesEntity; +import org.nrg.containers.utils.JsonDateSerializer; +import org.nrg.containers.utils.JsonStringToDateSerializer; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonGetter; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.google.auto.value.AutoValue; +import com.google.common.base.Function; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; -import javax.annotation.Nullable; -import java.util.Collection; -import java.util.Collections; -import java.util.Date; -import java.util.List; -import java.util.Map; @AutoValue public abstract class Container { @@ -36,6 +43,7 @@ public abstract class Container { @JsonProperty("id") public abstract long databaseId(); @JsonProperty("command-id") public abstract long commandId(); @Nullable @JsonProperty("status") public abstract String status(); + @JsonSerialize(using=JsonDateSerializer.class) @Nullable @JsonProperty("status-time") public abstract Date statusTime(); @JsonProperty("wrapper-id") public abstract long wrapperId(); @Nullable @JsonProperty("container-id") public abstract String containerId(); @@ -735,7 +743,9 @@ public static abstract class ContainerHistory { @JsonProperty("status") public abstract String status(); @JsonProperty("entity-type") public abstract String entityType(); @Nullable @JsonProperty("entity-id") public abstract String entityId(); + @JsonSerialize(using=JsonDateSerializer.class) @JsonProperty("time-recorded") public abstract Date timeRecorded(); + @JsonSerialize(using=JsonStringToDateSerializer.class) @Nullable @JsonProperty("external-timestamp") public abstract String externalTimestamp(); @Nullable @JsonProperty("message") public abstract String message(); @Nullable @JsonProperty("exitCode") public abstract String exitCode(); @@ -792,7 +802,7 @@ public static ContainerHistory fromSystem(final String status, .entityType("system") .entityId(null) .timeRecorded(new Date()) - .externalTimestamp(null) + .externalTimestamp(Long.toString(System.nanoTime())) .build(); } @@ -802,7 +812,7 @@ public static ContainerHistory fromUserAction(final String status, final String .entityType("user") .entityId(username) .timeRecorded(new Date()) - .externalTimestamp(null) + .externalTimestamp(Long.toString(System.nanoTime())) .message(null) .build(); } diff --git a/src/main/java/org/nrg/containers/model/container/entity/ContainerEntity.java b/src/main/java/org/nrg/containers/model/container/entity/ContainerEntity.java index 66a3339b9..e4fd4ab57 100644 --- a/src/main/java/org/nrg/containers/model/container/entity/ContainerEntity.java +++ b/src/main/java/org/nrg/containers/model/container/entity/ContainerEntity.java @@ -5,11 +5,12 @@ import com.google.common.collect.ImmutableMap; import com.google.common.collect.Lists; import com.google.common.collect.Maps; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang.StringUtils; import org.hibernate.envers.Audited; import org.nrg.containers.model.container.ContainerInputType; import org.nrg.containers.model.container.auto.Container; import org.nrg.framework.orm.hibernate.AbstractHibernateEntity; - import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.ElementCollection; @@ -17,6 +18,7 @@ import javax.persistence.ManyToOne; import javax.persistence.OneToMany; import javax.persistence.Transient; +import java.lang.reflect.Array; import java.util.Arrays; import java.util.Collections; import java.util.Date; @@ -29,6 +31,7 @@ @Entity @Audited +@Slf4j public class ContainerEntity extends AbstractHibernateEntity { public static Map STANDARD_STATUS_MAP = ImmutableMap.builder() .put("complete", "Complete") @@ -515,16 +518,42 @@ public void addToHistory(final ContainerEntityHistory historyItem) { } @Transient + /* + * Does this item have a different status that the most recent event. + * + */ public boolean isItemInHistory(final ContainerEntityHistory historyItem) { if (this.history == null){ return false; } + historyItem.setContainerEntity(this); - - return this.history.contains(historyItem); - - } - + + boolean match=false; + Collections.sort(history); + for (ContainerEntityHistory hist : history) { + log.debug("isItemInHistory items {} {} {}",hist.getContainerEntity().getId(),hist.getStatus(),hist.getTimeRecorded()); + } + if(history.size()>0){ + ContainerEntityHistory latest=history.get(0); + match= StringUtils.equals(latest.getStatus(),historyItem.getStatus()); + if(log.isDebugEnabled()){ + log.debug("isItemInHistory skip {} {} {} {} {} {} {}", + match, + historyItem.getContainerEntity().getId(), + latest.getContainerEntity().getId(), + historyItem.getStatus(), + latest.getStatus(), + historyItem.getTimeRecorded(), + latest.getTimeRecorded()); + } + } + return match; + } + + + + @ElementCollection public List getLogPaths() { return logPaths; diff --git a/src/main/java/org/nrg/containers/model/container/entity/ContainerEntityHistory.java b/src/main/java/org/nrg/containers/model/container/entity/ContainerEntityHistory.java index cf8e87b20..c0bcb5521 100644 --- a/src/main/java/org/nrg/containers/model/container/entity/ContainerEntityHistory.java +++ b/src/main/java/org/nrg/containers/model/container/entity/ContainerEntityHistory.java @@ -21,7 +21,7 @@ @Slf4j @Entity @Audited -public class ContainerEntityHistory { +public class ContainerEntityHistory implements Comparable{ private long id; @JsonIgnore private ContainerEntity containerEntity; private String status; @@ -192,4 +192,9 @@ public String toString() { .add("exitCode", exitCode) .toString(); } + + @Override + public int compareTo(ContainerEntityHistory o) { + return o.timeRecorded.compareTo(this.timeRecorded); + } } diff --git a/src/main/java/org/nrg/containers/services/impl/CommandServiceImpl.java b/src/main/java/org/nrg/containers/services/impl/CommandServiceImpl.java index 048acbd7a..396bb187c 100644 --- a/src/main/java/org/nrg/containers/services/impl/CommandServiceImpl.java +++ b/src/main/java/org/nrg/containers/services/impl/CommandServiceImpl.java @@ -668,4 +668,4 @@ public int hashCode() { return Objects.hash(wrapperXsiType, userRequestedXsiType); } } -} +} \ No newline at end of file diff --git a/src/main/java/org/nrg/containers/services/impl/ContainerServiceImpl.java b/src/main/java/org/nrg/containers/services/impl/ContainerServiceImpl.java index f45e78ef1..8f55a8388 100644 --- a/src/main/java/org/nrg/containers/services/impl/ContainerServiceImpl.java +++ b/src/main/java/org/nrg/containers/services/impl/ContainerServiceImpl.java @@ -59,8 +59,10 @@ import org.nrg.xdat.security.user.exceptions.UserNotFoundException; import org.nrg.xdat.services.AliasTokenService; import org.nrg.xft.XFTItem; +import org.nrg.xft.event.EventDetails; import org.nrg.xft.event.EventUtils; import org.nrg.xft.event.persist.PersistentWorkflowI; +import org.nrg.xft.event.persist.PersistentWorkflowUtils; import org.nrg.xft.security.UserI; import org.nrg.xnat.utils.WorkflowUtils; import org.springframework.beans.factory.annotation.Autowired; @@ -314,37 +316,43 @@ private Container launchResolvedDockerCommand(final ResolvedCommand resolvedComm throws NoDockerServerException, DockerServerException, ContainerException { log.info("Preparing to launch resolved command."); final ResolvedCommand preparedToLaunch = prepareToLaunch(resolvedCommand, userI); + final PersistentWorkflowI workflow = makeWorkflowIfAppropriate(resolvedCommand, userI); log.info("Creating container from resolved command."); - final Container createdContainerOrService = containerControlApi.createContainerOrSwarmService(preparedToLaunch, userI); - - log.info("Recording container launch."); - final String workflowId = makeWorkflowIfAppropriate(resolvedCommand, createdContainerOrService, userI); - final Container savedContainerOrService = toPojo(containerEntityService.save(fromPojo( - createdContainerOrService.toBuilder() - .workflowId(workflowId) - .parent(parent) - .build() - ), userI)); - - if (resolvedCommand.wrapupCommands().size() > 0) { - log.info("Creating wrapup container objects in database (not creating docker containers)."); - for (final ResolvedCommand resolvedWrapupCommand : resolvedCommand.wrapupCommands()) { - final Container wrapupContainer = createWrapupContainerInDbFromResolvedCommand(resolvedWrapupCommand, savedContainerOrService, userI); - log.debug("Created wrapup container {} for parent container {}.", wrapupContainer.databaseId(), savedContainerOrService.databaseId()); + try { + final Container createdContainerOrService = containerControlApi.createContainerOrSwarmService(preparedToLaunch, userI); + //Update workflow with container information + addContainerInformationToWorkflow(workflow,createdContainerOrService); + log.info("Recording container launch."); + final Container savedContainerOrService = toPojo(containerEntityService.save(fromPojo( + createdContainerOrService.toBuilder() + .workflowId(workflow.getWorkflowId().toString()) + .parent(parent) + .build() + ), userI)); + + if (resolvedCommand.wrapupCommands().size() > 0) { + log.info("Creating wrapup container objects in database (not creating docker containers)."); + for (final ResolvedCommand resolvedWrapupCommand : resolvedCommand.wrapupCommands()) { + final Container wrapupContainer = createWrapupContainerInDbFromResolvedCommand(resolvedWrapupCommand, savedContainerOrService, userI); + log.debug("Created wrapup container {} for parent container {}.", wrapupContainer.databaseId(), savedContainerOrService.databaseId()); + } } - } - if (resolvedCommand.setupCommands().size() > 0) { - log.info("Launching setup containers."); - for (final ResolvedCommand resolvedSetupCommand : resolvedCommand.setupCommands()) { - launchResolvedCommand(resolvedSetupCommand, userI, savedContainerOrService); + if (resolvedCommand.setupCommands().size() > 0) { + log.info("Launching setup containers."); + for (final ResolvedCommand resolvedSetupCommand : resolvedCommand.setupCommands()) { + launchResolvedCommand(resolvedSetupCommand, userI, savedContainerOrService); + } + } else { + startContainer(userI, savedContainerOrService); } - } else { - startContainer(userI, savedContainerOrService); - } - return savedContainerOrService; + return savedContainerOrService; + }catch(Exception e) { + handleFailure(workflow); + } + return null; } private void startContainer(final UserI userI, final Container savedContainerOrService) throws NoDockerServerException, ContainerException { @@ -353,7 +361,7 @@ private void startContainer(final UserI userI, final Container savedContainerOrS containerControlApi.startContainer(savedContainerOrService); } catch (DockerServerException e) { addContainerHistoryItem(savedContainerOrService, ContainerHistory.fromSystem("Failed", "Did not start." + e.getMessage()), userI); - handleFailure(savedContainerOrService); + handleFailure(userI,savedContainerOrService); throw new ContainerException("Failed to start"); } } @@ -519,7 +527,7 @@ public void run() { log.debug("Docker event has not exited yet" + service.serviceId() + " Workflow: " + service.workflowId() + service.status()); } } - if (log.isDebugEnabled()){ + if (log.isInfoEnabled()){ int countOfContainersWaiting = containerEntityService.howManyContainersAreWaiting(); log.info("There are {}/{} being finalized at present with {} waiting",countOfContainersBeingFinalized,containerControlApi.getContainerFinalizationPoolLimit(),countOfContainersWaiting); } @@ -830,12 +838,27 @@ private InputStream getLogStream(final Container container, final String logFile return null; } - private void handleFailure(final Container container) { - // TODO handle failure + private void handleFailure(UserI userI,final Container container) { + try { + String workFlowId = container.workflowId(); + PersistentWorkflowI workflow = WorkflowUtils.getUniqueWorkflow(userI,workFlowId); + handleFailure(workflow); + }catch(Exception e) { + log.error("Unable to update workflow and set it to FAILED status for container", e); + } + } + + private void handleFailure(PersistentWorkflowI workflow) { + try { + workflow.setStatus(PersistentWorkflowUtils.FAILED); + WorkflowUtils.save(workflow, workflow.buildEvent()); + }catch(Exception e) { + log.error("Unable to update workflow and set it to FAILED status", e); + } } /** - * Creates a workflow if possible and returns its ID. + * Creates a workflow if possible and returns it. * * This is a way for us to show the * the container execution in the history table and as a workflow alert banner @@ -848,13 +871,11 @@ private void handleFailure(final Container container) { * workflow, so we don't make one. * * @param resolvedCommand A resolved command that will be used to launch a container - * @param containerOrService The Container object which refers to either a container launched on - * a single docker machine or a service created on a swarm * @param userI The user launching the container - * @return ID of the created workflow, or null if no workflow was created + * @return created workflow or null if no workflow was created */ @Nullable - private String makeWorkflowIfAppropriate(final ResolvedCommand resolvedCommand, final Container containerOrService, final UserI userI) { + private PersistentWorkflowI makeWorkflowIfAppropriate(final ResolvedCommand resolvedCommand, final UserI userI) { log.debug("Preparing to make workflow."); final XFTItem rootInputObject = findRootInputObject(resolvedCommand, userI); if (rootInputObject == null) { @@ -866,23 +887,39 @@ private String makeWorkflowIfAppropriate(final ResolvedCommand resolvedCommand, log.debug("Creating workflow for Wrapper {} - Command {} - Image {}.", resolvedCommand.wrapperName(), resolvedCommand.commandName(), resolvedCommand.image()); try { - final PersistentWorkflowI workflow = WorkflowUtils.buildOpenWorkflow(userI, rootInputObject, + PersistentWorkflowI workflow = WorkflowUtils.buildOpenWorkflow(userI, rootInputObject, EventUtils.newEventInstance(EventUtils.CATEGORY.DATA, EventUtils.TYPE.PROCESS, resolvedCommand.wrapperName(), "Container launch", - StringUtils.isNotBlank(containerOrService.serviceId()) ? - containerOrService.serviceId() : - containerOrService.containerId())); + "")); + workflow.setStatus(PersistentWorkflowUtils.QUEUED); WorkflowUtils.save(workflow, workflow.buildEvent()); log.debug("Created workflow {}.", workflow.getWorkflowId()); - return String.valueOf(workflow.getWorkflowId()); + return workflow; } catch (Exception e) { log.error("Could not create workflow.", e); } - return null; - } + } + private void addContainerInformationToWorkflow(PersistentWorkflowI wrk, Container containerOrService) { + if (wrk == null) { + log.debug("Cannot update workflow with container information."); + return; + } + try { + String wrkFlowComment = StringUtils.isNotBlank(containerOrService.serviceId()) ? + containerOrService.serviceId() : + containerOrService.containerId(); + wrk.setComments(wrkFlowComment); + wrk.setStatus(PersistentWorkflowUtils.IN_PROGRESS); + WorkflowUtils.save(wrk, wrk.buildEvent()); + log.debug("updated workflow {}.", wrk.getWorkflowId()); + } catch (Exception e) { + log.error("Could not create workflow.", e); + } + } + @Nullable private XFTItem findRootInputObject(final ResolvedCommand resolvedCommand, final UserI userI) { log.debug("Checking input values to find root XNAT input object."); diff --git a/src/main/java/org/nrg/containers/utils/JsonDateSerializer.java b/src/main/java/org/nrg/containers/utils/JsonDateSerializer.java new file mode 100644 index 000000000..4aa44db05 --- /dev/null +++ b/src/main/java/org/nrg/containers/utils/JsonDateSerializer.java @@ -0,0 +1,21 @@ +package org.nrg.containers.utils; + +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.Date; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; + +public class JsonDateSerializer extends JsonSerializer { + + private static final SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ"); + + @Override + public void serialize(Date value, JsonGenerator jgen, SerializerProvider provider) throws IOException, + JsonProcessingException { + jgen.writeString(format.format(value)); + } +} \ No newline at end of file diff --git a/src/main/java/org/nrg/containers/utils/JsonStringToDateSerializer.java b/src/main/java/org/nrg/containers/utils/JsonStringToDateSerializer.java new file mode 100644 index 000000000..87fb8bba2 --- /dev/null +++ b/src/main/java/org/nrg/containers/utils/JsonStringToDateSerializer.java @@ -0,0 +1,42 @@ +package org.nrg.containers.utils; + +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.Date; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; + +/** + * @author Mohana Ramaratnam + * + */ +public class JsonStringToDateSerializer extends JsonSerializer { + private static final SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ"); + + @Override + public void serialize(String value, JsonGenerator jgen, SerializerProvider provider) throws IOException, + JsonProcessingException { + if (value == null || value.equals("")) + return; + long longVal = Long.parseLong(value); + Date longAsDate = new Date(longVal); + jgen.writeString(format.format(longAsDate)); + } + + public static void main(String[] args) { + long longVal = Long.parseLong("1542051871478"); + Date longAsDate = new Date(longVal); + SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS Z"); + //System.out.println("String to Date: " + format.format(longAsDate)); + try { + Date d = format.parse("2018-11-03T12:45:38.615-05:00"); + long milliseconds = d.getTime(); + } catch (Exception e) { + e.printStackTrace(); + } + } + +} diff --git a/src/main/resources/META-INF/resources/scripts/search/csDataTableSearch.js b/src/main/resources/META-INF/resources/scripts/search/csDataTableSearch.js index b23a42084..a63b605f5 100644 --- a/src/main/resources/META-INF/resources/scripts/search/csDataTableSearch.js +++ b/src/main/resources/META-INF/resources/scripts/search/csDataTableSearch.js @@ -139,7 +139,7 @@ function DataTableSearch(_div_table_id, obj, _config, _options){ this.setDefaultValue("showReload", true); this.setDefaultValue("showOptionsDropdown", true); - this.setDefaultValue("showRcMenu", true); + this.setDefaultValue("showRcMenu", false); this.setDefaultValue("showFilterDisplay", true); this.setDefaultValue("allowInTableMods", true); @@ -280,7 +280,7 @@ function DataTableSearch(_div_table_id, obj, _config, _options){ "
" + "" + "" + - "" + + // "" + "" + ""; } diff --git a/src/main/resources/META-INF/resources/templates/screens/Search.vm b/src/main/resources/META-INF/resources/templates/screens/Search.vm deleted file mode 100644 index 7575933c2..000000000 --- a/src/main/resources/META-INF/resources/templates/screens/Search.vm +++ /dev/null @@ -1,77 +0,0 @@ -##Copyright 2005 Harvard University / Howard Hughes Medical Institute (HHMI) All Rights Reserved - - - - - - - - - - - - -#if ($data.message) -
$data.message
-
-#end - -
-
-
-
-
- -#if($xss) - -#end - - \ No newline at end of file