/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 gobblin.cluster; import java.io.File; import java.util.List; import java.util.Properties; import javax.annotation.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.base.Optional; import com.google.common.eventbus.EventBus; import com.google.common.util.concurrent.AbstractIdleService; import com.typesafe.config.Config; import gobblin.annotation.Alpha; import gobblin.cluster.event.DeleteJobConfigArrivalEvent; import gobblin.cluster.event.NewJobConfigArrivalEvent; import gobblin.cluster.event.UpdateJobConfigArrivalEvent; import gobblin.configuration.ConfigurationKeys; import gobblin.util.ConfigUtils; import gobblin.util.SchedulerUtils; /** * A class for managing Gobblin job configurations. * * <p> * Currently this class reads all-at-once at startup all the job configuration files found * in the directory uncompressed from the job configuration file package and have them all * scheduled by the {@link GobblinHelixJobScheduler} by posting a * {@link NewJobConfigArrivalEvent} for each job configuration file. * </p> * * <p> * In the future, we may add the ability to accept new job configuration files or updates * to existing configuration files at runtime to this class. * </p> * * @author Yinan Li */ @Alpha public class JobConfigurationManager extends AbstractIdleService { private static final Logger LOGGER = LoggerFactory.getLogger(JobConfigurationManager.class); protected final EventBus eventBus; protected final Config config; protected Optional<String> jobConfDirPath; public JobConfigurationManager(EventBus eventBus, Config config) { this.eventBus = eventBus; this.config = config; this.jobConfDirPath = config.hasPath(GobblinClusterConfigurationKeys.JOB_CONF_PATH_KEY) ? Optional .of(config.getString(GobblinClusterConfigurationKeys.JOB_CONF_PATH_KEY)) : Optional.<String>absent(); } @Override protected void startUp() throws Exception { if (this.jobConfDirPath.isPresent()) { File path = new File(this.jobConfDirPath.get()); File jobConfigDir = path; // Backward compatibility: Previous impl was forcing users to look for jobConf within ${user.dir} // .. so if jobConfigDir does not exists, try to resolve config path via legacy route for backward // .. compatibility if (!path.exists()) { String pwd = System.getProperty("user.dir"); jobConfigDir = new File(pwd, path.getName() + GobblinClusterConfigurationKeys.TAR_GZ_FILE_SUFFIX); } if (jobConfigDir.exists()) { LOGGER.info("Loading job configurations from " + jobConfigDir); Properties properties = ConfigUtils.configToProperties(this.config); properties.setProperty(ConfigurationKeys.JOB_CONFIG_FILE_GENERAL_PATH_KEY, "file://" + jobConfigDir.getAbsolutePath()); List<Properties> jobConfigs = SchedulerUtils.loadGenericJobConfigs(properties); LOGGER.info("Loaded " + jobConfigs.size() + " job configuration(s)"); for (Properties config : jobConfigs) { postNewJobConfigArrival(config.getProperty(ConfigurationKeys.JOB_NAME_KEY), config); } } else { LOGGER.warn("Job configuration directory " + jobConfigDir + " not found"); } } } @Override protected void shutDown() throws Exception { // Nothing to do } protected void postNewJobConfigArrival(String jobName, Properties jobConfig) { LOGGER.info(String.format("Posting new JobConfig with name: %s and config: %s", jobName, jobConfig)); this.eventBus.post(new NewJobConfigArrivalEvent(jobName, jobConfig)); } protected void postUpdateJobConfigArrival(String jobName, Properties jobConfig) { LOGGER.info(String.format("Posting update JobConfig with name: %s and config: %s", jobName, jobConfig)); this.eventBus.post(new UpdateJobConfigArrivalEvent(jobName, jobConfig)); } protected void postDeleteJobConfigArrival(String jobName, @Nullable Properties jobConfig) { LOGGER.info(String.format("Posting delete JobConfig with name: %s and config: %s", jobName, jobConfig)); this.eventBus.post(new DeleteJobConfigArrivalEvent(jobName, jobConfig)); } }