/* * Copyright © 2014-2015 Cask Data, Inc. * * 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 co.cask.cdap.logging.run; import co.cask.cdap.api.metrics.MetricsCollectionService; import co.cask.cdap.common.conf.CConfiguration; import co.cask.cdap.common.conf.Constants; import co.cask.cdap.common.guice.ConfigModule; import co.cask.cdap.common.guice.DiscoveryRuntimeModule; import co.cask.cdap.common.guice.IOModule; import co.cask.cdap.common.guice.KafkaClientModule; import co.cask.cdap.common.guice.LocationRuntimeModule; import co.cask.cdap.common.guice.ZKClientModule; import co.cask.cdap.data.runtime.DataFabricModules; import co.cask.cdap.data.runtime.DataSetsModules; import co.cask.cdap.data2.audit.AuditModule; import co.cask.cdap.logging.LoggingConfiguration; import co.cask.cdap.logging.guice.LogSaverServiceModule; import co.cask.cdap.logging.guice.LoggingModules; import co.cask.cdap.logging.save.KafkaLogSaverService; import co.cask.cdap.logging.service.LogSaverStatusService; import co.cask.cdap.metrics.guice.MetricsClientRuntimeModule; import com.google.common.base.Throwables; import com.google.common.collect.ImmutableMap; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.SettableFuture; import com.google.inject.Guice; import com.google.inject.Injector; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.security.UserGroupInformation; import org.apache.hadoop.util.ShutdownHookManager; import org.apache.twill.api.AbstractTwillRunnable; import org.apache.twill.api.TwillContext; import org.apache.twill.api.TwillRunnableSpecification; import org.apache.twill.internal.Services; import org.apache.twill.kafka.client.KafkaClientService; import org.apache.twill.zookeeper.ZKClientService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; import java.util.Map; import java.util.concurrent.ExecutionException; /** * Twill wrapper for running LogSaver through Twill. */ public final class LogSaverTwillRunnable extends AbstractTwillRunnable { private static final Logger LOG = LoggerFactory.getLogger(LogSaverTwillRunnable.class); private SettableFuture<?> completion; private String name; private String hConfName; private String cConfName; private ZKClientService zkClientService; private KafkaClientService kafkaClientService; private KafkaLogSaverService logSaverService; private LogSaverStatusService logSaverStatusService; private MetricsCollectionService metricsCollectionService; public LogSaverTwillRunnable(String name, String hConfName, String cConfName) { this.name = name; this.hConfName = hConfName; this.cConfName = cConfName; } @Override public TwillRunnableSpecification configure() { return TwillRunnableSpecification.Builder.with() .setName(name) .withConfigs(ImmutableMap.of( "hConf", hConfName, "cConf", cConfName )) .build(); } @Override public void initialize(TwillContext context) { super.initialize(context); completion = SettableFuture.create(); name = context.getSpecification().getName(); Map<String, String> configs = context.getSpecification().getConfigs(); LOG.info("Initialize runnable: " + name); try { // Load configuration Configuration hConf = new Configuration(); hConf.clear(); hConf.addResource(new File(configs.get("hConf")).toURI().toURL()); UserGroupInformation.setConfiguration(hConf); CConfiguration cConf = CConfiguration.create(new File(configs.get("cConf"))); cConf.set(Constants.LogSaver.ADDRESS, context.getHost().getCanonicalHostName()); // Initialize ZK client String zookeeper = cConf.get(Constants.Zookeeper.QUORUM); if (zookeeper == null) { LOG.error("No ZooKeeper quorum provided."); throw new IllegalStateException("No ZooKeeper quorum provided."); } Injector injector = createGuiceInjector(cConf, hConf); zkClientService = injector.getInstance(ZKClientService.class); kafkaClientService = injector.getInstance(KafkaClientService.class); logSaverService = injector.getInstance(KafkaLogSaverService.class); int numPartitions = Integer.parseInt(cConf.get(LoggingConfiguration.NUM_PARTITIONS, LoggingConfiguration.DEFAULT_NUM_PARTITIONS)); LOG.info("Num partitions = {}", numPartitions); logSaverStatusService = injector.getInstance(LogSaverStatusService.class); metricsCollectionService = injector.getInstance(MetricsCollectionService.class); LOG.info("Runnable initialized: " + name); } catch (Throwable t) { LOG.error(t.getMessage(), t); throw Throwables.propagate(t); } } @Override public void run() { LOG.info("Starting runnable " + name); // Register shutdown hook to stop Log Saver before Hadoop Filesystem shuts down ShutdownHookManager.get().addShutdownHook(new Runnable() { @Override public void run() { LOG.info("Shutdown hook triggered."); stop(); } }, FileSystem.SHUTDOWN_HOOK_PRIORITY + 1); Futures.getUnchecked(Services.chainStart(zkClientService, kafkaClientService, metricsCollectionService, logSaverService, logSaverStatusService)); LOG.info("Runnable started " + name); try { completion.get(); LOG.info("Runnable stopped " + name); } catch (InterruptedException e) { LOG.error("Waiting on completion interrupted", e); Thread.currentThread().interrupt(); } catch (ExecutionException e) { // Propagate the execution exception will causes TwillRunnable terminate with error, // and AM would detect and restarts it. LOG.error("Completed with exception. Exception get propagated", e); throw Throwables.propagate(e); } } @Override public void stop() { LOG.info("Stopping runnable " + name); Futures.getUnchecked(Services.chainStop(logSaverStatusService, logSaverService, metricsCollectionService, kafkaClientService, zkClientService)); completion.set(null); } private static Injector createGuiceInjector(CConfiguration cConf, Configuration hConf) { return Guice.createInjector( new ConfigModule(cConf, hConf), new IOModule(), new ZKClientModule(), new KafkaClientModule(), new MetricsClientRuntimeModule().getDistributedModules(), new DiscoveryRuntimeModule().getDistributedModules(), new LocationRuntimeModule().getDistributedModules(), new DataFabricModules().getDistributedModules(), new DataSetsModules().getDistributedModules(), new LogSaverServiceModule(), new LoggingModules().getDistributedModules(), new AuditModule().getDistributedModules() ); } }