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.security.access;
019
020import static org.junit.jupiter.api.Assertions.assertThrows;
021import static org.mockito.Mockito.mock;
022
023import java.util.List;
024import java.util.Map;
025import java.util.Set;
026import org.apache.hadoop.hbase.NamespaceDescriptor;
027import org.apache.hadoop.hbase.TableName;
028import org.apache.hadoop.hbase.WriteAttemptedOnReadOnlyClusterException;
029import org.apache.hadoop.hbase.client.BalanceRequest;
030import org.apache.hadoop.hbase.client.Mutation;
031import org.apache.hadoop.hbase.client.RegionInfo;
032import org.apache.hadoop.hbase.client.SnapshotDescription;
033import org.apache.hadoop.hbase.client.TableDescriptor;
034import org.apache.hadoop.hbase.coprocessor.MasterCoprocessorEnvironment;
035import org.apache.hadoop.hbase.coprocessor.ObserverContext;
036import org.apache.hadoop.hbase.net.Address;
037import org.apache.hadoop.hbase.quotas.GlobalQuotaSettings;
038import org.apache.hadoop.hbase.replication.ReplicationPeerConfig;
039import org.apache.hadoop.hbase.replication.SyncReplicationState;
040import org.apache.hadoop.hbase.testclassification.SecurityTests;
041import org.apache.hadoop.hbase.testclassification.SmallTests;
042import org.apache.hadoop.hbase.util.Bytes;
043import org.junit.jupiter.api.AfterEach;
044import org.junit.jupiter.api.BeforeEach;
045import org.junit.jupiter.api.Tag;
046import org.junit.jupiter.api.Test;
047
048// Tests methods of Master Observer which are implemented in ReadOnlyController,
049// by mocking the coprocessor environment and dependencies
050
051@Tag(SecurityTests.TAG)
052@Tag(SmallTests.TAG)
053public class TestReadOnlyControllerMasterObserver {
054
055  MasterReadOnlyController MasterReadOnlyController;
056
057  // Master Coprocessor mocking variables
058  ObserverContext<MasterCoprocessorEnvironment> c, ctx;
059  TableDescriptor desc;
060  RegionInfo[] regions;
061  TableName tableName;
062  TableDescriptor currentDescriptor, newDescriptor;
063  String dstSFT;
064  byte[] family;
065  byte[] splitRow;
066  byte[] splitKey;
067  List<Mutation> metaEntries;
068  RegionInfo[] regionsToMerge;
069  SnapshotDescription snapshot;
070  TableDescriptor tableDescriptor;
071  NamespaceDescriptor ns;
072  NamespaceDescriptor currentNsDescriptor, newNsDescriptor;
073  String namespace;
074  String userName;
075  GlobalQuotaSettings quotas;
076  String regionServer;
077  Set<Address> servers;
078  Set<TableName> tables;
079  String targetGroup;
080  String name;
081  String groupName;
082  BalanceRequest request;
083  String oldName, newName;
084  Map<String, String> configuration;
085  String peerId;
086  ReplicationPeerConfig peerConfig;
087  SyncReplicationState state;
088  UserPermission userPermission;
089  boolean mergeExistingPermissions;
090
091  @BeforeEach
092  public void setup() throws Exception {
093    MasterReadOnlyController = new MasterReadOnlyController();
094
095    // mocking variables initialization
096    c = mock(ObserverContext.class);
097    // ctx is created to make naming variable in sync with the Observer interface
098    // methods where 'ctx' is used as the ObserverContext variable name instead of 'c'.
099    // otherwise both are one and the same
100    ctx = c;
101    desc = mock(TableDescriptor.class);
102    regions = new RegionInfo[] {};
103    tableName = TableName.valueOf("testTable");
104    currentDescriptor = mock(TableDescriptor.class);
105    newDescriptor = mock(TableDescriptor.class);
106    dstSFT = "dstSFT";
107    family = Bytes.toBytes("testFamily");
108    splitRow = Bytes.toBytes("splitRow");
109    splitKey = Bytes.toBytes("splitKey");
110    metaEntries = List.of();
111    regionsToMerge = new RegionInfo[] {};
112    snapshot = mock(SnapshotDescription.class);
113    tableDescriptor = mock(TableDescriptor.class);
114    ns = mock(NamespaceDescriptor.class);
115    currentNsDescriptor = mock(NamespaceDescriptor.class);
116    newNsDescriptor = mock(NamespaceDescriptor.class);
117    namespace = "testNamespace";
118    userName = "testUser";
119    quotas = mock(GlobalQuotaSettings.class);
120    regionServer = "testRegionServer";
121    servers = Set.of();
122    tables = Set.of();
123    targetGroup = "targetGroup";
124    name = "testRSGroup";
125    groupName = "testGroupName";
126    request = BalanceRequest.newBuilder().build();
127    oldName = "oldRSGroupName";
128    newName = "newRSGroupName";
129    configuration = Map.of();
130    peerId = "testPeerId";
131    peerConfig = mock(ReplicationPeerConfig.class);
132    state = SyncReplicationState.NONE;
133    userPermission = mock(UserPermission.class);
134    mergeExistingPermissions = false;
135
136    // Linking the mocks:
137  }
138
139  @AfterEach
140  public void tearDown() throws Exception {
141
142  }
143
144  @Test
145  public void testPreCreateTableRegionsInfosReadOnlyException() {
146    assertThrows(WriteAttemptedOnReadOnlyClusterException.class, () -> {
147      MasterReadOnlyController.preCreateTableRegionsInfos(ctx, desc);
148    });
149  }
150
151  @Test
152  public void testPreCreateTableReadOnlyException() {
153    assertThrows(WriteAttemptedOnReadOnlyClusterException.class, () -> {
154      MasterReadOnlyController.preCreateTable(ctx, desc, regions);
155    });
156  }
157
158  @Test
159  public void testPreCreateTableActionReadOnlyException() {
160    assertThrows(WriteAttemptedOnReadOnlyClusterException.class, () -> {
161      MasterReadOnlyController.preCreateTableAction(ctx, desc, regions);
162    });
163  }
164
165  @Test
166  public void testPreDeleteTableReadOnlyException() {
167    assertThrows(WriteAttemptedOnReadOnlyClusterException.class, () -> {
168      MasterReadOnlyController.preDeleteTable(ctx, tableName);
169    });
170  }
171
172  @Test
173  public void testPreDeleteTableActionReadOnlyException() {
174    assertThrows(WriteAttemptedOnReadOnlyClusterException.class, () -> {
175      MasterReadOnlyController.preDeleteTableAction(ctx, tableName);
176    });
177  }
178
179  @Test
180  public void testPreTruncateTableReadOnlyException() {
181    assertThrows(WriteAttemptedOnReadOnlyClusterException.class, () -> {
182      MasterReadOnlyController.preTruncateTable(ctx, tableName);
183    });
184  }
185
186  @Test
187  public void testPreTruncateTableActionReadOnlyException() {
188    assertThrows(WriteAttemptedOnReadOnlyClusterException.class, () -> {
189      MasterReadOnlyController.preTruncateTableAction(ctx, tableName);
190    });
191  }
192
193  @Test
194  public void testPreModifyTableReadOnlyException() {
195    assertThrows(WriteAttemptedOnReadOnlyClusterException.class, () -> {
196      MasterReadOnlyController.preModifyTable(ctx, tableName, currentDescriptor, newDescriptor);
197    });
198  }
199
200  @Test
201  public void testPreModifyTableStoreFileTrackerReadOnlyException() {
202    assertThrows(WriteAttemptedOnReadOnlyClusterException.class, () -> {
203      MasterReadOnlyController.preModifyTableStoreFileTracker(ctx, tableName, dstSFT);
204    });
205  }
206
207  @Test
208  public void testPreModifyColumnFamilyStoreFileTrackerReadOnlyException() {
209    assertThrows(WriteAttemptedOnReadOnlyClusterException.class, () -> {
210      MasterReadOnlyController.preModifyColumnFamilyStoreFileTracker(ctx, tableName, family,
211        dstSFT);
212    });
213  }
214
215  @Test
216  public void testPreModifyTableActionReadOnlyException() {
217    assertThrows(WriteAttemptedOnReadOnlyClusterException.class, () -> {
218      MasterReadOnlyController.preModifyTableAction(ctx, tableName, currentDescriptor,
219        newDescriptor);
220    });
221  }
222
223  @Test
224  public void testPreSplitRegionReadOnlyException() {
225    assertThrows(WriteAttemptedOnReadOnlyClusterException.class, () -> {
226      MasterReadOnlyController.preSplitRegion(c, tableName, splitRow);
227    });
228  }
229
230  @Test
231  public void testPreSplitRegionActionReadOnlyException() {
232    assertThrows(WriteAttemptedOnReadOnlyClusterException.class, () -> {
233      MasterReadOnlyController.preSplitRegionAction(c, tableName, splitRow);
234    });
235  }
236
237  @Test
238  public void testPreSplitRegionBeforeMETAActionReadOnlyException() {
239    assertThrows(WriteAttemptedOnReadOnlyClusterException.class, () -> {
240      MasterReadOnlyController.preSplitRegionBeforeMETAAction(ctx, splitKey, metaEntries);
241    });
242  }
243
244  @Test
245  public void testPreSplitRegionAfterMETAActionReadOnlyException() {
246    assertThrows(WriteAttemptedOnReadOnlyClusterException.class, () -> {
247      MasterReadOnlyController.preSplitRegionAfterMETAAction(ctx);
248    });
249  }
250
251  @Test
252  public void testPreMergeRegionsActionReadOnlyException() {
253    assertThrows(WriteAttemptedOnReadOnlyClusterException.class, () -> {
254      MasterReadOnlyController.preMergeRegionsAction(ctx, regionsToMerge);
255    });
256  }
257
258  @Test
259  public void testPreMergeRegionsCommitActionReadOnlyException() {
260    assertThrows(WriteAttemptedOnReadOnlyClusterException.class, () -> {
261      MasterReadOnlyController.preMergeRegionsCommitAction(ctx, regionsToMerge, metaEntries);
262    });
263  }
264
265  @Test
266  public void testPreSnapshotReadOnlyException() {
267    assertThrows(WriteAttemptedOnReadOnlyClusterException.class, () -> {
268      MasterReadOnlyController.preSnapshot(ctx, snapshot, tableDescriptor);
269    });
270  }
271
272  @Test
273  public void testPreCloneSnapshotReadOnlyException() {
274    assertThrows(WriteAttemptedOnReadOnlyClusterException.class, () -> {
275      MasterReadOnlyController.preCloneSnapshot(ctx, snapshot, tableDescriptor);
276    });
277  }
278
279  @Test
280  public void testPreRestoreSnapshotReadOnlyException() {
281    assertThrows(WriteAttemptedOnReadOnlyClusterException.class, () -> {
282      MasterReadOnlyController.preRestoreSnapshot(ctx, snapshot, tableDescriptor);
283    });
284  }
285
286  @Test
287  public void testPreDeleteSnapshotReadOnlyException() {
288    assertThrows(WriteAttemptedOnReadOnlyClusterException.class, () -> {
289      MasterReadOnlyController.preDeleteSnapshot(ctx, snapshot);
290    });
291  }
292
293  @Test
294  public void testPreCreateNamespaceReadOnlyException() {
295    assertThrows(WriteAttemptedOnReadOnlyClusterException.class, () -> {
296      MasterReadOnlyController.preCreateNamespace(ctx, ns);
297    });
298  }
299
300  @Test
301  public void testPreModifyNamespaceReadOnlyException() {
302    assertThrows(WriteAttemptedOnReadOnlyClusterException.class, () -> {
303      MasterReadOnlyController.preModifyNamespace(ctx, currentNsDescriptor, newNsDescriptor);
304    });
305  }
306
307  @Test
308  public void testPreDeleteNamespaceReadOnlyException() {
309    assertThrows(WriteAttemptedOnReadOnlyClusterException.class, () -> {
310      MasterReadOnlyController.preDeleteNamespace(ctx, namespace);
311    });
312  }
313
314  @Test
315  public void testPreMasterStoreFlushReadOnlyException() {
316    assertThrows(WriteAttemptedOnReadOnlyClusterException.class, () -> {
317      MasterReadOnlyController.preMasterStoreFlush(ctx);
318    });
319  }
320
321  @Test
322  public void testPreSetUserQuotaReadOnlyException() {
323    assertThrows(WriteAttemptedOnReadOnlyClusterException.class, () -> {
324      MasterReadOnlyController.preSetUserQuota(ctx, userName, quotas);
325    });
326  }
327
328  @Test
329  public void testPreSetUserQuotaOnTableReadOnlyException() {
330    assertThrows(WriteAttemptedOnReadOnlyClusterException.class, () -> {
331      MasterReadOnlyController.preSetUserQuota(ctx, userName, tableName, quotas);
332    });
333  }
334
335  @Test
336  public void testPreSetUserQuotaOnNamespaceReadOnlyException() {
337    assertThrows(WriteAttemptedOnReadOnlyClusterException.class, () -> {
338      MasterReadOnlyController.preSetUserQuota(ctx, userName, namespace, quotas);
339    });
340  }
341
342  @Test
343  public void testPreSetTableQuotaReadOnlyException() {
344    assertThrows(WriteAttemptedOnReadOnlyClusterException.class, () -> {
345      MasterReadOnlyController.preSetTableQuota(ctx, tableName, quotas);
346    });
347  }
348
349  @Test
350  public void testPreSetNamespaceQuotaReadOnlyException() {
351    assertThrows(WriteAttemptedOnReadOnlyClusterException.class, () -> {
352      MasterReadOnlyController.preSetNamespaceQuota(ctx, namespace, quotas);
353    });
354  }
355
356  @Test
357  public void testPreSetRegionServerQuotaReadOnlyException() {
358    assertThrows(WriteAttemptedOnReadOnlyClusterException.class, () -> {
359      MasterReadOnlyController.preSetRegionServerQuota(ctx, regionServer, quotas);
360    });
361  }
362
363  @Test
364  public void testPreMergeRegionsReadOnlyException() {
365    assertThrows(WriteAttemptedOnReadOnlyClusterException.class, () -> {
366      MasterReadOnlyController.preMergeRegions(ctx, regionsToMerge);
367    });
368  }
369
370  @Test
371  public void testPreMoveServersAndTablesReadOnlyException() {
372    assertThrows(WriteAttemptedOnReadOnlyClusterException.class, () -> {
373      MasterReadOnlyController.preMoveServersAndTables(ctx, servers, tables, targetGroup);
374    });
375  }
376
377  @Test
378  public void testPreMoveServersReadOnlyException() {
379    assertThrows(WriteAttemptedOnReadOnlyClusterException.class, () -> {
380      MasterReadOnlyController.preMoveServers(ctx, servers, targetGroup);
381    });
382  }
383
384  @Test
385  public void testPreMoveTablesReadOnlyException() {
386    assertThrows(WriteAttemptedOnReadOnlyClusterException.class, () -> {
387      MasterReadOnlyController.preMoveTables(ctx, tables, targetGroup);
388    });
389  }
390
391  @Test
392  public void testPreAddRSGroupReadOnlyException() {
393    assertThrows(WriteAttemptedOnReadOnlyClusterException.class, () -> {
394      MasterReadOnlyController.preAddRSGroup(ctx, name);
395    });
396  }
397
398  @Test
399  public void testPreRemoveRSGroupReadOnlyException() {
400    assertThrows(WriteAttemptedOnReadOnlyClusterException.class, () -> {
401      MasterReadOnlyController.preRemoveRSGroup(ctx, name);
402    });
403  }
404
405  @Test
406  public void testPreBalanceRSGroupReadOnlyException() {
407    assertThrows(WriteAttemptedOnReadOnlyClusterException.class, () -> {
408      MasterReadOnlyController.preBalanceRSGroup(ctx, groupName, request);
409    });
410  }
411
412  @Test
413  public void testPreRemoveServersReadOnlyException() {
414    assertThrows(WriteAttemptedOnReadOnlyClusterException.class, () -> {
415      MasterReadOnlyController.preRemoveServers(ctx, servers);
416    });
417  }
418
419  @Test
420  public void testPreRenameRSGroupReadOnlyException() {
421    assertThrows(WriteAttemptedOnReadOnlyClusterException.class, () -> {
422      MasterReadOnlyController.preRenameRSGroup(ctx, oldName, newName);
423    });
424  }
425
426  @Test
427  public void testPreUpdateRSGroupConfigReadOnlyException() {
428    assertThrows(WriteAttemptedOnReadOnlyClusterException.class, () -> {
429      MasterReadOnlyController.preUpdateRSGroupConfig(ctx, groupName, configuration);
430    });
431  }
432
433  @Test
434  public void testPreAddReplicationPeerReadOnlyException() {
435    assertThrows(WriteAttemptedOnReadOnlyClusterException.class, () -> {
436      MasterReadOnlyController.preAddReplicationPeer(ctx, peerId, peerConfig);
437    });
438  }
439
440  @Test
441  public void testPreRemoveReplicationPeerReadOnlyException() {
442    assertThrows(WriteAttemptedOnReadOnlyClusterException.class, () -> {
443      MasterReadOnlyController.preRemoveReplicationPeer(ctx, peerId);
444    });
445  }
446
447  @Test
448  public void testPreEnableReplicationPeerReadOnlyException() {
449    assertThrows(WriteAttemptedOnReadOnlyClusterException.class, () -> {
450      MasterReadOnlyController.preEnableReplicationPeer(ctx, peerId);
451    });
452  }
453
454  @Test
455  public void testPreDisableReplicationPeerReadOnlyException() {
456    assertThrows(WriteAttemptedOnReadOnlyClusterException.class, () -> {
457      MasterReadOnlyController.preDisableReplicationPeer(ctx, peerId);
458    });
459  }
460
461  @Test
462  public void testPreUpdateReplicationPeerConfigReadOnlyException() {
463    assertThrows(WriteAttemptedOnReadOnlyClusterException.class, () -> {
464      MasterReadOnlyController.preUpdateReplicationPeerConfig(ctx, peerId, peerConfig);
465    });
466  }
467
468  @Test
469  public void testPreTransitReplicationPeerSyncReplicationStateReadOnlyException() {
470    assertThrows(WriteAttemptedOnReadOnlyClusterException.class, () -> {
471      MasterReadOnlyController.preTransitReplicationPeerSyncReplicationState(ctx, peerId, state);
472    });
473  }
474
475  @Test
476  public void testPreGrantReadOnlyException() {
477    assertThrows(WriteAttemptedOnReadOnlyClusterException.class, () -> {
478      MasterReadOnlyController.preGrant(ctx, userPermission, mergeExistingPermissions);
479    });
480  }
481
482  @Test
483  public void testPreRevokeReadOnlyException() {
484    assertThrows(WriteAttemptedOnReadOnlyClusterException.class, () -> {
485      MasterReadOnlyController.preRevoke(ctx, userPermission);
486    });
487  }
488}