blob: 33c3170a5ca3ab32e2076ae7b17aed86057d6f82 [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package org.apache.hadoop.ozone.om.multitenant;
import static org.apache.hadoop.ozone.om.OMConfigKeys.OZONE_OM_RANGER_HTTPS_ADMIN_API_PASSWD;
import static org.apache.hadoop.ozone.om.OMConfigKeys.OZONE_OM_RANGER_HTTPS_ADMIN_API_USER;
import static org.apache.hadoop.ozone.om.OMConfigKeys.OZONE_RANGER_HTTPS_ADDRESS_KEY;
import static org.apache.hadoop.ozone.om.OMConfigKeys.OZONE_RANGER_SERVICE;
import static org.apache.hadoop.ozone.om.OMMultiTenantManager.OZONE_TENANT_RANGER_ROLE_DESCRIPTION;
import static org.apache.hadoop.security.authentication.util.KerberosName.DEFAULT_MECHANISM;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.framework;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import com.google.protobuf.ServiceException;
import org.apache.hadoop.hdds.HddsConfigKeys;
import org.apache.hadoop.hdds.conf.OzoneConfiguration;
import org.apache.hadoop.ipc.RPC;
import org.apache.hadoop.ipc.Server;
import org.apache.hadoop.ozone.OzoneConsts;
import org.apache.hadoop.ozone.audit.AuditLogger;
import org.apache.hadoop.ozone.audit.AuditMessage;
import org.apache.hadoop.ozone.om.OMConfigKeys;
import org.apache.hadoop.ozone.om.OMMetadataManager;
import org.apache.hadoop.ozone.om.OMMetrics;
import org.apache.hadoop.ozone.om.OMMultiTenantManager;
import org.apache.hadoop.ozone.om.OmMetadataManagerImpl;
import org.apache.hadoop.ozone.om.OzoneManager;
import org.apache.hadoop.ozone.om.helpers.OmDBAccessIdInfo;
import org.apache.hadoop.ozone.om.helpers.OmDBTenantState;
import org.apache.hadoop.ozone.om.multitenant.MultiTenantAccessController.Policy;
import org.apache.hadoop.ozone.om.multitenant.MultiTenantAccessController.Role;
import org.apache.hadoop.ozone.om.ratis.OzoneManagerRatisServer;
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OMRequest;
import org.apache.hadoop.security.UserGroupInformation;
import org.apache.hadoop.security.authentication.util.KerberosName;
import org.apache.ozone.test.GenericTestUtils;
import org.apache.ranger.RangerServiceException;
import org.apache.ratis.protocol.RaftGroupId;
import org.apache.ratis.protocol.RaftPeerId;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.junit.rules.Timeout;
import org.mockito.Mockito;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.event.Level;
/**
* Tests Ozone Manager Multi-Tenancy feature Background Sync with Apache Ranger.
* Marking it as Ignore because it needs Ranger access point.
*/
@Ignore("TODO: Requires a Ranger endpoint")
public class TestRangerBGSyncService {
private static final Logger LOG =
LoggerFactory.getLogger(TestRangerBGSyncService.class);
/**
* Timeout for each test.
*/
@Rule
public Timeout timeout = new Timeout(180, TimeUnit.SECONDS);
private static final long TEST_SYNC_INTERVAL_SEC = 1L;
private static final long TEST_SYNC_TIMEOUT_SEC = 3L;
private static final int CHECK_SYNC_MILLIS = 1000;
private static final int WAIT_SYNC_TIMEOUT_MILLIS = 60000;
private TemporaryFolder folder = new TemporaryFolder();
private MultiTenantAccessController accessController;
private OMRangerBGSyncService bgSync;
// List of policy names created in Ranger for the test
private final List<String> policiesCreated = new ArrayList<>();
// List of role names created in Ranger for the test
private final List<String> rolesCreated = new ArrayList<>();
// List of user names created in Ranger for the test
private final List<String> usersCreated = new ArrayList<>();
private static OzoneConfiguration conf;
private OzoneManager ozoneManager;
private OMMetrics omMetrics;
private OMMetadataManager omMetadataManager;
private OMMultiTenantManager omMultiTenantManager;
private AuditLogger auditLogger;
private Tenant tenant;
private static final String TENANT_ID = "tenant1";
// UGI-related vars
private static final String USER_ALICE = "alice@EXAMPLE.COM";
private static final String USER_ALICE_SHORT = "alice";
private UserGroupInformation ugiAlice;
private static final String USER_BOB_SHORT = "bob";
private RangerUserRequest rangerUserRequest;
private static void simulateOzoneSiteXmlConfig() {
// The following configs need to be set before the test can be enabled.
// Pass them in as JVM properties. e.g.:
//
// -Dozone.om.ranger.https-address=http://ranger:6080
// -Dozone.om.ranger.https.admin.api.user=admin
// -Dozone.om.ranger.https.admin.api.passwd=passwd
conf.set(OZONE_RANGER_HTTPS_ADDRESS_KEY,
System.getProperty(OZONE_RANGER_HTTPS_ADDRESS_KEY));
conf.set(OZONE_OM_RANGER_HTTPS_ADMIN_API_USER,
System.getProperty(OZONE_OM_RANGER_HTTPS_ADMIN_API_USER));
conf.set(OZONE_OM_RANGER_HTTPS_ADMIN_API_PASSWD,
System.getProperty(OZONE_OM_RANGER_HTTPS_ADMIN_API_PASSWD));
}
@BeforeClass
public static void init() {
conf = new OzoneConfiguration();
simulateOzoneSiteXmlConfig();
GenericTestUtils.setLogLevel(OMRangerBGSyncService.LOG, Level.DEBUG);
GenericTestUtils.setLogLevel(
LoggerFactory.getLogger(RangerClientMultiTenantAccessController.class),
Level.INFO);
}
@AfterClass
public static void shutdown() {
}
@Before
public void setUp() throws IOException {
KerberosName.setRuleMechanism(DEFAULT_MECHANISM);
KerberosName.setRules(
"RULE:[2:$1@$0](.*@EXAMPLE.COM)s/@.*//\n" +
"RULE:[1:$1@$0](.*@EXAMPLE.COM)s/@.*//\n" +
"DEFAULT");
ugiAlice = UserGroupInformation.createRemoteUser(USER_ALICE);
Assert.assertEquals(USER_ALICE_SHORT, ugiAlice.getShortUserName());
ozoneManager = mock(OzoneManager.class);
Server.Call call = spy(new Server.Call(1, 1, null, null,
RPC.RpcKind.RPC_BUILTIN, new byte[] {1, 2, 3}));
// Run as alice, so that Server.getRemoteUser() won't return null.
when(call.getRemoteUser()).thenReturn(ugiAlice);
Server.getCurCall().set(call);
String omID = UUID.randomUUID().toString();
final String path = GenericTestUtils.getTempPath(omID);
Path metaDirPath = Paths.get(path, "om-meta");
conf.set(HddsConfigKeys.OZONE_METADATA_DIRS, metaDirPath.toString());
omMetrics = OMMetrics.create();
folder = new TemporaryFolder(new File("/tmp"));
folder.create();
conf.set(OMConfigKeys.OZONE_OM_DB_DIRS,
folder.newFolder().getAbsolutePath());
// No need to conf.set(OzoneConfigKeys.OZONE_ADMINISTRATORS, ...) here
// as we did the trick earlier with mockito.
omMetadataManager = new OmMetadataManagerImpl(conf);
when(ozoneManager.getMetrics()).thenReturn(omMetrics);
when(ozoneManager.getMetadataManager()).thenReturn(omMetadataManager);
when(ozoneManager.isRatisEnabled()).thenReturn(true);
auditLogger = mock(AuditLogger.class);
when(ozoneManager.getAuditLogger()).thenReturn(auditLogger);
doNothing().when(auditLogger).logWrite(any(AuditMessage.class));
// Multi-tenant related initializations
omMultiTenantManager = mock(OMMultiTenantManager.class);
tenant = mock(Tenant.class);
when(ozoneManager.getMultiTenantManager()).thenReturn(omMultiTenantManager);
when(ozoneManager.getConfiguration()).thenReturn(conf);
when(ozoneManager.isLeaderReady()).thenReturn(true);
when(omMultiTenantManager.getTenantVolumeName(TENANT_ID))
.thenReturn(TENANT_ID);
when(omMultiTenantManager.getTenantUserRoleName(TENANT_ID))
.thenReturn(OMMultiTenantManager.getDefaultUserRoleName(TENANT_ID));
when(omMultiTenantManager.getTenantAdminRoleName(TENANT_ID))
.thenReturn(OMMultiTenantManager.getDefaultAdminRoleName(TENANT_ID));
when(omMultiTenantManager.getAuthorizerLock())
.thenReturn(new AuthorizerLockImpl());
// Raft client request handling
OzoneManagerRatisServer omRatisServer = mock(OzoneManagerRatisServer.class);
when(omRatisServer.getRaftPeerId())
.thenReturn(RaftPeerId.valueOf("peerId"));
when(omRatisServer.getRaftGroupId())
.thenReturn(RaftGroupId.randomId());
when(ozoneManager.getOmRatisServer()).thenReturn(omRatisServer);
try {
doAnswer(invocation -> {
OMRequest request = invocation.getArgument(0);
long v = request.getSetRangerServiceVersionRequest()
.getRangerServiceVersion();
LOG.info("Writing Ranger Ozone Service Version to DB: {}", v);
ozoneManager.getMetadataManager().getMetaTable().put(
OzoneConsts.RANGER_OZONE_SERVICE_VERSION_KEY, String.valueOf(v));
return null;
}).when(omRatisServer).submitRequest(Mockito.any(), Mockito.any());
} catch (ServiceException e) {
throw new RuntimeException(e);
}
when(tenant.getTenantAccessPolicies()).thenReturn(new ArrayList<>());
System.setProperty("javax.net.ssl.trustStore",
"/path/to/cm-auto-global_truststore.jks");
conf.set(OZONE_RANGER_SERVICE, "cm_ozone");
// Helper to create and delete users from Ranger for the test.
// RangerClient hasn't implemented these yet so we had to roll our own.
rangerUserRequest = new RangerUserRequest(
conf.get(OZONE_RANGER_HTTPS_ADDRESS_KEY),
conf.get(OZONE_OM_RANGER_HTTPS_ADMIN_API_USER),
conf.get(OZONE_OM_RANGER_HTTPS_ADMIN_API_PASSWD));
accessController = new RangerClientMultiTenantAccessController(conf);
}
@After
public void tearDown() {
bgSync.shutdown();
cleanupPoliciesRolesUsers();
omMetrics.unRegister();
framework().clearInlineMocks();
}
long initBGSync() throws IOException {
bgSync = new OMRangerBGSyncService(ozoneManager,
ozoneManager.getMultiTenantManager(), accessController,
TEST_SYNC_INTERVAL_SEC, TimeUnit.SECONDS, TEST_SYNC_TIMEOUT_SEC);
return bgSync.getRangerOzoneServicePolicyVersion();
}
private void createRoleHelper(Role role) throws IOException {
Role roleCreated = accessController.createRole(role);
// Confirm role creation
Assert.assertEquals(role.getName(), roleCreated.getName());
// Add to created roles list
rolesCreated.add(0, role.getName());
}
private void createRolesAndPoliciesInRanger(boolean populateDB) {
policiesCreated.clear();
rolesCreated.clear();
// Tenant name to be used for this test
final String tenantId = TENANT_ID;
// volume name = bucket namespace name
final String volumeName = tenantId;
final String adminRoleName =
OMMultiTenantManager.getDefaultAdminRoleName(tenantId);
final String userRoleName =
OMMultiTenantManager.getDefaultUserRoleName(tenantId);
final String bucketNamespacePolicyName =
OMMultiTenantManager.getDefaultBucketNamespacePolicyName(tenantId);
final String bucketPolicyName =
OMMultiTenantManager.getDefaultBucketPolicyName(tenantId);
// Add tenant entry in OM DB
if (populateDB) {
LOG.info("Creating OM DB tenant entries");
try {
// Tenant State entry
omMetadataManager.getTenantStateTable().put(tenantId,
new OmDBTenantState(
tenantId, volumeName, userRoleName, adminRoleName,
bucketNamespacePolicyName, bucketPolicyName));
// Access ID entry for alice
final String aliceAccessId = OMMultiTenantManager.getDefaultAccessId(
tenantId, USER_ALICE_SHORT);
omMetadataManager.getTenantAccessIdTable().put(aliceAccessId,
new OmDBAccessIdInfo.Builder()
.setTenantId(tenantId)
.setUserPrincipal(USER_ALICE_SHORT)
.setIsAdmin(false)
.setIsDelegatedAdmin(false)
.build());
// Access ID entry for bob
final String bobAccessId = OMMultiTenantManager.getDefaultAccessId(
tenantId, USER_BOB_SHORT);
omMetadataManager.getTenantAccessIdTable().put(bobAccessId,
new OmDBAccessIdInfo.Builder()
.setTenantId(tenantId)
.setUserPrincipal(USER_BOB_SHORT)
.setIsAdmin(false)
.setIsDelegatedAdmin(false)
.build());
} catch (IOException e) {
Assert.fail(e.getMessage());
}
}
try {
LOG.info("Creating user in Ranger: {}", USER_ALICE_SHORT);
rangerUserRequest.createUser(USER_ALICE_SHORT, "Password12");
usersCreated.add(USER_ALICE_SHORT);
} catch (IOException e) {
Assert.fail(e.getMessage());
}
try {
LOG.info("Creating user in Ranger: {}", USER_BOB_SHORT);
rangerUserRequest.createUser(USER_BOB_SHORT, "Password12");
usersCreated.add(USER_BOB_SHORT);
} catch (IOException e) {
Assert.fail(e.getMessage());
}
try {
LOG.info("Creating admin role in Ranger: {}", adminRoleName);
// Create empty admin role first
Role adminRole = new Role.Builder()
.setName(adminRoleName)
.setDescription(OZONE_TENANT_RANGER_ROLE_DESCRIPTION)
.build();
createRoleHelper(adminRole);
} catch (IOException e) {
Assert.fail(e.getMessage());
}
try {
LOG.info("Creating user role in Ranger: {}", userRoleName);
Role userRole = new Role.Builder()
.setName(userRoleName)
.setDescription(OZONE_TENANT_RANGER_ROLE_DESCRIPTION)
.addRole(adminRoleName, true)
// Add alice and bob to the user role
.addUsers(Arrays.asList(USER_ALICE_SHORT, USER_BOB_SHORT))
.build();
createRoleHelper(userRole);
} catch (IOException e) {
Assert.fail(e.getMessage());
}
try {
Policy tenant1VolumeAccessPolicy =
OMMultiTenantManager.getDefaultVolumeAccessPolicy(
tenantId, volumeName, userRoleName, adminRoleName);
LOG.info("Creating VolumeAccess policy in Ranger: {}",
tenant1VolumeAccessPolicy.getName());
accessController.createPolicy(tenant1VolumeAccessPolicy);
policiesCreated.add(tenant1VolumeAccessPolicy.getName());
} catch (IOException e) {
Assert.fail(e.getMessage());
}
try {
Policy tenant1BucketCreatePolicy =
OMMultiTenantManager.getDefaultBucketAccessPolicy(
tenantId, volumeName, userRoleName);
LOG.info("Creating BucketAccess policy in Ranger: {}",
tenant1BucketCreatePolicy.getName());
accessController.createPolicy(tenant1BucketCreatePolicy);
policiesCreated.add(tenant1BucketCreatePolicy.getName());
} catch (IOException e) {
Assert.fail(e.getMessage());
}
}
public void cleanupPolicies() {
for (String policyName : policiesCreated) {
try {
LOG.info("Deleting policy: {}", policyName);
accessController.deletePolicy(policyName);
} catch (Exception e) {
LOG.error(e.getMessage());
}
}
}
public void cleanupRoles() {
for (String roleName : rolesCreated) {
try {
LOG.info("Deleting role: {}", roleName);
accessController.deleteRole(roleName);
} catch (Exception e) {
LOG.error(e.getMessage());
}
}
}
public void cleanupUsers() {
for (String user : usersCreated) {
try {
LOG.info("Deleting user: {}", user);
String userId = rangerUserRequest.getUserId(user);
rangerUserRequest.deleteUser(userId);
} catch (Exception e) {
LOG.error(e.getMessage());
}
}
}
public void cleanupOMDB() {
try {
omMetadataManager.getTenantStateTable().delete(TENANT_ID);
omMetadataManager.getTenantAccessIdTable().delete(
OMMultiTenantManager.getDefaultAccessId(TENANT_ID, USER_ALICE_SHORT));
omMetadataManager.getTenantAccessIdTable().delete(
OMMultiTenantManager.getDefaultAccessId(TENANT_ID, USER_BOB_SHORT));
} catch (IOException e) {
LOG.error(e.getMessage());
}
}
public void cleanupPoliciesRolesUsers() {
cleanupPolicies();
cleanupRoles();
cleanupUsers();
cleanupOMDB();
}
/**
* OM DB does not have the tenant state.
* Expect sync service to clean up all the leftover multi-tenancy
* policies and roles in Ranger.
*/
@Test
public void testRemovePolicyAndRole() throws Exception {
long startingRangerVersion = initBGSync();
// Create roles and policies in ranger that are NOT
// backed up by OzoneManger Multi-Tenant tables
createRolesAndPoliciesInRanger(false);
final long rangerSvcVersionBefore =
bgSync.getRangerOzoneServicePolicyVersion();
Assert.assertTrue(rangerSvcVersionBefore >= startingRangerVersion);
// Note: DB Service Version will be -1 if the test starts with an empty DB
final long dbSvcVersionBefore = bgSync.getOMDBRangerServiceVersion();
bgSync.start();
// Wait for sync to finish once.
// The counter is incremented at the beginning of the run, hence the ">"
GenericTestUtils.waitFor(() -> bgSync.getRangerSyncRunCount() > 1L,
CHECK_SYNC_MILLIS, WAIT_SYNC_TIMEOUT_MILLIS);
bgSync.shutdown();
final long dbSvcVersionAfter = bgSync.getOMDBRangerServiceVersion();
final long rangerSvcVersionAfter =
bgSync.getRangerOzoneServicePolicyVersion();
Assert.assertEquals(rangerSvcVersionAfter, dbSvcVersionAfter);
Assert.assertTrue(dbSvcVersionAfter > dbSvcVersionBefore);
Assert.assertTrue(rangerSvcVersionAfter > rangerSvcVersionBefore);
// Verify that the Ranger policies and roles not backed up
// by OzoneManager Multi-Tenancy tables are cleaned up by sync thread
for (String policy : policiesCreated) {
try {
final Policy policyRead = accessController.getPolicy(policy);
Assert.fail("The policy should have been deleted: " + policyRead);
} catch (IOException ex) {
if (!(ex.getCause() instanceof RangerServiceException)) {
Assert.fail("Expected RangerServiceException, got " +
ex.getCause().getClass().getSimpleName());
}
RangerServiceException rse = (RangerServiceException) ex.getCause();
Assert.assertEquals(404, rse.getStatus().getStatusCode());
}
}
for (String roleName : rolesCreated) {
try {
final Role role = accessController.getRole(roleName);
Assert.fail("This role should have been deleted from Ranger: " + role);
} catch (IOException ex) {
if (!(ex.getCause() instanceof RangerServiceException)) {
Assert.fail("Expected RangerServiceException, got " +
ex.getCause().getClass().getSimpleName());
}
RangerServiceException rse = (RangerServiceException) ex.getCause();
Assert.assertEquals(400, rse.getStatus().getStatusCode());
}
}
}
/**
* OM DB has the tenant state.
* Ranger has the consistent role status, and the policies are in-place.
* Expect sync service to check Ranger state but write nothing to Ranger.
*/
@Test
public void testConsistentState() throws Exception {
long startingRangerVersion = initBGSync();
// Create roles and policies in ranger that are
// backed up by OzoneManger Multi-Tenant tables
createRolesAndPoliciesInRanger(true);
long rangerSvcVersionBefore = bgSync.getRangerOzoneServicePolicyVersion();
Assert.assertTrue(rangerSvcVersionBefore >= startingRangerVersion);
// Note: DB Service Version will be -1 if the test starts with an empty DB
final long dbSvcVersionBefore = bgSync.getOMDBRangerServiceVersion();
bgSync.start();
// Wait for sync to finish once.
// The counter is incremented at the beginning of the run, hence the ">"
GenericTestUtils.waitFor(() -> bgSync.getRangerSyncRunCount() > 1L,
CHECK_SYNC_MILLIS, WAIT_SYNC_TIMEOUT_MILLIS);
bgSync.shutdown();
final long dbSvcVersionAfter = bgSync.getOMDBRangerServiceVersion();
final long rangerSvcVersionAfter =
bgSync.getRangerOzoneServicePolicyVersion();
Assert.assertEquals(rangerSvcVersionAfter, dbSvcVersionAfter);
Assert.assertEquals(rangerSvcVersionAfter, rangerSvcVersionBefore);
if (dbSvcVersionBefore != -1L) {
Assert.assertEquals(dbSvcVersionBefore, dbSvcVersionAfter);
}
for (String policyName : policiesCreated) {
try {
final Policy policyRead = accessController.getPolicy(policyName);
Assert.assertEquals(policyName, policyRead.getName());
} catch (Exception e) {
e.printStackTrace();
Assert.fail(e.getMessage());
}
}
for (String roleName : rolesCreated) {
try {
final Role roleResponse = accessController.getRole(roleName);
Assert.assertEquals(roleName, roleResponse.getName());
} catch (Exception e) {
e.printStackTrace();
Assert.fail(e.getMessage());
}
}
}
/**
* OM DB has the tenant state.
* But the user list in a Ranger role is tampered with.
* Expect sync service to restore that Ranger role to the desired state.
*/
@Test
public void testRecoverRangerRole() throws Exception {
long startingRangerVersion = initBGSync();
createRolesAndPoliciesInRanger(true);
long rangerVersionAfterCreation =
bgSync.getRangerOzoneServicePolicyVersion();
Assert.assertTrue(rangerVersionAfterCreation >= startingRangerVersion);
// Delete user bob from user role, expect Ranger sync thread to update it
String userRoleName = rolesCreated.get(0);
Assert.assertEquals(
OMMultiTenantManager.getDefaultUserRoleName(TENANT_ID), userRoleName);
Role userRole = accessController.getRole(userRoleName);
// Remove user from role
Role updatedRole = new Role.Builder(userRole)
.removeUser(USER_BOB_SHORT)
.build();
accessController.updateRole(userRole.getId().get(), updatedRole);
HashSet<String> userSet = new HashSet<>();
userSet.add(USER_ALICE_SHORT);
userSet.add(USER_BOB_SHORT);
// Note: DB Service Version will be -1 if the test starts with an empty DB
final long dbSvcVersionBefore = bgSync.getOMDBRangerServiceVersion();
final long rangerSvcVersionBefore =
bgSync.getRangerOzoneServicePolicyVersion();
final long currRunCount = bgSync.getRangerSyncRunCount();
bgSync.start();
// Wait for sync to finish once.
// The counter is incremented at the beginning of the run, hence the ">"
GenericTestUtils.waitFor(
() -> bgSync.getRangerSyncRunCount() > currRunCount + 1L,
CHECK_SYNC_MILLIS, WAIT_SYNC_TIMEOUT_MILLIS);
bgSync.shutdown();
final long dbSvcVersionAfter = bgSync.getOMDBRangerServiceVersion();
final long rangerSvcVersionAfter =
bgSync.getRangerOzoneServicePolicyVersion();
Assert.assertEquals(rangerSvcVersionAfter, dbSvcVersionAfter);
Assert.assertTrue(dbSvcVersionAfter > dbSvcVersionBefore);
Assert.assertTrue(rangerSvcVersionAfter > rangerSvcVersionBefore);
for (String policyName : policiesCreated) {
final Policy policy = accessController.getPolicy(policyName);
Assert.assertNotNull("Policy should exist in Ranger: " + policyName,
policy);
Assert.assertEquals(policyName, policy.getName());
}
for (String roleName : rolesCreated) {
if (!roleName.equals(userRoleName)) {
continue;
}
final Role roleRead = accessController.getRole(roleName);
final Set<String> usersGot = roleRead.getUsersMap().keySet();
Assert.assertEquals(userSet, usersGot);
break;
}
}
/**
* OM DB has the tenant state. But tenant policies are deleted from Ranger.
* Expect sync service to recover both policies to their default states.
*/
@Test
public void testRecreateDeletedRangerPolicy() throws Exception {
long startingRangerVersion = initBGSync();
// Create roles and policies in ranger that are
// backed up by OzoneManger Multi-Tenant tables
createRolesAndPoliciesInRanger(true);
long rangerVersionAfterCreation =
bgSync.getRangerOzoneServicePolicyVersion();
Assert.assertTrue(rangerVersionAfterCreation >= startingRangerVersion);
// Delete both policies, expect Ranger sync thread to recover both
accessController.deletePolicy(
OMMultiTenantManager.getDefaultBucketNamespacePolicyName(TENANT_ID));
accessController.deletePolicy(
OMMultiTenantManager.getDefaultBucketPolicyName(TENANT_ID));
final long rangerSvcVersionBefore =
bgSync.getRangerOzoneServicePolicyVersion();
// Note: DB Service Version will be -1 if the test starts with an empty DB
final long dbSvcVersionBefore = bgSync.getOMDBRangerServiceVersion();
bgSync.start();
// Wait for sync to finish once.
// The counter is incremented at the beginning of the run, hence the ">"
GenericTestUtils.waitFor(() -> bgSync.getRangerSyncRunCount() > 1L,
CHECK_SYNC_MILLIS, WAIT_SYNC_TIMEOUT_MILLIS);
bgSync.shutdown();
long dbSvcVersionAfter = bgSync.getOMDBRangerServiceVersion();
final long rangerSvcVersionAfter =
bgSync.getRangerOzoneServicePolicyVersion();
Assert.assertEquals(rangerSvcVersionAfter, dbSvcVersionAfter);
Assert.assertTrue(dbSvcVersionAfter > dbSvcVersionBefore);
Assert.assertTrue(rangerSvcVersionAfter > rangerSvcVersionBefore);
for (String policyName : policiesCreated) {
try {
final Policy policyRead = accessController.getPolicy(policyName);
Assert.assertEquals(policyName, policyRead.getName());
} catch (Exception e) {
e.printStackTrace();
Assert.fail(e.getMessage());
}
}
for (String roleName : rolesCreated) {
try {
final Role roleRead = accessController.getRole(roleName);
Assert.assertEquals(roleName, roleRead.getName());
} catch (Exception e) {
e.printStackTrace();
Assert.fail(e.getMessage());
}
}
}
}