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.master;
019
020import static org.junit.jupiter.api.Assertions.fail;
021import static org.mockito.Mockito.mock;
022import static org.mockito.Mockito.when;
023
024import java.net.InetAddress;
025import org.apache.hadoop.conf.Configuration;
026import org.apache.hadoop.hbase.ClockOutOfSyncException;
027import org.apache.hadoop.hbase.HBaseConfiguration;
028import org.apache.hadoop.hbase.master.assignment.AssignmentManager;
029import org.apache.hadoop.hbase.master.assignment.RegionStates;
030import org.apache.hadoop.hbase.testclassification.MasterTests;
031import org.apache.hadoop.hbase.testclassification.SmallTests;
032import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
033import org.junit.jupiter.api.Tag;
034import org.junit.jupiter.api.Test;
035import org.slf4j.Logger;
036import org.slf4j.LoggerFactory;
037
038import org.apache.hadoop.hbase.shaded.protobuf.generated.RegionServerStatusProtos.RegionServerStartupRequest;
039
040@Tag(MasterTests.TAG)
041@Tag(SmallTests.TAG)
042public class TestClockSkewDetection {
043
044  private static final Logger LOG = LoggerFactory.getLogger(TestClockSkewDetection.class);
045
046  private static final class DummyMasterServices extends MockNoopMasterServices {
047
048    private final AssignmentManager am;
049
050    public DummyMasterServices(Configuration conf) {
051      super(conf);
052      am = mock(AssignmentManager.class);
053      RegionStates rss = mock(RegionStates.class);
054      when(am.getRegionStates()).thenReturn(rss);
055    }
056
057    @Override
058    public AssignmentManager getAssignmentManager() {
059      return am;
060    }
061  }
062
063  @Test
064  public void testClockSkewDetection() throws Exception {
065    final Configuration conf = HBaseConfiguration.create();
066    ServerManager sm =
067      new ServerManager(new DummyMasterServices(conf), new DummyRegionServerList());
068
069    LOG.debug("regionServerStartup 1");
070    InetAddress ia1 = InetAddress.getLocalHost();
071    RegionServerStartupRequest.Builder request = RegionServerStartupRequest.newBuilder();
072    request.setPort(1234);
073    request.setServerStartCode(-1);
074    request.setServerCurrentTime(EnvironmentEdgeManager.currentTime());
075    sm.regionServerStartup(request.build(), 0, "0.0.0", ia1);
076
077    final Configuration c = HBaseConfiguration.create();
078    long maxSkew = c.getLong("hbase.master.maxclockskew", 30000);
079    long warningSkew = c.getLong("hbase.master.warningclockskew", 1000);
080
081    try {
082      // Master Time > Region Server Time
083      LOG.debug("Test: Master Time > Region Server Time");
084      LOG.debug("regionServerStartup 2");
085      InetAddress ia2 = InetAddress.getLocalHost();
086      request = RegionServerStartupRequest.newBuilder();
087      request.setPort(1235);
088      request.setServerStartCode(-1);
089      request.setServerCurrentTime(EnvironmentEdgeManager.currentTime() - maxSkew * 2);
090      sm.regionServerStartup(request.build(), 0, "0.0.0", ia2);
091      fail("HMaster should have thrown a ClockOutOfSyncException but didn't.");
092    } catch (ClockOutOfSyncException e) {
093      // we want an exception
094      LOG.info("Received expected exception: " + e);
095    }
096
097    try {
098      // Master Time < Region Server Time
099      LOG.debug("Test: Master Time < Region Server Time");
100      LOG.debug("regionServerStartup 3");
101      InetAddress ia3 = InetAddress.getLocalHost();
102      request = RegionServerStartupRequest.newBuilder();
103      request.setPort(1236);
104      request.setServerStartCode(-1);
105      request.setServerCurrentTime(EnvironmentEdgeManager.currentTime() + maxSkew * 2);
106      sm.regionServerStartup(request.build(), 0, "0.0.0", ia3);
107      fail("HMaster should have thrown a ClockOutOfSyncException but didn't.");
108    } catch (ClockOutOfSyncException e) {
109      // we want an exception
110      LOG.info("Received expected exception: " + e);
111    }
112
113    // make sure values above warning threshold but below max threshold don't kill
114    LOG.debug("regionServerStartup 4");
115    InetAddress ia4 = InetAddress.getLocalHost();
116    request = RegionServerStartupRequest.newBuilder();
117    request.setPort(1237);
118    request.setServerStartCode(-1);
119    request.setServerCurrentTime(EnvironmentEdgeManager.currentTime() - warningSkew * 2);
120    sm.regionServerStartup(request.build(), 0, "0.0.0", ia4);
121
122    // make sure values above warning threshold but below max threshold don't kill
123    LOG.debug("regionServerStartup 5");
124    InetAddress ia5 = InetAddress.getLocalHost();
125    request = RegionServerStartupRequest.newBuilder();
126    request.setPort(1238);
127    request.setServerStartCode(-1);
128    request.setServerCurrentTime(EnvironmentEdgeManager.currentTime() + warningSkew * 2);
129    sm.regionServerStartup(request.build(), 0, "0.0.0", ia5);
130  }
131}