001/**
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *      http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018
019package org.apache.oozie.action.hadoop;
020
021import java.io.IOException;
022import java.net.URI;
023import java.net.URISyntaxException;
024
025import org.apache.hadoop.conf.Configuration;
026import org.apache.hadoop.fs.FileStatus;
027import org.apache.hadoop.fs.FileSystem;
028import org.apache.hadoop.fs.Path;
029import org.apache.hadoop.fs.PathFilter;
030import org.apache.oozie.DagELFunctions;
031import org.apache.oozie.action.ActionExecutorException;
032import org.apache.oozie.client.WorkflowJob;
033import org.apache.oozie.service.ConfigurationService;
034import org.apache.oozie.service.HadoopAccessorException;
035import org.apache.oozie.service.Services;
036import org.apache.oozie.service.HadoopAccessorService;
037
038/**
039 * EL function for fs action executor.
040 */
041public class FsELFunctions {
042
043    private static FileSystem getFileSystem(URI uri) throws HadoopAccessorException {
044        WorkflowJob workflow = DagELFunctions.getWorkflow();
045        String user = workflow.getUser();
046        HadoopAccessorService has = Services.get().get(HadoopAccessorService.class);
047        Configuration conf = has.createConfiguration(uri.getAuthority());
048        return has.createFileSystem(user, uri, conf);
049    }
050
051    /**
052     * Get file status.
053     *
054     * @param pathUri fs path uri
055     * @return file status
056     * @throws URISyntaxException
057     * @throws IOException
058     * @throws Exception
059     */
060    private static FileStatus getFileStatus(String pathUri) throws Exception {
061        URI uri = new URI(pathUri);
062        String path = uri.getPath();
063        FileSystem fs = getFileSystem(uri);
064        Path p = new Path(path);
065        return fs.exists(p) ? fs.getFileStatus(p) : null;
066    }
067
068    /**
069     * Return if a path exists.
070     *
071     * @param pathUri file system path uri.
072     * @return <code>true</code> if the path exists, <code>false</code> if it does not.
073     * @throws Exception
074     */
075    public static boolean fs_exists(String pathUri) throws Exception {
076        Path path = new Path(pathUri);
077        FileSystem fs = getFileSystem(path.toUri());
078        FileStatus[] pathArr;
079        try {
080            pathArr = fs.globStatus(path, new FSPathFilter());
081        }
082        catch (ReachingGlobMaxException e) {
083            throw new ActionExecutorException(ActionExecutorException.ErrorType.ERROR, "FS013",
084                    "too many globbed files/dirs to do FS operation");
085        }
086        return (pathArr != null && pathArr.length > 0);
087    }
088
089    /**
090     * Return if a path is a directory.
091     *
092     * @param pathUri fs path uri.
093     * @return <code>true</code> if the path exists and it is a directory, <code>false</code> otherwise.
094     * @throws Exception
095     */
096    public static boolean fs_isDir(String pathUri) throws Exception {
097        boolean isDir = false;
098        FileStatus fileStatus = getFileStatus(pathUri);
099        if (fileStatus != null) {
100            isDir = fileStatus.isDirectory();
101        }
102        return isDir;
103    }
104
105    /**
106     * Return the len of a file.
107     *
108     * @param pathUri file system path uri.
109     * @return the file len in bytes, -1 if the file does not exist or if it is a directory.
110     * @throws Exception
111     */
112    public static long fs_fileSize(String pathUri) throws Exception {
113        long len = -1;
114        FileStatus fileStatus = getFileStatus(pathUri);
115        if (fileStatus != null) {
116            len = fileStatus.getLen();
117        }
118        return len;
119    }
120
121    /**
122     * Return the size of all files in the directory, it is not recursive.
123     *
124     * @param pathUri file system path uri.
125     * @return the size of all files in the directory, -1 if the directory does not exist or if it is a file.
126     * @throws Exception
127     */
128    public static long fs_dirSize(String pathUri) throws Exception {
129        URI uri = new URI(pathUri);
130        String path = uri.getPath();
131        long size = -1;
132        try {
133            FileSystem fs = getFileSystem(uri);
134            Path p = new Path(path);
135            if (fs.exists(p) && !fs.isFile(p)) {
136                FileStatus[] stati = fs.listStatus(p);
137                size = 0;
138                if (stati != null) {
139                    for (FileStatus status : stati) {
140                        if (!status.isDirectory()) {
141                            size += status.getLen();
142                        }
143                    }
144                }
145            }
146        }
147        catch (Exception ex) {
148            throw new RuntimeException(ex);
149        }
150        return size;
151    }
152
153    /**
154     * Return the file block size in bytes.
155     *
156     * @param pathUri file system path uri.
157     * @return the block size of the file in bytes, -1 if the file does not exist or if it is a directory.
158     * @throws Exception
159     */
160    public static long fs_blockSize(String pathUri) throws Exception {
161        long blockSize = -1;
162        FileStatus fileStatus = getFileStatus(pathUri);
163        if (fileStatus != null) {
164            blockSize = fileStatus.getBlockSize();
165        }
166        return blockSize;
167    }
168
169    static class FSPathFilter implements PathFilter {
170        int count = 0;
171        int globMax = Integer.MAX_VALUE;
172        public FSPathFilter() {
173            globMax = ConfigurationService.getInt(LauncherAMUtils.CONF_OOZIE_ACTION_FS_GLOB_MAX);
174        }
175        @Override
176        public boolean accept(Path p) {
177            count++;
178            if(count > globMax) {
179                throw new ReachingGlobMaxException();
180            }
181            return true;
182        }
183    }
184
185    /**
186     * ReachingGlobMaxException thrown when globbed file count exceeds the limit
187     */
188    static class ReachingGlobMaxException extends RuntimeException {
189    }
190
191}