All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.hubspot.singularity.data.DeployManager Maven / Gradle / Ivy

package com.hubspot.singularity.data;

import java.util.Collection;
import java.util.List;
import java.util.Map;

import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.utils.ZKPaths;
import org.apache.zookeeper.data.Stat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.annotation.Timed;
import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import com.hubspot.singularity.SingularityCreateResult;
import com.hubspot.singularity.SingularityDeleteResult;
import com.hubspot.singularity.SingularityDeploy;
import com.hubspot.singularity.SingularityDeployHistory;
import com.hubspot.singularity.SingularityDeployKey;
import com.hubspot.singularity.SingularityDeployMarker;
import com.hubspot.singularity.SingularityDeployResult;
import com.hubspot.singularity.SingularityDeployStatistics;
import com.hubspot.singularity.SingularityDeployUpdate;
import com.hubspot.singularity.SingularityDeployUpdate.DeployEventType;
import com.hubspot.singularity.SingularityPendingDeploy;
import com.hubspot.singularity.SingularityRequest;
import com.hubspot.singularity.SingularityRequestDeployState;
import com.hubspot.singularity.SingularityUpdatePendingDeployRequest;
import com.hubspot.singularity.config.SingularityConfiguration;
import com.hubspot.singularity.data.transcoders.IdTranscoder;
import com.hubspot.singularity.data.transcoders.Transcoder;
import com.hubspot.singularity.event.SingularityEventListener;
import com.hubspot.singularity.scheduler.SingularityLeaderCache;

@Singleton
public class DeployManager extends CuratorAsyncManager {

  private static final Logger LOG = LoggerFactory.getLogger(DeployManager.class);

  private final SingularityEventListener singularityEventListener;
  private final Transcoder deployTranscoder;
  private final Transcoder pendingDeployTranscoder;
  private final Transcoder deployMarkerTranscoder;
  private final Transcoder requestDeployStateTranscoder;
  private final Transcoder deployStatisticsTranscoder;
  private final Transcoder deployStateTranscoder;
  private final Transcoder updateRequestTranscoder;

  private final IdTranscoder deployKeyTranscoder;

  private final ZkCache deploysCache;
  private final SingularityLeaderCache leaderCache;

  private static final String DEPLOY_ROOT = "/deploys";

  private static final String PENDING_ROOT = DEPLOY_ROOT + "/pending";
  private static final String CANCEL_ROOT = DEPLOY_ROOT + "/cancel";
  private static final String UPDATE_ROOT = DEPLOY_ROOT + "/update";

  private static final String BY_REQUEST_ROOT = DEPLOY_ROOT + "/requests";

  private static final String REQUEST_DEPLOY_STATE_KEY = "STATE";
  private static final String DEPLOY_LIST_KEY = "/ids";

  private static final String DEPLOY_DATA_KEY = "DEPLOY";
  private static final String DEPLOY_MARKER_KEY = "MARKER";
  private static final String DEPLOY_STATISTICS_KEY = "STATISTICS";
  private static final String DEPLOY_RESULT_KEY = "RESULT_STATE";

  @Inject
  public DeployManager(CuratorFramework curator, SingularityConfiguration configuration, MetricRegistry metricRegistry, SingularityEventListener singularityEventListener, Transcoder deployTranscoder,
                       Transcoder requestDeployStateTranscoder, Transcoder pendingDeployTranscoder, Transcoder deployMarkerTranscoder,
                       Transcoder deployStatisticsTranscoder, Transcoder deployStateTranscoder, IdTranscoder deployKeyTranscoder,
                       Transcoder updateRequestTranscoder, ZkCache deploysCache, SingularityLeaderCache leaderCache) {
    super(curator, configuration, metricRegistry);

    this.singularityEventListener = singularityEventListener;
    this.pendingDeployTranscoder = pendingDeployTranscoder;
    this.deployTranscoder = deployTranscoder;
    this.deployStatisticsTranscoder = deployStatisticsTranscoder;
    this.deployMarkerTranscoder = deployMarkerTranscoder;
    this.requestDeployStateTranscoder = requestDeployStateTranscoder;
    this.deployStateTranscoder = deployStateTranscoder;
    this.deployKeyTranscoder = deployKeyTranscoder;
    this.updateRequestTranscoder = updateRequestTranscoder;
    this.deploysCache = deploysCache;
    this.leaderCache = leaderCache;
  }

  public List getDeployIdsFor(String requestId) {
    return getChildrenAsIds(getDeployIdPath(requestId), deployKeyTranscoder);
  }

  public List getAllDeployIds() {
    final List requestIds = getChildren(BY_REQUEST_ROOT);
    final List paths = Lists.newArrayListWithCapacity(requestIds.size());

    for (String requestId : requestIds) {
      paths.add(getDeployIdPath(requestId));
    }

    return getChildrenAsIdsForParents("getAllDeployIds", paths, deployKeyTranscoder);
  }

  @Timed
  public Map getRequestDeployStatesByRequestIds(Collection requestIds) {
    if (leaderCache.active()) {
      return leaderCache.getRequestDeployStateByRequestId(requestIds);
    }

    return fetchDeployStatesByRequestIds(requestIds);
  }

  public Map fetchDeployStatesByRequestIds(Collection requestIds) {
    final List paths = Lists.newArrayListWithCapacity(requestIds.size());

    for (String requestId : requestIds) {
      paths.add(getRequestDeployStatePath(requestId));
    }

    return Maps.uniqueIndex(getAsync("getRequestDeployStatesByRequestIds", paths, requestDeployStateTranscoder), new Function() {

      @Override
      public String apply(SingularityRequestDeployState input) {
        return input.getRequestId();
      }

    });
  }

  @Timed
  public Map getAllRequestDeployStatesByRequestId() {
    if (leaderCache.active()) {
      return leaderCache.getRequestDeployStateByRequestId();
    }
    final List requestIds = getChildren(BY_REQUEST_ROOT);
    return fetchDeployStatesByRequestIds(requestIds);
  }

  public List getCancelDeploys() {
    return getAsyncChildren(CANCEL_ROOT, deployMarkerTranscoder);
  }

  @Timed
  public List getPendingDeploys() {
    return getAsyncChildren(PENDING_ROOT, pendingDeployTranscoder);
  }

  private String getRequestDeployPath(String requestId) {
    return ZKPaths.makePath(BY_REQUEST_ROOT, requestId);
  }

  private String getDeployStatisticsPath(String requestId, String deployId) {
    return ZKPaths.makePath(getDeployParentPath(requestId, deployId), DEPLOY_STATISTICS_KEY);
  }

  private String getDeployResultPath(String requestId, String deployId) {
    return ZKPaths.makePath(getDeployParentPath(requestId, deployId), DEPLOY_RESULT_KEY);
  }

  private String getDeployIdPath(String requestId) {
    return ZKPaths.makePath(getRequestDeployPath(requestId), DEPLOY_LIST_KEY);
  }

  private String getDeployParentPath(String requestId, String deployId) {
    return ZKPaths.makePath(getDeployIdPath(requestId), new SingularityDeployKey(requestId, deployId).getId());
  }

  private String getDeployDataPath(String requestId, String deployId) {
    return ZKPaths.makePath(getDeployParentPath(requestId, deployId), DEPLOY_DATA_KEY);
  }

  private String getDeployMarkerPath(String requestId, String deployId) {
    return ZKPaths.makePath(getDeployParentPath(requestId, deployId), DEPLOY_MARKER_KEY);
  }

  private String getRequestDeployStatePath(String requestId) {
    return ZKPaths.makePath(getRequestDeployPath(requestId), REQUEST_DEPLOY_STATE_KEY);
  }

  public Map getDeploysForKeys(Collection deployKeys) {
    final List paths = Lists.newArrayListWithCapacity(deployKeys.size());

    for (SingularityDeployKey deployKey : deployKeys) {
      paths.add(getDeployDataPath(deployKey.getRequestId(), deployKey.getDeployId()));
    }

    final List deploys = getAsync("getDeploysForKeys", paths, deployTranscoder, deploysCache);

    final Map deployKeyToDeploy = Maps.uniqueIndex(deploys, new Function() {
      @Override
      public SingularityDeployKey apply(SingularityDeploy input) {
        return SingularityDeployKey.fromDeploy(input);
      }
    });

    return deployKeyToDeploy;
  }

  public SingularityCreateResult saveDeploy(SingularityRequest request, SingularityDeployMarker deployMarker, SingularityDeploy deploy) {
    final SingularityCreateResult deploySaveResult = create(getDeployDataPath(deploy.getRequestId(), deploy.getId()), deploy, deployTranscoder);

    if (deploySaveResult == SingularityCreateResult.EXISTED) {
      LOG.info("Deploy object for {} already existed (new marker: {})", deploy, deployMarker);
    }

    singularityEventListener.deployHistoryEvent(new SingularityDeployUpdate(deployMarker, Optional.of(deploy), DeployEventType.STARTING, Optional.absent()));

    create(getDeployMarkerPath(deploy.getRequestId(), deploy.getId()), deployMarker, deployMarkerTranscoder);

    final Optional currentState = getRequestDeployState(deploy.getRequestId());

    Optional activeDeploy = Optional.absent();
    Optional pendingDeploy = Optional.absent();

    if (request.isDeployable()) {
      if (currentState.isPresent()) {
        activeDeploy = currentState.get().getActiveDeploy();
      }
      pendingDeploy = Optional.of(deployMarker);
    } else {
      activeDeploy = Optional.of(deployMarker);
    }

    final SingularityRequestDeployState newState = new SingularityRequestDeployState(deploy.getRequestId(), activeDeploy, pendingDeploy);

    return saveNewRequestDeployState(newState);
  }

  public Optional getDeployHistory(String requestId, String deployId, boolean loadEntireHistory) {
    Optional deployMarker = getData(getDeployMarkerPath(requestId, deployId), deployMarkerTranscoder);

    if (!deployMarker.isPresent()) {
      return Optional.absent();
    }

    Optional deployState = getDeployResult(requestId, deployId);

    if (!loadEntireHistory) {
      return Optional.of(new SingularityDeployHistory(deployState, deployMarker.get(), Optional. absent(), Optional.absent()));
    }

    Optional deploy = getDeploy(requestId, deployId);

    if (!deploy.isPresent()) {
      return Optional.absent();
    }

    Optional deployStatistics = getDeployStatistics(requestId, deployId);

    return Optional.of(new SingularityDeployHistory(deployState, deployMarker.get(), deploy, deployStatistics));
  }

  public Optional getDeploy(String requestId, String deployId) {
    final String deployPath = getDeployDataPath(requestId, deployId);

    return getData(deployPath, deployTranscoder, deploysCache, true);
  }

  public Optional getInUseDeployId(String requestId) {
    Optional deployState = getRequestDeployState(requestId);

    if (!deployState.isPresent() || !deployState.get().getActiveDeploy().isPresent() && !deployState.get().getPendingDeploy().isPresent()) {
      return Optional.absent();
    }

    return Optional.of(deployState.get().getActiveDeploy().or(deployState.get().getPendingDeploy()).get().getDeployId());
  }

  public Optional getRequestDeployState(String requestId) {
    if (leaderCache.active()) {
      return leaderCache.getRequestDeployState(requestId);
    }
    return getData(getRequestDeployStatePath(requestId), requestDeployStateTranscoder);
  }

  public SingularityCreateResult saveNewRequestDeployState(SingularityRequestDeployState newDeployState) {
    if (leaderCache.active()) {
      leaderCache.putRequestDeployState(newDeployState);
    }

    return save(getRequestDeployStatePath(newDeployState.getRequestId()), newDeployState, requestDeployStateTranscoder);
  }

  public Optional getDeployStatistics(String requestId, String deployId) {
    return getData(getDeployStatisticsPath(requestId, deployId), deployStatisticsTranscoder);
  }

  public SingularityCreateResult saveDeployStatistics(SingularityDeployStatistics newDeployStatistics) {
    return save(getDeployStatisticsPath(newDeployStatistics.getRequestId(), newDeployStatistics.getDeployId()), newDeployStatistics, deployStatisticsTranscoder);
  }

  private String getPendingDeployPath(String requestId) {
    return ZKPaths.makePath(PENDING_ROOT, requestId);
  }

  private String getCancelDeployPath(SingularityDeployMarker deployMarker) {
    return ZKPaths.makePath(CANCEL_ROOT, String.format("%s-%s", deployMarker.getRequestId(), deployMarker.getDeployId()));
  }

  public SingularityCreateResult createCancelDeployRequest(SingularityDeployMarker deployMarker) {
    return create(getCancelDeployPath(deployMarker), deployMarker, deployMarkerTranscoder);
  }

  public SingularityDeleteResult deleteRequestDeployState(String requestId) {
    if (leaderCache.active()) {
      leaderCache.deleteRequestDeployState(requestId);
    }
    return delete(getRequestDeployStatePath(requestId));
  }

  public SingularityDeleteResult deleteDeployHistory(SingularityDeployKey deployKey) {
    return delete(getDeployParentPath(deployKey.getRequestId(), deployKey.getDeployId()));
  }

  public SingularityDeleteResult deletePendingDeploy(String requestId) {
    return delete(getPendingDeployPath(requestId));
  }

  public SingularityDeleteResult deleteCancelDeployRequest(SingularityDeployMarker deployMarker) {
    LOG.debug("Removing cancel deploy request {}", deployMarker);
    return delete(getCancelDeployPath(deployMarker));
  }

  public SingularityCreateResult createPendingDeploy(SingularityPendingDeploy pendingDeploy) {
    return create(getPendingDeployPath(pendingDeploy.getDeployMarker().getRequestId()), pendingDeploy, pendingDeployTranscoder);
  }

  public SingularityCreateResult savePendingDeploy(SingularityPendingDeploy pendingDeploy) {
    return save(getPendingDeployPath(pendingDeploy.getDeployMarker().getRequestId()), pendingDeploy, pendingDeployTranscoder);
  }

  public Optional getPendingDeploy(String requestId) {
    return getData(getPendingDeployPath(requestId), pendingDeployTranscoder);
  }

  public SingularityCreateResult saveDeployResult(SingularityDeployMarker deployMarker, Optional deploy, SingularityDeployResult result) {
    singularityEventListener.deployHistoryEvent(new SingularityDeployUpdate(deployMarker, deploy, DeployEventType.FINISHED, Optional.of(result)));

    return save(getDeployResultPath(deployMarker.getRequestId(), deployMarker.getDeployId()), result, deployStateTranscoder);
  }

  public Optional getDeployResult(String requestId, String deployId) {
    return getData(getDeployResultPath(requestId, deployId), deployStateTranscoder);
  }

  private String getUpdatePendingDeployPath(SingularityUpdatePendingDeployRequest updateRequest) {
    return ZKPaths.makePath(UPDATE_ROOT, String.format("%s-%s", updateRequest.getRequestId(), updateRequest.getDeployId()));
  }

  public SingularityCreateResult createUpdatePendingDeployRequest(SingularityUpdatePendingDeployRequest updateRequest) {
    return create(getUpdatePendingDeployPath(updateRequest), updateRequest, updateRequestTranscoder);
  }

  public SingularityDeleteResult deleteUpdatePendingDeployRequest(SingularityUpdatePendingDeployRequest updateRequest) {
    LOG.debug("Removing request to update pending deploy {}", updateRequest);
    return delete(getUpdatePendingDeployPath(updateRequest));
  }

  public List getPendingDeployUpdates() {
    return getAsyncChildren(UPDATE_ROOT, updateRequestTranscoder);
  }

  public void purgeStaleRequests(List activeRequestIds, long deleteBeforeTime) {
    final List requestIds = getChildren(BY_REQUEST_ROOT);
    for (String requestId : requestIds) {
      if (!activeRequestIds.contains(requestId)) {
        String path = getRequestDeployPath(requestId);
        Optional maybeStat = checkExists(path);
        if (maybeStat.isPresent() && maybeStat.get().getMtime() < deleteBeforeTime && !getChildren(path).contains(REQUEST_DEPLOY_STATE_KEY)) {
          delete(path);
        }
      }
    }
  }

  public SingularityDeleteResult deleteRequestId(String requestId) {
    return delete(getRequestDeployPath(requestId));
  }

  public void activateLeaderCache() {
    final List requestIds = getChildren(BY_REQUEST_ROOT);
    leaderCache.cacheRequestDeployStates(fetchDeployStatesByRequestIds(requestIds));
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy