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.rsgroup;
019
020import com.google.protobuf.ServiceException;
021import java.io.IOException;
022import java.util.ArrayList;
023import java.util.EnumSet;
024import java.util.List;
025import java.util.Map;
026import java.util.Set;
027import java.util.stream.Collectors;
028import org.apache.hadoop.hbase.ClusterMetrics;
029import org.apache.hadoop.hbase.ServerName;
030import org.apache.hadoop.hbase.TableName;
031import org.apache.hadoop.hbase.TableNotFoundException;
032import org.apache.hadoop.hbase.client.Admin;
033import org.apache.hadoop.hbase.client.BalanceRequest;
034import org.apache.hadoop.hbase.client.BalanceResponse;
035import org.apache.hadoop.hbase.client.Connection;
036import org.apache.hadoop.hbase.net.Address;
037import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
038import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos;
039import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.NameStringPair;
040import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos;
041import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.AddRSGroupRequest;
042import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.GetRSGroupInfoOfServerRequest;
043import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.GetRSGroupInfoOfServerResponse;
044import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.GetRSGroupInfoOfTableRequest;
045import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.GetRSGroupInfoOfTableResponse;
046import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.GetRSGroupInfoRequest;
047import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.GetRSGroupInfoResponse;
048import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.ListRSGroupInfosRequest;
049import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.MoveServersAndTablesRequest;
050import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.MoveServersRequest;
051import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.MoveTablesRequest;
052import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.RSGroupAdminService;
053import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.RemoveRSGroupRequest;
054import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.RemoveServersRequest;
055import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.RenameRSGroupRequest;
056import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.UpdateRSGroupConfigRequest;
057import org.apache.hadoop.hbase.protobuf.generated.RSGroupProtos;
058import org.apache.yetus.audience.InterfaceAudience;
059
060import org.apache.hbase.thirdparty.com.google.common.collect.Sets;
061
062/**
063 * Client used for managing region server group information.
064 */
065@InterfaceAudience.Private
066public class RSGroupAdminClient implements RSGroupAdmin {
067  private RSGroupAdminService.BlockingInterface stub;
068  private Admin admin;
069
070  public RSGroupAdminClient(Connection conn) throws IOException {
071    admin = conn.getAdmin();
072    stub = RSGroupAdminService.newBlockingStub(admin.coprocessorService());
073  }
074
075  @Override
076  public RSGroupInfo getRSGroupInfo(String groupName) throws IOException {
077    try {
078      GetRSGroupInfoResponse resp = stub.getRSGroupInfo(null,
079        GetRSGroupInfoRequest.newBuilder().setRSGroupName(groupName).build());
080      if (resp.hasRSGroupInfo()) {
081        return RSGroupProtobufUtil.toGroupInfo(resp.getRSGroupInfo());
082      }
083      return null;
084    } catch (ServiceException e) {
085      throw ProtobufUtil.handleRemoteException(e);
086    }
087  }
088
089  @Override
090  public RSGroupInfo getRSGroupInfoOfTable(TableName tableName) throws IOException {
091    GetRSGroupInfoOfTableRequest request = GetRSGroupInfoOfTableRequest.newBuilder()
092      .setTableName(ProtobufUtil.toProtoTableName(tableName)).build();
093    try {
094      GetRSGroupInfoOfTableResponse resp = stub.getRSGroupInfoOfTable(null, request);
095      if (resp.hasRSGroupInfo()) {
096        return RSGroupProtobufUtil.toGroupInfo(resp.getRSGroupInfo());
097      }
098      return null;
099    } catch (ServiceException e) {
100      throw ProtobufUtil.handleRemoteException(e);
101    }
102  }
103
104  @Override
105  public void moveServers(Set<Address> servers, String targetGroup) throws IOException {
106    Set<HBaseProtos.ServerName> hostPorts = Sets.newHashSet();
107    for (Address el : servers) {
108      hostPorts.add(HBaseProtos.ServerName.newBuilder().setHostName(el.getHostname())
109        .setPort(el.getPort()).build());
110    }
111    MoveServersRequest request =
112      MoveServersRequest.newBuilder().setTargetGroup(targetGroup).addAllServers(hostPorts).build();
113    try {
114      stub.moveServers(null, request);
115    } catch (ServiceException e) {
116      throw ProtobufUtil.handleRemoteException(e);
117    }
118  }
119
120  @Override
121  public void moveTables(Set<TableName> tables, String targetGroup) throws IOException {
122    MoveTablesRequest.Builder builder = MoveTablesRequest.newBuilder().setTargetGroup(targetGroup);
123    for (TableName tableName : tables) {
124      builder.addTableName(ProtobufUtil.toProtoTableName(tableName));
125      if (!admin.tableExists(tableName)) {
126        throw new TableNotFoundException(tableName);
127      }
128    }
129    try {
130      stub.moveTables(null, builder.build());
131    } catch (ServiceException e) {
132      throw ProtobufUtil.handleRemoteException(e);
133    }
134  }
135
136  @Override
137  public void addRSGroup(String groupName) throws IOException {
138    AddRSGroupRequest request = AddRSGroupRequest.newBuilder().setRSGroupName(groupName).build();
139    try {
140      stub.addRSGroup(null, request);
141    } catch (ServiceException e) {
142      throw ProtobufUtil.handleRemoteException(e);
143    }
144  }
145
146  @Override
147  public void removeRSGroup(String name) throws IOException {
148    RemoveRSGroupRequest request = RemoveRSGroupRequest.newBuilder().setRSGroupName(name).build();
149    try {
150      stub.removeRSGroup(null, request);
151    } catch (ServiceException e) {
152      throw ProtobufUtil.handleRemoteException(e);
153    }
154  }
155
156  @Override
157  public BalanceResponse balanceRSGroup(String groupName, BalanceRequest request)
158    throws IOException {
159    try {
160      RSGroupAdminProtos.BalanceRSGroupRequest req =
161        RSGroupProtobufUtil.createBalanceRSGroupRequest(groupName, request);
162      return RSGroupProtobufUtil.toBalanceResponse(stub.balanceRSGroup(null, req));
163    } catch (ServiceException e) {
164      throw ProtobufUtil.handleRemoteException(e);
165    }
166  }
167
168  @Override
169  public List<RSGroupInfo> listRSGroups() throws IOException {
170    try {
171      List<RSGroupProtos.RSGroupInfo> resp = stub
172        .listRSGroupInfos(null, ListRSGroupInfosRequest.getDefaultInstance()).getRSGroupInfoList();
173      List<RSGroupInfo> result = new ArrayList<>(resp.size());
174      for (RSGroupProtos.RSGroupInfo entry : resp) {
175        result.add(RSGroupProtobufUtil.toGroupInfo(entry));
176      }
177      return result;
178    } catch (ServiceException e) {
179      throw ProtobufUtil.handleRemoteException(e);
180    }
181  }
182
183  @Override
184  public RSGroupInfo getRSGroupOfServer(Address hostPort) throws IOException {
185    GetRSGroupInfoOfServerRequest request =
186      GetRSGroupInfoOfServerRequest.newBuilder().setServer(HBaseProtos.ServerName.newBuilder()
187        .setHostName(hostPort.getHostname()).setPort(hostPort.getPort()).build()).build();
188    try {
189      GetRSGroupInfoOfServerResponse resp = stub.getRSGroupInfoOfServer(null, request);
190      if (resp.hasRSGroupInfo()) {
191        return RSGroupProtobufUtil.toGroupInfo(resp.getRSGroupInfo());
192      }
193      return null;
194    } catch (ServiceException e) {
195      throw ProtobufUtil.handleRemoteException(e);
196    }
197  }
198
199  @Override
200  public void moveServersAndTables(Set<Address> servers, Set<TableName> tables, String targetGroup)
201    throws IOException {
202    MoveServersAndTablesRequest.Builder builder =
203      MoveServersAndTablesRequest.newBuilder().setTargetGroup(targetGroup);
204    for (Address el : servers) {
205      builder.addServers(HBaseProtos.ServerName.newBuilder().setHostName(el.getHostname())
206        .setPort(el.getPort()).build());
207    }
208    for (TableName tableName : tables) {
209      builder.addTableName(ProtobufUtil.toProtoTableName(tableName));
210      if (!admin.tableExists(tableName)) {
211        throw new TableNotFoundException(tableName);
212      }
213    }
214    try {
215      stub.moveServersAndTables(null, builder.build());
216    } catch (ServiceException e) {
217      throw ProtobufUtil.handleRemoteException(e);
218    }
219  }
220
221  @Override
222  public void removeServers(Set<Address> servers) throws IOException {
223    Set<HBaseProtos.ServerName> hostPorts = Sets.newHashSet();
224    for (Address el : servers) {
225      hostPorts.add(HBaseProtos.ServerName.newBuilder().setHostName(el.getHostname())
226        .setPort(el.getPort()).build());
227    }
228    RemoveServersRequest request =
229      RemoveServersRequest.newBuilder().addAllServers(hostPorts).build();
230    try {
231      stub.removeServers(null, request);
232    } catch (ServiceException e) {
233      throw ProtobufUtil.handleRemoteException(e);
234    }
235  }
236
237  @Override
238  public void renameRSGroup(String oldName, String newName) throws IOException {
239    RenameRSGroupRequest request = RenameRSGroupRequest.newBuilder().setOldRsgroupName(oldName)
240      .setNewRsgroupName(newName).build();
241    try {
242      stub.renameRSGroup(null, request);
243    } catch (ServiceException e) {
244      throw ProtobufUtil.handleRemoteException(e);
245    }
246  }
247
248  @Override
249  public void updateRSGroupConfig(String groupName, Map<String, String> configuration)
250    throws IOException {
251    UpdateRSGroupConfigRequest.Builder builder =
252      UpdateRSGroupConfigRequest.newBuilder().setGroupName(groupName);
253    if (configuration != null) {
254      configuration.entrySet().forEach(e -> builder.addConfiguration(
255        NameStringPair.newBuilder().setName(e.getKey()).setValue(e.getValue()).build()));
256    }
257    try {
258      stub.updateRSGroupConfig(null, builder.build());
259    } catch (ServiceException e) {
260      throw ProtobufUtil.handleRemoteException(e);
261    }
262  }
263
264  @Override
265  public void updateConfiguration(String groupName) throws IOException {
266    RSGroupInfo rsGroupInfo = getRSGroupInfo(groupName);
267    if (rsGroupInfo == null) {
268      throw new IllegalArgumentException("RSGroup does not exist: " + groupName);
269    }
270    ClusterMetrics status = admin.getClusterMetrics(EnumSet.of(ClusterMetrics.Option.SERVERS_NAME));
271    List<ServerName> groupServers = status.getServersName().stream()
272      .filter(s -> rsGroupInfo.containsServer(s.getAddress())).collect(Collectors.toList());
273    for (ServerName server : groupServers) {
274      admin.updateConfiguration(server);
275    }
276  }
277}