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.client.replication;
019
020import java.io.Closeable;
021import java.io.IOException;
022import java.util.ArrayList;
023import java.util.Collection;
024import java.util.HashMap;
025import java.util.List;
026import java.util.Map;
027import java.util.TreeMap;
028import java.util.regex.Pattern;
029import org.apache.hadoop.conf.Configuration;
030import org.apache.hadoop.hbase.HConstants;
031import org.apache.hadoop.hbase.ReplicationPeerNotFoundException;
032import org.apache.hadoop.hbase.TableName;
033import org.apache.hadoop.hbase.client.Admin;
034import org.apache.hadoop.hbase.client.Connection;
035import org.apache.hadoop.hbase.client.ConnectionFactory;
036import org.apache.hadoop.hbase.replication.ReplicationException;
037import org.apache.hadoop.hbase.replication.ReplicationPeerConfig;
038import org.apache.hadoop.hbase.replication.ReplicationPeerDescription;
039import org.apache.yetus.audience.InterfaceAudience;
040import org.slf4j.Logger;
041import org.slf4j.LoggerFactory;
042
043import org.apache.hbase.thirdparty.com.google.common.collect.Lists;
044
045/**
046 * <p>
047 * This class provides the administrative interface to HBase cluster replication.
048 * </p>
049 * <p>
050 * Adding a new peer results in creating new outbound connections from every region server to a
051 * subset of region servers on the slave cluster. Each new stream of replication will start
052 * replicating from the beginning of the current WAL, meaning that edits from that past will be
053 * replicated.
054 * </p>
055 * <p>
056 * Removing a peer is a destructive and irreversible operation that stops all the replication
057 * streams for the given cluster and deletes the metadata used to keep track of the replication
058 * state.
059 * </p>
060 * <p>
061 * To see which commands are available in the shell, type <code>replication</code>.
062 * </p>
063 * @deprecated use {@link org.apache.hadoop.hbase.client.Admin} instead.
064 */
065@InterfaceAudience.Public
066@Deprecated
067public class ReplicationAdmin implements Closeable {
068  private static final Logger LOG = LoggerFactory.getLogger(ReplicationAdmin.class);
069
070  public static final String TNAME = "tableName";
071  public static final String CFNAME = "columnFamilyName";
072
073  // only Global for now, can add other type
074  // such as, 1) no global replication, or 2) the table is replicated to this cluster, etc.
075  public static final String REPLICATIONTYPE = "replicationType";
076  public static final String REPLICATIONGLOBAL =
077    Integer.toString(HConstants.REPLICATION_SCOPE_GLOBAL);
078
079  private final Connection connection;
080  private Admin admin;
081
082  /**
083   * Constructor that creates a connection to the local ZooKeeper ensemble.
084   * @param conf Configuration to use
085   * @throws IOException      if an internal replication error occurs
086   * @throws RuntimeException if replication isn't enabled.
087   */
088  public ReplicationAdmin(Configuration conf) throws IOException {
089    this.connection = ConnectionFactory.createConnection(conf);
090    admin = connection.getAdmin();
091  }
092
093  /**
094   * Add a new remote slave cluster for replication.
095   * @param id         a short name that identifies the cluster
096   * @param peerConfig configuration for the replication slave cluster
097   * @param tableCfs   the table and column-family list which will be replicated for this peer. A
098   *                   map from tableName to column family names. An empty collection can be passed
099   *                   to indicate replicating all column families. Pass null for replicating all
100   *                   table and column families
101   * @deprecated as release of 2.0.0, and it will be removed in 3.0.0, use
102   *             {@link #addPeer(String, ReplicationPeerConfig)} instead.
103   */
104  @Deprecated
105  public void addPeer(String id, ReplicationPeerConfig peerConfig,
106    Map<TableName, ? extends Collection<String>> tableCfs)
107    throws ReplicationException, IOException {
108    if (tableCfs != null) {
109      peerConfig.setTableCFsMap(tableCfs);
110    }
111    this.admin.addReplicationPeer(id, peerConfig);
112  }
113
114  /**
115   * Add a new remote slave cluster for replication.
116   * @param id         a short name that identifies the cluster
117   * @param peerConfig configuration for the replication slave cluster
118   * @deprecated use
119   *             {@link org.apache.hadoop.hbase.client.Admin#addReplicationPeer(String, ReplicationPeerConfig)}
120   *             instead
121   */
122  @Deprecated
123  public void addPeer(String id, ReplicationPeerConfig peerConfig)
124    throws ReplicationException, IOException {
125    this.admin.addReplicationPeer(id, peerConfig);
126  }
127
128  /**
129   * @deprecated as release of 2.0.0, and it will be removed in 3.0.0
130   */
131  @Deprecated
132  public static Map<TableName, List<String>> parseTableCFsFromConfig(String tableCFsConfig) {
133    return ReplicationPeerConfigUtil.parseTableCFsFromConfig(tableCFsConfig);
134  }
135
136  /**
137   * @deprecated use
138   *             {@link org.apache.hadoop.hbase.client.Admin#updateReplicationPeerConfig(String, ReplicationPeerConfig)}
139   *             instead
140   */
141  @Deprecated
142  public void updatePeerConfig(String id, ReplicationPeerConfig peerConfig) throws IOException {
143    this.admin.updateReplicationPeerConfig(id, peerConfig);
144  }
145
146  /**
147   * Removes a peer cluster and stops the replication to it.
148   * @param id a short name that identifies the cluster
149   * @deprecated use {@link org.apache.hadoop.hbase.client.Admin#removeReplicationPeer(String)}
150   *             instead
151   */
152  @Deprecated
153  public void removePeer(String id) throws IOException {
154    this.admin.removeReplicationPeer(id);
155  }
156
157  /**
158   * Restart the replication stream to the specified peer.
159   * @param id a short name that identifies the cluster
160   * @deprecated use {@link org.apache.hadoop.hbase.client.Admin#enableReplicationPeer(String)}
161   *             instead
162   */
163  @Deprecated
164  public void enablePeer(String id) throws IOException {
165    this.admin.enableReplicationPeer(id);
166  }
167
168  /**
169   * Stop the replication stream to the specified peer.
170   * @param id a short name that identifies the cluster
171   * @deprecated use {@link org.apache.hadoop.hbase.client.Admin#disableReplicationPeer(String)}
172   *             instead
173   */
174  @Deprecated
175  public void disablePeer(String id) throws IOException {
176    this.admin.disableReplicationPeer(id);
177  }
178
179  /**
180   * Get the number of slave clusters the local cluster has.
181   * @return number of slave clusters
182   * @deprecated
183   */
184  @Deprecated
185  public int getPeersCount() throws IOException {
186    return this.admin.listReplicationPeers().size();
187  }
188
189  /**
190   * @deprecated use {@link org.apache.hadoop.hbase.client.Admin#listReplicationPeers()} instead
191   */
192  @Deprecated
193  public Map<String, ReplicationPeerConfig> listPeerConfigs() throws IOException {
194    List<ReplicationPeerDescription> peers = this.admin.listReplicationPeers();
195    Map<String, ReplicationPeerConfig> result = new TreeMap<>();
196    for (ReplicationPeerDescription peer : peers) {
197      result.put(peer.getPeerId(), peer.getPeerConfig());
198    }
199    return result;
200  }
201
202  /**
203   * @deprecated use {@link org.apache.hadoop.hbase.client.Admin#getReplicationPeerConfig(String)}
204   *             instead
205   */
206  @Deprecated
207  public ReplicationPeerConfig getPeerConfig(String id) throws IOException {
208    return admin.getReplicationPeerConfig(id);
209  }
210
211  /**
212   * Get the replicable table-cf config of the specified peer.
213   * @param id a short name that identifies the cluster
214   * @deprecated as release of 2.0.0, and it will be removed in 3.0.0, use
215   *             {@link #getPeerConfig(String)} instead.
216   */
217  @Deprecated
218  public String getPeerTableCFs(String id) throws IOException {
219    ReplicationPeerConfig peerConfig = admin.getReplicationPeerConfig(id);
220    return ReplicationPeerConfigUtil.convertToString(peerConfig.getTableCFsMap());
221  }
222
223  /**
224   * Append the replicable table-cf config of the specified peer
225   * @param id       a short that identifies the cluster
226   * @param tableCfs table-cfs config str
227   * @deprecated as release of 2.0.0, and it will be removed in 3.0.0, use
228   *             {@link #appendPeerTableCFs(String, Map)} instead.
229   */
230  @Deprecated
231  public void appendPeerTableCFs(String id, String tableCfs)
232    throws ReplicationException, IOException {
233    appendPeerTableCFs(id, ReplicationPeerConfigUtil.parseTableCFsFromConfig(tableCfs));
234  }
235
236  /**
237   * Append the replicable table-cf config of the specified peer
238   * @param id       a short that identifies the cluster
239   * @param tableCfs A map from tableName to column family names
240   */
241  @Deprecated
242  public void appendPeerTableCFs(String id, Map<TableName, ? extends Collection<String>> tableCfs)
243    throws ReplicationException, IOException {
244    this.admin.appendReplicationPeerTableCFs(id, copyTableCFs(tableCfs));
245  }
246
247  /**
248   * Remove some table-cfs from table-cfs config of the specified peer
249   * @param id      a short name that identifies the cluster
250   * @param tableCf table-cfs config str
251   * @deprecated as release of 2.0.0, and it will be removed in 3.0.0, use
252   *             {@link #removePeerTableCFs(String, Map)} instead.
253   */
254  @Deprecated
255  public void removePeerTableCFs(String id, String tableCf)
256    throws ReplicationException, IOException {
257    removePeerTableCFs(id, ReplicationPeerConfigUtil.parseTableCFsFromConfig(tableCf));
258  }
259
260  /**
261   * Remove some table-cfs from config of the specified peer
262   * @param id       a short name that identifies the cluster
263   * @param tableCfs A map from tableName to column family names
264   */
265  @Deprecated
266  public void removePeerTableCFs(String id, Map<TableName, ? extends Collection<String>> tableCfs)
267    throws ReplicationException, IOException {
268    this.admin.removeReplicationPeerTableCFs(id, copyTableCFs(tableCfs));
269  }
270
271  private Map<TableName, List<String>>
272    copyTableCFs(Map<TableName, ? extends Collection<String>> tableCfs) {
273    Map<TableName, List<String>> newTableCfs = new HashMap<>();
274    if (tableCfs != null) {
275      tableCfs.forEach(
276        (table, cfs) -> newTableCfs.put(table, cfs != null ? Lists.newArrayList(cfs) : null));
277    }
278    return newTableCfs;
279  }
280
281  /**
282   * Set the replicable table-cf config of the specified peer
283   * @param id       a short name that identifies the cluster
284   * @param tableCfs the table and column-family list which will be replicated for this peer. A map
285   *                 from tableName to column family names. An empty collection can be passed to
286   *                 indicate replicating all column families. Pass null for replicating all table
287   *                 and column families
288   */
289  @Deprecated
290  public void setPeerTableCFs(String id, Map<TableName, ? extends Collection<String>> tableCfs)
291    throws IOException {
292    ReplicationPeerConfig peerConfig = getPeerConfig(id);
293    peerConfig.setTableCFsMap(tableCfs);
294    updatePeerConfig(id, peerConfig);
295  }
296
297  /**
298   * Get the state of the specified peer cluster
299   * @param id String format of the Short name that identifies the peer, an IllegalArgumentException
300   *           is thrown if it doesn't exist
301   * @return true if replication is enabled to that peer, false if it isn't
302   */
303  @Deprecated
304  public boolean getPeerState(String id) throws ReplicationException, IOException {
305    List<ReplicationPeerDescription> peers = admin.listReplicationPeers(Pattern.compile(id));
306    if (peers.isEmpty() || !id.equals(peers.get(0).getPeerId())) {
307      throw new ReplicationPeerNotFoundException(id);
308    }
309    return peers.get(0).isEnabled();
310  }
311
312  @Override
313  public void close() throws IOException {
314    if (this.connection != null) {
315      this.connection.close();
316    }
317    admin.close();
318  }
319
320  /**
321   * Find all column families that are replicated from this cluster
322   * @return the full list of the replicated column families of this cluster as: tableName, family
323   *         name, replicationType Currently replicationType is Global. In the future, more
324   *         replication types may be extended here. For example 1) the replication may only apply
325   *         to selected peers instead of all peers 2) the replicationType may indicate the host
326   *         Cluster servers as Slave for the table:columnFam.
327   * @deprecated use {@link org.apache.hadoop.hbase.client.Admin#listReplicatedTableCFs()} instead
328   */
329  @Deprecated
330  public List<HashMap<String, String>> listReplicated() throws IOException {
331    List<HashMap<String, String>> replicationColFams = new ArrayList<>();
332    admin.listReplicatedTableCFs().forEach((tableCFs) -> {
333      String table = tableCFs.getTable().getNameAsString();
334      tableCFs.getColumnFamilyMap().forEach((cf, scope) -> {
335        HashMap<String, String> replicationEntry = new HashMap<>();
336        replicationEntry.put(TNAME, table);
337        replicationEntry.put(CFNAME, cf);
338        replicationEntry.put(REPLICATIONTYPE, REPLICATIONGLOBAL);
339        replicationColFams.add(replicationEntry);
340      });
341    });
342    return replicationColFams;
343  }
344
345  /**
346   * Enable a table's replication switch.
347   * @param tableName name of the table
348   * @throws IOException if a remote or network exception occurs
349   * @deprecated use {@link org.apache.hadoop.hbase.client.Admin#enableTableReplication(TableName)}
350   *             instead
351   */
352  @Deprecated
353  public void enableTableRep(final TableName tableName) throws IOException {
354    admin.enableTableReplication(tableName);
355  }
356
357  /**
358   * Disable a table's replication switch.
359   * @param tableName name of the table
360   * @throws IOException if a remote or network exception occurs
361   * @deprecated use {@link org.apache.hadoop.hbase.client.Admin#disableTableReplication(TableName)}
362   *             instead
363   */
364  @Deprecated
365  public void disableTableRep(final TableName tableName) throws IOException {
366    admin.disableTableReplication(tableName);
367  }
368
369  /**
370   * @deprecated use {@link org.apache.hadoop.hbase.client.Admin#listReplicationPeers()} instead
371   */
372  @InterfaceAudience.Private
373  @Deprecated
374  List<ReplicationPeerDescription> listReplicationPeers() throws IOException {
375    return admin.listReplicationPeers();
376  }
377}