gobblin.util.ProxiedFileSystemCache.java Source code

Java tutorial

Introduction

Here is the source code for gobblin.util.ProxiedFileSystemCache.java

Source

/*
 * 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.util;

import java.io.IOException;
import java.net.URI;
import java.util.Properties;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;

import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.NonNull;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.security.token.Token;

import gobblin.configuration.ConfigurationKeys;
import gobblin.configuration.State;

/**
 * A cache for storing a mapping between Hadoop users and user {@link FileSystem} objects.
 *
 * <p>
 *  This classes uses Guava's {@link Cache} for storing the user to {@link FileSystem} mapping, and creates the
 *  {@link FileSystem}s using the {@link ProxiedFileSystemUtils} class.
 * </p>
 *
 * @see Cache
 * @see ProxiedFileSystemUtils
 */
public class ProxiedFileSystemCache {

    private static final String KEY_SEPARATOR = ";";
    private static final String RATE_CONTROLLED_TOKEN = "RateControlled";
    private static final int DEFAULT_MAX_CACHE_SIZE = 1000;

    private static final Cache<String, FileSystem> USER_NAME_TO_FILESYSTEM_CACHE = CacheBuilder.newBuilder()
            .maximumSize(DEFAULT_MAX_CACHE_SIZE).build();

    /**
     * Gets a {@link FileSystem} that can perform any operations allowed by the specified userNameToProxyAs.
     *
     * @param userNameToProxyAs The name of the user the super user should proxy as
     * @param properties {@link java.util.Properties} containing initialization properties.
     * @param fsURI The {@link URI} for the {@link FileSystem} that should be created.
     * @return a {@link FileSystem} that can execute commands on behalf of the specified userNameToProxyAs
     * @throws IOException
     * @deprecated use {@link #fromProperties}
     */
    @Deprecated
    public static FileSystem getProxiedFileSystem(@NonNull final String userNameToProxyAs, Properties properties,
            URI fsURI) throws IOException {
        return getProxiedFileSystem(userNameToProxyAs, properties, fsURI, new Configuration());
    }

    /**
     * Gets a {@link FileSystem} that can perform any operations allowed by the specified userNameToProxyAs.
     *
     * @param userNameToProxyAs The name of the user the super user should proxy as
     * @param properties {@link java.util.Properties} containing initialization properties.
     * @param conf The {@link Configuration} for the {@link FileSystem} that should be created.
     * @return a {@link FileSystem} that can execute commands on behalf of the specified userNameToProxyAs
     * @throws IOException
     * @deprecated use {@link #fromProperties}
     */
    @Deprecated
    public static FileSystem getProxiedFileSystem(@NonNull final String userNameToProxyAs, Properties properties,
            Configuration conf) throws IOException {
        return getProxiedFileSystem(userNameToProxyAs, properties, FileSystem.getDefaultUri(conf), conf);
    }

    /**
     * Gets a {@link FileSystem} that can perform any operations allowed by the specified userNameToProxyAs.
     *
     * @param userNameToProxyAs The name of the user the super user should proxy as
     * @param properties {@link java.util.Properties} containing initialization properties.
     * @param fsURI The {@link URI} for the {@link FileSystem} that should be created.
     * @param configuration The {@link Configuration} for the {@link FileSystem} that should be created.
     * @return a {@link FileSystem} that can execute commands on behalf of the specified userNameToProxyAs
     * @throws IOException
     * @deprecated Use {@link #fromProperties}
     */
    @Deprecated
    public static FileSystem getProxiedFileSystem(@NonNull final String userNameToProxyAs,
            final Properties properties, final URI fsURI, final Configuration configuration) throws IOException {
        return getProxiedFileSystem(userNameToProxyAs, properties, fsURI, configuration, null);
    }

    /**
     * Gets a {@link FileSystem} that can perform any operations allowed by the specified userNameToProxyAs.
     *
     * @param userNameToProxyAs The name of the user the super user should proxy as
     * @param properties {@link java.util.Properties} containing initialization properties.
     * @param fsURI The {@link URI} for the {@link FileSystem} that should be created.
     * @param configuration The {@link Configuration} for the {@link FileSystem} that should be created.
     * @param referenceFS reference {@link FileSystem}. Used to replicate certain decorators of the reference FS:
     *                    {@link RateControlledFileSystem}.
     * @return a {@link FileSystem} that can execute commands on behalf of the specified userNameToProxyAs
     * @throws IOException
     */
    @Builder(builderClassName = "ProxiedFileSystemFromProperties", builderMethodName = "fromProperties")
    private static FileSystem getProxiedFileSystem(@NonNull String userNameToProxyAs, Properties properties,
            URI fsURI, Configuration configuration, FileSystem referenceFS) throws IOException {
        Preconditions.checkNotNull(userNameToProxyAs, "Must provide a user name to proxy as.");
        Preconditions.checkNotNull(properties, "Properties is a mandatory field for proxiedFileSystem generation.");
        URI actualURI = resolveUri(fsURI, configuration, referenceFS);
        Configuration actualConfiguration = resolveConfiguration(configuration, referenceFS);

        try {
            return USER_NAME_TO_FILESYSTEM_CACHE.get(getFileSystemKey(actualURI, userNameToProxyAs, referenceFS),
                    new CreateProxiedFileSystemFromProperties(userNameToProxyAs, properties, actualURI,
                            actualConfiguration, referenceFS));
        } catch (ExecutionException ee) {
            throw new IOException("Failed to get proxied file system for user " + userNameToProxyAs, ee);
        }
    }

    /**
     * Cached version of {@link ProxiedFileSystemUtils#createProxiedFileSystemUsingKeytab(State, URI, Configuration)}.
     * @deprecated use {@link #fromKeytab}.
     */
    @Deprecated
    public static FileSystem getProxiedFileSystemUsingKeytab(State state, URI fsURI, Configuration conf)
            throws ExecutionException {
        Preconditions.checkArgument(state.contains(ConfigurationKeys.FS_PROXY_AS_USER_NAME));
        Preconditions.checkArgument(state.contains(ConfigurationKeys.SUPER_USER_NAME_TO_PROXY_AS_OTHERS));
        Preconditions.checkArgument(state.contains(ConfigurationKeys.SUPER_USER_KEY_TAB_LOCATION));

        return getProxiedFileSystemUsingKeytab(state.getProp(ConfigurationKeys.FS_PROXY_AS_USER_NAME),
                state.getProp(ConfigurationKeys.SUPER_USER_NAME_TO_PROXY_AS_OTHERS),
                new Path(state.getProp(ConfigurationKeys.SUPER_USER_KEY_TAB_LOCATION)), fsURI, conf);
    }

    /**
     * Cached version of {@link ProxiedFileSystemUtils#createProxiedFileSystemUsingKeytab(String, String, Path, URI, Configuration)}.
     * @deprecated use {@link #fromKeytab}.
     */
    @Deprecated
    public static FileSystem getProxiedFileSystemUsingKeytab(@NonNull final String userNameToProxyAs,
            final String superUserName, final Path superUserKeytabLocation, final URI fsURI,
            final Configuration conf) throws ExecutionException {
        try {
            return getProxiedFileSystemUsingKeytab(userNameToProxyAs, superUserName, superUserKeytabLocation, fsURI,
                    conf, null);
        } catch (IOException ioe) {
            throw new ExecutionException(ioe);
        }
    }

    /**
     * Cached version of {@link ProxiedFileSystemUtils#createProxiedFileSystemUsingKeytab(String, String, Path, URI, Configuration)}.
     */
    @Builder(builderClassName = "ProxiedFileSystemFromKeytab", builderMethodName = "fromKeytab")
    private static FileSystem getProxiedFileSystemUsingKeytab(@NonNull final String userNameToProxyAs,
            final String superUserName, final Path superUserKeytabLocation, final URI fsURI,
            final Configuration conf, FileSystem referenceFS) throws IOException, ExecutionException {
        Preconditions.checkNotNull(userNameToProxyAs, "Must provide a user name to proxy as.");
        Preconditions.checkNotNull(superUserName, "Must provide a super user name.");
        Preconditions.checkNotNull(superUserKeytabLocation, "Must provide a keytab location.");
        URI actualURI = resolveUri(fsURI, conf, referenceFS);
        Configuration actualConfiguration = resolveConfiguration(conf, referenceFS);

        return USER_NAME_TO_FILESYSTEM_CACHE.get(getFileSystemKey(actualURI, userNameToProxyAs, referenceFS),
                new CreateProxiedFileSystemFromKeytab(userNameToProxyAs, superUserName, superUserKeytabLocation,
                        actualURI, actualConfiguration, referenceFS));
    }

    /**
     * Cached version of {@link ProxiedFileSystemUtils#createProxiedFileSystemUsingToken(String, Token, URI, Configuration)}.
     * @deprecated use {@link #fromToken}.
     */
    @Deprecated
    public static FileSystem getProxiedFileSystemUsingToken(@NonNull final String userNameToProxyAs,
            final Token<?> userNameToken, final URI fsURI, final Configuration conf) throws ExecutionException {
        try {
            return getProxiedFileSystemUsingToken(userNameToProxyAs, userNameToken, fsURI, conf, null);
        } catch (IOException ioe) {
            throw new ExecutionException(ioe);
        }
    }

    /**
     * Cached version of {@link ProxiedFileSystemUtils#createProxiedFileSystemUsingToken(String, Token, URI, Configuration)}.
     */
    @Builder(builderClassName = "ProxiedFileSystemFromToken", builderMethodName = "fromToken")
    private static FileSystem getProxiedFileSystemUsingToken(@NonNull String userNameToProxyAs,
            Token<?> userNameToken, URI fsURI, Configuration conf, FileSystem referenceFS)
            throws IOException, ExecutionException {
        Preconditions.checkNotNull(userNameToProxyAs, "Must provide a user name to proxy as.");
        Preconditions.checkNotNull(userNameToken, "Must provide token for user to proxy.");
        URI actualURI = resolveUri(fsURI, conf, referenceFS);
        Configuration actualConfiguration = resolveConfiguration(conf, referenceFS);

        return USER_NAME_TO_FILESYSTEM_CACHE.get(getFileSystemKey(actualURI, userNameToProxyAs, referenceFS),
                new CreateProxiedFileSystemFromToken(userNameToProxyAs, userNameToken, actualURI,
                        actualConfiguration, referenceFS));
    }

    @AllArgsConstructor
    private static class CreateProxiedFileSystemFromProperties implements Callable<FileSystem> {
        @NonNull
        private final String userNameToProxyAs;
        @NonNull
        private final Properties properties;
        @NonNull
        private final URI uri;
        @NonNull
        private final Configuration configuration;
        private final FileSystem referenceFS;

        @Override
        public FileSystem call() throws Exception {
            FileSystem fs = ProxiedFileSystemUtils.createProxiedFileSystem(this.userNameToProxyAs, this.properties,
                    this.uri, this.configuration);
            if (this.referenceFS != null) {
                return decorateFilesystemFromReferenceFS(fs, this.referenceFS);
            }
            return fs;
        }
    }

    @AllArgsConstructor
    private static class CreateProxiedFileSystemFromKeytab implements Callable<FileSystem> {
        @NonNull
        private final String userNameToProxyAs;
        @NonNull
        private final String superUser;
        @NonNull
        private final Path keytabLocation;
        @NonNull
        private final URI uri;
        @NonNull
        private final Configuration configuration;
        private final FileSystem referenceFS;

        @Override
        public FileSystem call() throws Exception {
            FileSystem fs = ProxiedFileSystemUtils.createProxiedFileSystemUsingKeytab(this.userNameToProxyAs,
                    this.superUser, this.keytabLocation, this.uri, this.configuration);
            if (this.referenceFS != null) {
                return decorateFilesystemFromReferenceFS(fs, this.referenceFS);
            }
            return fs;
        }
    }

    @AllArgsConstructor
    private static class CreateProxiedFileSystemFromToken implements Callable<FileSystem> {
        @NonNull
        private final String userNameToProxyAs;
        @NonNull
        private final Token<?> userNameToken;
        @NonNull
        private final URI uri;
        @NonNull
        private final Configuration configuration;
        private final FileSystem referenceFS;

        @Override
        public FileSystem call() throws Exception {
            FileSystem fs = ProxiedFileSystemUtils.createProxiedFileSystemUsingToken(this.userNameToProxyAs,
                    this.userNameToken, this.uri, this.configuration);
            if (this.referenceFS != null) {
                return decorateFilesystemFromReferenceFS(fs, this.referenceFS);
            }
            return fs;
        }
    }

    private static URI resolveUri(URI uri, Configuration configuration, FileSystem fileSystem) throws IOException {
        if (uri != null) {
            return uri;
        }
        if (fileSystem != null) {
            return fileSystem.getUri();
        }
        if (configuration != null) {
            return FileSystem.getDefaultUri(configuration);
        }
        throw new IOException("FileSystem URI could not be determined from available inputs.");
    }

    private static Configuration resolveConfiguration(Configuration configuration, FileSystem fileSystem)
            throws IOException {
        if (configuration != null) {
            return configuration;
        }
        if (fileSystem != null) {
            return fileSystem.getConf();
        }
        throw new IOException("FileSystem configuration could not be determined from available inputs.");
    }

    private static String getFileSystemKey(URI uri, String user, FileSystem referenceFS) {

        StringBuilder keyBuilder = new StringBuilder();
        keyBuilder.append(uri.toString());
        keyBuilder.append(KEY_SEPARATOR);
        keyBuilder.append(user);

        if (referenceFS != null && RateControlledFileSystem.getRateIfRateControlled(referenceFS).isPresent()) {
            keyBuilder.append(KEY_SEPARATOR);
            keyBuilder.append(RATE_CONTROLLED_TOKEN);
        }

        return keyBuilder.toString();
    }

    private static FileSystem decorateFilesystemFromReferenceFS(FileSystem newFS, FileSystem referenceFS) {
        FileSystem decoratedFs = newFS;

        Optional<Long> decoratedFSRateOpt = RateControlledFileSystem.getRateIfRateControlled(decoratedFs);
        if (!decoratedFSRateOpt.isPresent()) {
            Optional<Long> referenceRateOpt = RateControlledFileSystem.getRateIfRateControlled(referenceFS);
            if (referenceRateOpt.isPresent()) {
                decoratedFs = new RateControlledFileSystem(decoratedFs, referenceRateOpt.get());
            }
        }

        return decoratedFs;
    }
}