/** * 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 org.apache.falcon.oozie; import org.apache.commons.lang3.StringUtils; import org.apache.falcon.FalconException; import org.apache.falcon.entity.ClusterHelper; import org.apache.falcon.entity.EntityUtil; import org.apache.falcon.entity.HiveUtil; import org.apache.falcon.entity.v0.Entity; import org.apache.falcon.entity.v0.cluster.Cluster; import org.apache.falcon.hadoop.HadoopClientFactory; import org.apache.falcon.oozie.bundle.BUNDLEAPP; import org.apache.falcon.oozie.bundle.CONFIGURATION; import org.apache.falcon.oozie.bundle.CONFIGURATION.Property; import org.apache.falcon.oozie.bundle.COORDINATOR; import org.apache.falcon.security.CurrentUser; import org.apache.falcon.util.OozieUtils; import org.apache.falcon.workflow.engine.AbstractWorkflowEngine; import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.Path; import org.apache.oozie.client.OozieClient; import org.apache.falcon.Tag; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.xml.bind.JAXBElement; import javax.xml.bind.JAXBException; import javax.xml.bind.Unmarshaller; import javax.xml.transform.stream.StreamSource; import java.io.IOException; import java.util.List; import java.util.Map.Entry; import java.util.Properties; /** * Base class for building oozie bundle - bundle is the entity that falcon tracks in oozie. * @param <T> */ public abstract class OozieBundleBuilder<T extends Entity> extends OozieEntityBuilder<T> { public static final Logger LOG = LoggerFactory.getLogger(OozieBundleBuilder.class); public OozieBundleBuilder(T entity) { super(entity); } @Override public Properties build(Cluster cluster, Path buildPath) throws FalconException { String clusterName = cluster.getName(); if (EntityUtil.getStartTime(entity, clusterName).compareTo(EntityUtil.getEndTime(entity, clusterName)) >= 0) { LOG.info("process validity start <= end for cluster {}. Skipping schedule", clusterName); return null; } List<Properties> coords = buildCoords(cluster, buildPath); if (coords == null || coords.isEmpty()) { return null; } BUNDLEAPP bundle = new BUNDLEAPP(); bundle.setName(EntityUtil.getWorkflowName(entity).toString()); // all the properties are set prior to bundle and coordinators creation for (Properties coordProps : coords) { // add the coordinator to the bundle COORDINATOR coord = new COORDINATOR(); String coordPath = coordProps.getProperty(OozieEntityBuilder.ENTITY_PATH); final String coordName = coordProps.getProperty(OozieEntityBuilder.ENTITY_NAME); coord.setName(coordName); coord.setAppPath(getStoragePath(coordPath)); coordProps.put(OozieClient.USER_NAME, CurrentUser.getUser()); coordProps.setProperty(AbstractWorkflowEngine.NAME_NODE, ClusterHelper.getStorageUrl(cluster)); if (EntityUtil.isTableStorageType(cluster, entity)) { Tag tag = EntityUtil.getWorkflowNameTag(coordName, entity); if (tag == Tag.REPLICATION) { // todo: kludge send source hcat creds for coord dependency check to pass String srcClusterName = EntityUtil.getWorkflowNameSuffix(coordName, entity); coordProps.putAll(HiveUtil.getHiveCredentials(ClusterHelper.getCluster(srcClusterName))); } else { coordProps.putAll(HiveUtil.getHiveCredentials(cluster)); } } coord.setConfiguration(getConfig(coordProps)); bundle.getCoordinator().add(coord); } Path marshalPath = marshal(cluster, bundle, buildPath); // write the bundle Properties properties = getProperties(marshalPath, entity.getName()); properties.setProperty(OozieClient.BUNDLE_APP_PATH, getStoragePath(buildPath)); properties.setProperty(AbstractWorkflowEngine.NAME_NODE, ClusterHelper.getStorageUrl(cluster)); //Add libpath String libPath = getOozieLibPath(buildPath); if (StringUtils.isNotBlank(libPath)) { properties.put(OozieClient.LIBPATH, libPath); } return properties; } private String getOozieLibPath(final Path buildPath) { String path = getLibPath(buildPath); if (StringUtils.isBlank(path)) { return null; } StringBuilder storageLibPaths = new StringBuilder(); String[] libPaths = path.split(EntityUtil.WF_LIB_SEPARATOR); for (String libPath : libPaths) { String tempPath = getStoragePath(libPath); if (StringUtils.isNotBlank(tempPath)) { if (StringUtils.isNotBlank(storageLibPaths)) { storageLibPaths.append(EntityUtil.WF_LIB_SEPARATOR); } storageLibPaths.append(tempPath); } } return StringUtils.isBlank(storageLibPaths) ? null : storageLibPaths.toString(); } protected CONFIGURATION getConfig(Properties props) { CONFIGURATION conf = new CONFIGURATION(); for (Entry<Object, Object> prop : props.entrySet()) { Property confProp = new Property(); confProp.setName((String) prop.getKey()); confProp.setValue((String) prop.getValue()); conf.getProperty().add(confProp); } return conf; } protected Path marshal(Cluster cluster, BUNDLEAPP bundle, Path outPath) throws FalconException { return marshal(cluster, new org.apache.falcon.oozie.bundle.ObjectFactory().createBundleApp(bundle), OozieUtils.BUNDLE_JAXB_CONTEXT, new Path(outPath, "bundle.xml")); } //Used by coordinator builders to return multiple coords //TODO Can avoid separate interface that returns list by building at lifecycle level protected abstract List<Properties> buildCoords(Cluster cluster, Path bundlePath) throws FalconException; public static BUNDLEAPP unmarshal(Cluster cluster, Path path) throws FalconException { try { FileSystem fs = HadoopClientFactory.get().createProxiedFileSystem( path.toUri(), ClusterHelper.getConfiguration(cluster)); Unmarshaller unmarshaller = OozieUtils.BUNDLE_JAXB_CONTEXT.createUnmarshaller(); @SuppressWarnings("unchecked") JAXBElement<BUNDLEAPP> jaxbElement = unmarshaller.unmarshal(new StreamSource(fs.open(path)), BUNDLEAPP.class); return jaxbElement.getValue(); } catch (JAXBException e) { throw new FalconException(e); } catch (IOException e) { throw new FalconException(e); } } public abstract String getLibPath(Path buildPath); }