/* * Copyright 2015 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.admin.deployment.zk; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import org.apache.curator.framework.CuratorFramework; import org.apache.zookeeper.KeeperException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.util.Assert; import org.springframework.xd.dirt.cluster.Container; 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.Stream; import org.springframework.xd.dirt.server.admin.deployment.ContainerMatcher; import org.springframework.xd.dirt.server.admin.deployment.DeploymentUnitStateCalculator; import org.springframework.xd.dirt.server.admin.deployment.ModuleDeploymentStatus; import org.springframework.xd.dirt.server.admin.deployment.StreamRuntimePropertiesProvider; import org.springframework.xd.dirt.stream.StreamFactory; import org.springframework.xd.dirt.zookeeper.Paths; import org.springframework.xd.dirt.zookeeper.ZooKeeperUtils; import org.springframework.xd.module.ModuleDeploymentProperties; import org.springframework.xd.module.ModuleDescriptor; /** * Deployment handler that is responsible for deploying Stream. * * @author Patrick Peralta * @author Mark Fisher * @author Ilayaperumal Gopinathan */ public class ZKStreamDeploymentHandler extends ZKDeploymentHandler { /** * Logger. */ private static final Logger logger = LoggerFactory.getLogger(ZKStreamDeploymentHandler.class); /** * Factory to construct {@link org.springframework.xd.dirt.core.Stream} instance */ @Autowired private StreamFactory streamFactory; /** * Matcher that applies container matching criteria */ @Autowired private ContainerMatcher containerMatcher; /** * Repository for the containers */ @Autowired private ContainerRepository containerRepository; /** * Utility that writes module deployment requests to ZK path */ @Autowired private ModuleDeploymentWriter moduleDeploymentWriter; /** * Deployment unit state calculator */ @Autowired private DeploymentUnitStateCalculator stateCalculator; /** * Deploy the stream with the given name. * @param streamName the stream name * @throws Exception */ public void deploy(String streamName) throws Exception { CuratorFramework client = zkConnection.getClient(); deployStream(client, DeploymentLoader.loadStream(client, streamName, streamFactory)); } /** * Issue deployment requests for the modules of the given stream. * * @param stream stream to be deployed * * @throws InterruptedException */ private void deployStream(CuratorFramework client, Stream stream) throws InterruptedException { // 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.STREAM_DEPLOYMENTS, stream.getName(), Paths.MODULES)); } catch (Exception e) { ZooKeeperUtils.wrapAndThrowIgnoring(e, KeeperException.NodeExistsException.class); } String statusPath = Paths.build(Paths.STREAM_DEPLOYMENTS, stream.getName(), Paths.STATUS); // assert that the deployment status has been correctly set to "deploying" 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 stream '%s'; current status: %s", stream.getName(), deployingStatus)); try { Collection<ModuleDeploymentStatus> deploymentStatuses = new ArrayList<ModuleDeploymentStatus>(); DefaultModuleDeploymentPropertiesProvider deploymentPropertiesProvider = new DefaultModuleDeploymentPropertiesProvider(stream); for (Iterator<ModuleDescriptor> descriptors = stream.getDeploymentOrderIterator(); descriptors.hasNext(); ) { ModuleDescriptor descriptor = descriptors.next(); ModuleDeploymentProperties deploymentProperties = deploymentPropertiesProvider.propertiesForDescriptor(descriptor); // write out all of the required modules for this stream (including runtime properties); // this does not actually perform a deployment...this data is used in case there are not // enough containers to deploy the stream StreamRuntimePropertiesProvider partitionPropertiesProvider = new StreamRuntimePropertiesProvider(stream, deploymentPropertiesProvider); int moduleCount = deploymentProperties.getCount(); if (moduleCount == 0) { createModuleDeploymentRequestsPath(client, descriptor, partitionPropertiesProvider.propertiesForDescriptor(descriptor)); } else { for (int i = 0; i < moduleCount; i++) { createModuleDeploymentRequestsPath(client, descriptor, partitionPropertiesProvider.propertiesForDescriptor(descriptor)); } } try { // find the containers that can deploy these modules Collection<Container> containers = containerMatcher.match(descriptor, deploymentProperties, containerRepository.findAll()); // write out the deployment requests targeted to the containers obtained above; // a new instance of StreamPartitionPropertiesProvider is created since this // object is responsible for generating unique sequence ids for modules StreamRuntimePropertiesProvider deploymentRuntimeProvider = new StreamRuntimePropertiesProvider(stream, deploymentPropertiesProvider); deploymentStatuses.addAll(moduleDeploymentWriter.writeDeployment( descriptor, deploymentRuntimeProvider, containers)); } catch (NoContainerException e) { logger.warn("No containers available for deployment of module '{}' for stream '{}'", descriptor.getModuleLabel(), stream.getName()); } } DeploymentUnitStatus status = stateCalculator.calculate(stream, deploymentPropertiesProvider, deploymentStatuses); logger.info("Deployment status for stream '{}': {}", stream.getName(), status); client.setData().forPath(statusPath, ZooKeeperUtils.mapToBytes(status.toMap())); } catch (InterruptedException e) { throw e; } catch (Exception e) { throw ZooKeeperUtils.wrapThrowable(e); } } }