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 */
018package org.apache.hadoop.hbase;
019
020import static org.junit.jupiter.api.Assertions.assertEquals;
021import static org.junit.jupiter.api.Assertions.assertFalse;
022import static org.junit.jupiter.api.Assertions.assertTrue;
023
024import java.io.IOException;
025import java.io.InputStream;
026import java.net.URL;
027import org.apache.commons.io.IOUtils;
028import org.apache.hadoop.hbase.client.Admin;
029import org.apache.hadoop.hbase.master.HMaster;
030import org.apache.hadoop.hbase.testclassification.MediumTests;
031import org.apache.hadoop.hbase.testclassification.MiscTests;
032import org.apache.hadoop.hbase.util.Bytes;
033import org.junit.jupiter.api.AfterAll;
034import org.junit.jupiter.api.BeforeAll;
035import org.junit.jupiter.api.Tag;
036import org.junit.jupiter.api.Test;
037import org.junit.jupiter.api.TestInfo;
038import org.slf4j.Logger;
039import org.slf4j.LoggerFactory;
040
041/**
042 * Testing, info servers are disabled. This test enables then and checks that they serve pages.
043 */
044@Tag(MiscTests.TAG)
045@Tag(MediumTests.TAG)
046public class TestInfoServers {
047
048  private static final Logger LOG = LoggerFactory.getLogger(TestInfoServers.class);
049  private final static HBaseTestingUtil UTIL = new HBaseTestingUtil();
050
051  @BeforeAll
052  public static void beforeClass() throws Exception {
053    // The info servers do not run in tests by default.
054    // Set them to ephemeral ports so they will start
055    UTIL.getConfiguration().setInt(HConstants.MASTER_INFO_PORT, 0);
056    UTIL.getConfiguration().setInt(HConstants.REGIONSERVER_INFO_PORT, 0);
057
058    // We need to make sure that the server can be started as read only.
059    UTIL.getConfiguration().setBoolean("hbase.master.ui.readonly", true);
060    UTIL.startMiniCluster();
061    if (!UTIL.getHBaseCluster().waitForActiveAndReadyMaster(30000)) {
062      throw new RuntimeException("Active master not ready");
063    }
064  }
065
066  @AfterAll
067  public static void afterClass() throws Exception {
068    UTIL.shutdownMiniCluster();
069  }
070
071  @Test
072  public void testGetMasterInfoPort() throws Exception {
073    try (Admin admin = UTIL.getAdmin()) {
074      assertEquals(UTIL.getHBaseCluster().getMaster().getInfoServer().getPort(),
075        admin.getMasterInfoPort());
076    }
077  }
078
079  /**
080   * Ensure when we go to top level index pages that we get redirected to an info-server specific
081   * status page.
082   */
083  @Test
084  public void testInfoServersRedirect() throws Exception {
085    // give the cluster time to start up
086    UTIL.getConnection().getTable(TableName.META_TABLE_NAME).close();
087    int port = UTIL.getHBaseCluster().getMaster().getInfoServer().getPort();
088    assertContainsContent(new URL("http://localhost:" + port + "/index.html"), "master.jsp");
089    assertContainsContent(new URL("http://localhost:" + port + "/master-status"), "master.jsp");
090    port = UTIL.getHBaseCluster().getRegionServerThreads().get(0).getRegionServer().getInfoServer()
091      .getPort();
092    assertContainsContent(new URL("http://localhost:" + port + "/index.html"), "regionserver.jsp");
093    assertContainsContent(new URL("http://localhost:" + port + "/rs-status"), "regionserver.jsp");
094  }
095
096  /**
097   * Test that the status pages in the minicluster load properly. This is somewhat a duplicate of
098   * TestRSStatusServlet and TestMasterStatusServlet, but those are true unit tests whereas this
099   * uses a cluster.
100   */
101  @Test
102  public void testInfoServersStatusPages() throws Exception {
103    int port = UTIL.getHBaseCluster().getMaster().getInfoServer().getPort();
104    assertContainsContent(new URL("http://localhost:" + port + "/master.jsp"), "meta");
105    port = UTIL.getHBaseCluster().getRegionServerThreads().get(0).getRegionServer().getInfoServer()
106      .getPort();
107    assertContainsContent(new URL("http://localhost:" + port + "/regionserver.jsp"), "meta");
108  }
109
110  @Test
111  public void testMasterServerReadOnly(TestInfo testInfo) throws Exception {
112    final TableName tableName = TableName.valueOf(testInfo.getTestMethod().get().getName());
113    byte[] cf = Bytes.toBytes("d");
114    UTIL.createTable(tableName, cf);
115    UTIL.waitTableAvailable(tableName);
116    HMaster master = UTIL.getHBaseCluster().getMaster();
117    int port = master.getRegionServerInfoPort(master.getServerName());
118    assertDoesNotContainContent(
119      new URL("http://localhost:" + port + "/table.jsp?name=" + tableName + "&action=split&key="),
120      "Table action request accepted");
121    assertDoesNotContainContent(
122      new URL("http://localhost:" + port + "/table.jsp?name=" + tableName), "Actions:");
123  }
124
125  private void assertContainsContent(final URL u, final String expected) throws IOException {
126    LOG.info("Testing " + u.toString() + " has " + expected);
127    String content = getUrlContent(u);
128    assertTrue(content.contains(expected), "expected=" + expected + ", content=" + content);
129  }
130
131  private void assertDoesNotContainContent(final URL u, final String expected) throws IOException {
132    LOG.info("Testing " + u.toString() + " does not have " + expected);
133    String content = getUrlContent(u);
134    assertFalse(content.contains(expected),
135      "Does Not Contain =" + expected + ", content=" + content);
136  }
137
138  private String getUrlContent(URL u) throws IOException {
139    java.net.URLConnection c = u.openConnection();
140    c.setConnectTimeout(20000);
141    c.setReadTimeout(20000);
142    c.connect();
143    try (InputStream in = c.getInputStream()) {
144      return IOUtils.toString(in, HConstants.UTF8_ENCODING);
145    }
146  }
147}