Package org.springframework.xd.dirt.server

Source Code of org.springframework.xd.dirt.server.JobDeploymentListener

/*
* Copyright 2014 the original author or authors.
*
* Licensed 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.springframework.xd.dirt.server;

import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Deque;
import java.util.Iterator;
import java.util.List;

import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.recipes.cache.ChildData;
import org.apache.curator.framework.recipes.cache.PathChildrenCache;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.data.Stat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.springframework.util.Assert;
import org.springframework.xd.dirt.cluster.Container;
import org.springframework.xd.dirt.cluster.ContainerMatcher;
import org.springframework.xd.dirt.cluster.NoContainerException;
import org.springframework.xd.dirt.container.store.ContainerRepository;
import org.springframework.xd.dirt.core.DeploymentUnitStatus;
import org.springframework.xd.dirt.core.Job;
import org.springframework.xd.dirt.core.JobDeploymentsPath;
import org.springframework.xd.dirt.job.JobFactory;
import org.springframework.xd.dirt.zookeeper.ChildPathIterator;
import org.springframework.xd.dirt.zookeeper.Paths;
import org.springframework.xd.dirt.zookeeper.ZooKeeperConnection;
import org.springframework.xd.dirt.zookeeper.ZooKeeperUtils;
import org.springframework.xd.module.ModuleDeploymentProperties;
import org.springframework.xd.module.ModuleDescriptor;
import org.springframework.xd.module.ModuleType;
import org.springframework.xd.module.RuntimeModuleDeploymentProperties;


/**
* Listener implementation that handles job deployment requests.
*
* @author Patrick Peralta
* @author Mark Fisher
* @author Ilayaperumal Gopinathan
*/
public class JobDeploymentListener extends InitialDeploymentListener {

  /**
   * Logger.
   */
  private static final Logger logger = LoggerFactory.getLogger(JobDeploymentListener.class);

  /**
   * Job factory.
   */
  private final JobFactory jobFactory;

  /**
   * Construct a JobDeploymentListener.
   *
   * @param zkConnection ZooKeeper connection
   * @param moduleDeploymentRequests the requested module deployments
   * @param containerRepository repository to obtain container data
   * @param jobFactory factory to construct {@link Job}
   * @param containerMatcher matches modules to containers
   * @param stateCalculator calculator for job state
   */
  public JobDeploymentListener(ZooKeeperConnection zkConnection, PathChildrenCache moduleDeploymentRequests,
      ContainerRepository containerRepository, JobFactory jobFactory,
      ContainerMatcher containerMatcher, DeploymentUnitStateCalculator stateCalculator) {
    super(zkConnection, moduleDeploymentRequests, containerRepository, containerMatcher, stateCalculator);
    this.jobFactory = jobFactory;
  }

  /**
   * Handle the creation of a new job deployment.
   *
   * @param client curator client
   * @param data job deployment request data
   */
  @Override
  protected void onChildAdded(CuratorFramework client, ChildData data) throws Exception {
    String jobName = Paths.stripPath(data.getPath());
    Job job = DeploymentLoader.loadJob(client, jobName, jobFactory);
    deployJob(client, job);
  }

  /**
   * Issue deployment requests for a job. This deployment will occur if:
   * <ul>
   *     <li>the job has not been destroyed</li>
   *     <li>the job has not been undeployed</li>
   *     <li>there is a container that can deploy the job</li>
   * </ul>
   *
   * @param job the job instance to redeploy
   * @throws InterruptedException
   */
  private void deployJob(CuratorFramework client, final Job job) throws InterruptedException {
    if (job != null) {
      // Ensure that the path for modules used by the container to write
      // ephemeral nodes exists. The presence of this path is assumed
      // by the supervisor when it calculates stream state when it is
      // assigned leadership. See XD-2170 for details.
      try {
        client.create().creatingParentsIfNeeded().forPath(Paths.build(
            Paths.JOB_DEPLOYMENTS, job.getName(), Paths.MODULES));
      }
      catch (Exception e) {
        ZooKeeperUtils.wrapAndThrowIgnoring(e, KeeperException.NodeExistsException.class);
      }

      String statusPath = Paths.build(Paths.JOB_DEPLOYMENTS, job.getName(), Paths.STATUS);

      DeploymentUnitStatus deployingStatus = null;
      try {
        deployingStatus = new DeploymentUnitStatus(ZooKeeperUtils.bytesToMap(
            client.getData().forPath(statusPath)));
      }
      catch (Exception e) {
        // an exception indicates that the status has not been set
      }
      Assert.state(deployingStatus != null
          && deployingStatus.getState() == DeploymentUnitStatus.State.deploying,
          String.format("Expected 'deploying' status for job '%s'; current status: %s",
              job.getName(), deployingStatus));

      ModuleDeploymentPropertiesProvider<ModuleDeploymentProperties> provider =
          new DefaultModuleDeploymentPropertiesProvider(job);

      try {
        Collection<ModuleDeploymentStatus> deploymentStatuses = new ArrayList<ModuleDeploymentStatus>();
        for (ModuleDescriptor descriptor : job.getModuleDescriptors()) {
          RuntimeModuleDeploymentProperties deploymentProperties = new RuntimeModuleDeploymentProperties();
          deploymentProperties.putAll(provider.propertiesForDescriptor(descriptor));
          Deque<Container> matchedContainers = new ArrayDeque<Container>(containerMatcher.match(descriptor,
              deploymentProperties,
              containerRepository.findAll()));
          // Modules count == 0
          if (deploymentProperties.getCount() == 0) {
            deploymentProperties.setSequence(0);
            createModuleDeploymentRequestsPath(client, descriptor, deploymentProperties);
          }
          // Modules count > 0
          else {
            for (int i = 1; i <= deploymentProperties.getCount(); i++) {
              deploymentProperties.setSequence(i);
              createModuleDeploymentRequestsPath(client, descriptor, deploymentProperties);
            }
          }
          RuntimeModuleDeploymentPropertiesProvider deploymentRuntimeProvider =
              new RuntimeModuleDeploymentPropertiesProvider(provider);

          try {
            deploymentStatuses.addAll(moduleDeploymentWriter.writeDeployment(
                descriptor, deploymentRuntimeProvider, matchedContainers));
          }
          catch (NoContainerException e) {
            logger.warn("No containers available for deployment of job {}", job.getName());
          }

          DeploymentUnitStatus status = stateCalculator.calculate(job, provider, deploymentStatuses);

          logger.info("Deployment status for job '{}': {}", job.getName(), status);

          client.setData().forPath(statusPath, ZooKeeperUtils.mapToBytes(status.toMap()));
        }
      }
      catch (InterruptedException e) {
        throw e;
      }
      catch (Exception e) {
        throw ZooKeeperUtils.wrapThrowable(e);
      }
    }
  }

  /**
   * Iterate all deployed jobs, recalculate the deployment status of each, and
   * create an ephemeral node indicating the job state. This is typically invoked
   * upon leader election.
   *
   * @param client          curator client
   * @param jobDeployments  curator cache of job deployments
   * @throws Exception
   */
  public void recalculateJobStates(CuratorFramework client, PathChildrenCache jobDeployments) throws Exception {
    for (Iterator<String> iterator = new ChildPathIterator<String>(ZooKeeperUtils.stripPathConverter,
        jobDeployments); iterator.hasNext();) {
      String jobName = iterator.next();
      Job job = DeploymentLoader.loadJob(client, jobName, jobFactory);
      if (job != null) {
        String jobModulesPath = Paths.build(Paths.JOB_DEPLOYMENTS, jobName, Paths.MODULES);
        List<ModuleDeploymentStatus> statusList = new ArrayList<ModuleDeploymentStatus>();
        List<String> moduleDeployments = client.getChildren().forPath(jobModulesPath);
        for (String moduleDeployment : moduleDeployments) {
          JobDeploymentsPath jobDeploymentsPath = new JobDeploymentsPath(
              Paths.build(jobModulesPath, moduleDeployment));
          statusList.add(new ModuleDeploymentStatus(
              jobDeploymentsPath.getContainer(),
              jobDeploymentsPath.getModuleSequence(),
              new ModuleDescriptor.Key(jobName, ModuleType.job, jobDeploymentsPath.getModuleLabel()),
              ModuleDeploymentStatus.State.deployed, null));
        }
        DeploymentUnitStatus status = stateCalculator.calculate(job,
            new DefaultModuleDeploymentPropertiesProvider(job), statusList);

        logger.info("Deployment status for job '{}': {}", job.getName(), status);

        String statusPath = Paths.build(Paths.JOB_DEPLOYMENTS, job.getName(), Paths.STATUS);
        Stat stat = client.checkExists().forPath(statusPath);
        if (stat != null) {
          logger.trace("Found old status path {}; stat: {}", statusPath, stat);
          client.delete().forPath(statusPath);
        }
        client.create().withMode(CreateMode.EPHEMERAL).forPath(statusPath,
            ZooKeeperUtils.mapToBytes(status.toMap()));
      }
    }
  }

}
TOP

Related Classes of org.springframework.xd.dirt.server.JobDeploymentListener

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.