blob: 44040092dab56b0682a30e91d5a475d70b7dcb60 [file] [log] [blame]
// 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.impala.analysis;
import java.io.IOException;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.fs.permission.FsAction;
import org.apache.impala.authorization.Privilege;
import org.apache.impala.common.AnalysisException;
import org.apache.impala.common.FileSystemUtil;
import org.apache.impala.util.FsPermissionChecker;
import com.google.common.base.Preconditions;
/**
* Represents a Hadoop FileSystem URI in a SQL statement.
*/
public class HdfsUri {
private final String location_;
// Set during analysis
private Path uriPath_;
public HdfsUri(String location) {
Preconditions.checkNotNull(location);
this.location_ = location.trim();
}
public Path getPath() {
Preconditions.checkNotNull(uriPath_);
return uriPath_;
}
public void analyze(Analyzer analyzer, Privilege privilege)
throws AnalysisException {
analyze(analyzer, privilege, FsAction.NONE, /*registerPrivReq*/ true,
/*pathMustExist*/ false);
}
public void analyze(Analyzer analyzer, Privilege privilege, FsAction perm)
throws AnalysisException {
analyze(analyzer, privilege, perm, /*pathMustExist*/ true,
/*pathMustExist*/ false);
}
public void analyze(Analyzer analyzer, Privilege privilege, boolean registerPrivReq)
throws AnalysisException {
analyze(
analyzer, privilege, FsAction.NONE, registerPrivReq, /*pathMustExist*/ false);
}
/**
* Analyzes the URI.
* Optionally check location path permission, issue warning if impala user doesn't
* have sufficient access rights.
* Optionally register a privilege request. Used by GRANT/REVOKE privilege statements.
* If pathMustExist is true and the path does not exist, AnalysisException is thrown.
*/
public void analyze(Analyzer analyzer, Privilege privilege, FsAction perm,
boolean registerPrivReq, boolean pathMustExist) throws AnalysisException {
if (location_.isEmpty()) {
throw new AnalysisException("URI path cannot be empty.");
}
uriPath_ = new Path(location_);
if (!uriPath_.isUriPathAbsolute()) {
throw new AnalysisException("URI path must be absolute: " + uriPath_);
}
uriPath_ = FileSystemUtil.createFullyQualifiedPath(uriPath_);
// Check if parent path exists and if impala is allowed to access it.
Path parentPath = uriPath_.getParent();
try {
FileSystem fs = uriPath_.getFileSystem(FileSystemUtil.getConfiguration());
if (pathMustExist && !fs.exists(uriPath_)) {
throw new AnalysisException(String.format("Path does not exist: %s", uriPath_));
}
boolean parentPathExists = false;
StringBuilder errorMsg = new StringBuilder();
try {
parentPathExists = fs.exists(parentPath);
if (!parentPathExists) {
errorMsg.append("Path does not exist.");
}
} catch (Exception e) {
errorMsg.append(e.getMessage());
}
if (!parentPathExists) {
analyzer.addWarning(String.format("Path '%s' cannot be reached: %s",
parentPath, errorMsg.toString()));
} else if (perm != FsAction.NONE) {
FsPermissionChecker checker = FsPermissionChecker.getInstance();
if (!checker.getPermissions(fs, parentPath).checkPermissions(perm)) {
analyzer.addWarning(String.format(
"Impala does not have %s access to path '%s'",
perm.toString(), parentPath));
}
}
} catch (IOException e) {
throw new AnalysisException(e.getMessage(), e);
}
if (registerPrivReq) {
analyzer.registerPrivReq(builder ->
builder.onUri(uriPath_.toString())
.allOf(privilege)
.build());
}
}
@Override
public String toString() {
// If uriPath is null (this HdfsURI has not been analyzed yet) just return the raw
// location string the caller passed in.
return uriPath_ == null ? location_ : uriPath_.toString();
}
public String getLocation() { return location_; }
}