gobblin.yarn.YarnSecurityManagerTest.java Source code

Java tutorial

Introduction

Here is the source code for gobblin.yarn.YarnSecurityManagerTest.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.yarn;

import java.io.IOException;
import java.net.URL;
import java.util.Collection;

import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.RetryOneTime;
import org.apache.curator.test.TestingServer;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.security.UserGroupInformation;
import org.apache.hadoop.security.token.Token;
import org.apache.helix.HelixManager;
import org.apache.helix.HelixManagerFactory;
import org.apache.helix.InstanceType;
import org.mockito.Mockito;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testng.Assert;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;

import com.google.common.base.Function;
import com.google.common.eventbus.EventBus;
import com.google.common.io.Closer;
import com.typesafe.config.Config;
import com.typesafe.config.ConfigFactory;
import com.typesafe.config.ConfigValueFactory;

import gobblin.cluster.GobblinClusterConfigurationKeys;
import gobblin.cluster.HelixUtils;
import gobblin.cluster.TestHelper;
import gobblin.testing.AssertWithBackoff;

/**
 * Unit tests for {@link YarnAppSecurityManager} and {@link YarnContainerSecurityManager}.
 *
 * <p>
 *   This class tests {@link YarnAppSecurityManager} and {@link YarnContainerSecurityManager} together
 *   as it is more convenient to test both here where all dependencies are setup between the two.
 * </p>
 *
 * <p>
 *   This class uses a {@link TestingServer} as an embedded ZooKeeper server for testing. The Curator
 *   framework is used to provide a ZooKeeper client. This class also uses a {@link HelixManager} as
 *   being required by {@link YarnAppSecurityManager}. The local file system as returned by
 *   {@link FileSystem#getLocal(Configuration)} is used for writing the testing delegation token, which
 *   is acquired by mocking the method {@link FileSystem#getDelegationToken(String)} on the local
 *   {@link FileSystem} instance.
 * </p>
 * @author Yinan Li
 */
@Test(groups = { "gobblin.yarn" })
public class YarnSecurityManagerTest {
    final Logger LOG = LoggerFactory.getLogger(YarnSecurityManagerTest.class);

    private CuratorFramework curatorFramework;

    private HelixManager helixManager;

    private Configuration configuration;
    private FileSystem localFs;
    private Path baseDir;
    private Path tokenFilePath;
    private Token<?> token;

    private YarnAppSecurityManager yarnAppSecurityManager;
    private YarnContainerSecurityManager yarnContainerSecurityManager;

    private final Closer closer = Closer.create();

    @BeforeClass
    public void setUp() throws Exception {
        // Use a random ZK port
        TestingServer testingZKServer = this.closer.register(new TestingServer(-1));
        LOG.info("Testing ZK Server listening on: " + testingZKServer.getConnectString());

        this.curatorFramework = this.closer.register(
                CuratorFrameworkFactory.newClient(testingZKServer.getConnectString(), new RetryOneTime(2000)));
        this.curatorFramework.start();

        URL url = YarnSecurityManagerTest.class.getClassLoader()
                .getResource(YarnSecurityManagerTest.class.getSimpleName() + ".conf");
        Assert.assertNotNull(url, "Could not find resource " + url);

        Config config = ConfigFactory.parseURL(url).withValue("gobblin.cluster.zk.connection.string",
                ConfigValueFactory.fromAnyRef(testingZKServer.getConnectString())).resolve();

        String zkConnectingString = config.getString(GobblinClusterConfigurationKeys.ZK_CONNECTION_STRING_KEY);
        String helixClusterName = config.getString(GobblinClusterConfigurationKeys.HELIX_CLUSTER_NAME_KEY);

        HelixUtils.createGobblinHelixCluster(zkConnectingString, helixClusterName);

        this.helixManager = HelixManagerFactory.getZKHelixManager(helixClusterName,
                TestHelper.TEST_HELIX_INSTANCE_NAME, InstanceType.SPECTATOR, zkConnectingString);
        this.helixManager.connect();

        this.configuration = new Configuration();
        this.localFs = Mockito.spy(FileSystem.getLocal(this.configuration));

        this.token = new Token<>();
        this.token.setKind(new Text("test"));
        this.token.setService(new Text("test"));
        Mockito.<Token<?>>when(
                this.localFs.getDelegationToken(UserGroupInformation.getLoginUser().getShortUserName()))
                .thenReturn(this.token);

        this.baseDir = new Path(YarnSecurityManagerTest.class.getSimpleName());
        this.tokenFilePath = new Path(this.baseDir, GobblinYarnConfigurationKeys.TOKEN_FILE_NAME);
        this.yarnAppSecurityManager = new YarnAppSecurityManager(config, this.helixManager, this.localFs,
                this.tokenFilePath);
        this.yarnContainerSecurityManager = new YarnContainerSecurityManager(config, this.localFs, new EventBus());
    }

    @Test
    public void testGetNewDelegationTokenForLoginUser() throws IOException {
        this.yarnAppSecurityManager.getNewDelegationTokenForLoginUser();
    }

    @Test(dependsOnMethods = "testGetNewDelegationTokenForLoginUser")
    public void testWriteDelegationTokenToFile() throws IOException {
        this.yarnAppSecurityManager.writeDelegationTokenToFile();
        Assert.assertTrue(this.localFs.exists(this.tokenFilePath));
        assertToken(YarnHelixUtils.readTokensFromFile(this.tokenFilePath, this.configuration));
    }

    static class GetControllerMessageNumFunc implements Function<Void, Integer> {
        private final CuratorFramework curatorFramework;
        private final String testName;

        public GetControllerMessageNumFunc(String testName, CuratorFramework curatorFramework) {
            this.curatorFramework = curatorFramework;
            this.testName = testName;
        }

        @Override
        public Integer apply(Void input) {
            try {
                return this.curatorFramework.getChildren()
                        .forPath(String.format("/%s/CONTROLLER/MESSAGES", this.testName)).size();
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }

    }

    @Test
    public void testSendTokenFileUpdatedMessage() throws Exception {
        Logger log = LoggerFactory.getLogger("testSendTokenFileUpdatedMessage");
        this.yarnAppSecurityManager.sendTokenFileUpdatedMessage(InstanceType.CONTROLLER);
        Assert.assertEquals(this.curatorFramework.checkExists()
                .forPath(String.format("/%s/CONTROLLER/MESSAGES", YarnSecurityManagerTest.class.getSimpleName()))
                .getVersion(), 0);
        AssertWithBackoff.create().logger(log).timeoutMs(20000)
                .assertEquals(new GetControllerMessageNumFunc(YarnSecurityManagerTest.class.getSimpleName(),
                        this.curatorFramework), 1, "1 controller message queued");
    }

    @Test(dependsOnMethods = "testWriteDelegationTokenToFile")
    public void testYarnContainerSecurityManager() throws IOException {
        Collection<Token<?>> tokens = this.yarnContainerSecurityManager.readDelegationTokens(this.tokenFilePath);
        assertToken(tokens);
        this.yarnContainerSecurityManager.addDelegationTokens(tokens);
        assertToken(UserGroupInformation.getCurrentUser().getTokens());
    }

    @AfterClass
    public void tearDown() throws IOException {
        try {
            if (this.helixManager.isConnected()) {
                this.helixManager.disconnect();
            }
            this.localFs.delete(this.baseDir, true);
        } catch (Throwable t) {
            throw this.closer.rethrow(t);
        } finally {
            this.closer.close();
        }
    }

    private void assertToken(Collection<Token<?>> tokens) {
        Assert.assertEquals(tokens.size(), 1);
        Token<?> token = tokens.iterator().next();
        Assert.assertEquals(token, this.token);
    }
}