blob: 2334829601bff8ae2678195c2dc3e364801531d5 [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.multitenant.AccessPolicy.AccessGrantType.ALLOW;
import static org.apache.hadoop.ozone.security.acl.IAccessAuthorizer.ACLType.ALL;
import static org.apache.hadoop.ozone.security.acl.IAccessAuthorizer.ACLType.CREATE;
import static org.apache.hadoop.ozone.security.acl.IAccessAuthorizer.ACLType.LIST;
import static org.apache.hadoop.ozone.security.acl.IAccessAuthorizer.ACLType.READ;
import static org.apache.hadoop.ozone.security.acl.IAccessAuthorizer.ACLType.READ_ACL;
import static org.apache.hadoop.ozone.security.acl.OzoneObj.ResourceType.BUCKET;
import static org.apache.hadoop.ozone.security.acl.OzoneObj.ResourceType.VOLUME;
import static org.apache.hadoop.ozone.security.acl.OzoneObj.StoreType.OZONE;
import static org.apache.hadoop.security.authentication.util.KerberosName.DEFAULT_MECHANISM;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
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.HashSet;
import java.util.List;
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.ratis.OzoneManagerRatisServer;
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OMRequest;
import org.apache.hadoop.ozone.security.acl.OzoneObjInfo;
import org.apache.hadoop.security.UserGroupInformation;
import org.apache.hadoop.security.authentication.util.KerberosName;
import org.apache.ozone.test.GenericTestUtils;
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 com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
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 MultiTenantAccessAuthorizer auth;
private OMRangerBGSyncService bgSync;
// List of policy names created in Ranger
private final List<String> policiesCreated = new ArrayList<>();
// List of role ID created in Ranger
private final List<String> rolesCreated = new ArrayList<>();
// List of users created in Ranger
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 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.setStrings(OZONE_RANGER_HTTPS_ADDRESS_KEY,
System.getProperty(OZONE_RANGER_HTTPS_ADDRESS_KEY));
conf.setStrings(OZONE_OM_RANGER_HTTPS_ADMIN_API_USER,
System.getProperty(OZONE_OM_RANGER_HTTPS_ADMIN_API_USER));
conf.setStrings(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(
MultiTenantAccessAuthorizerRangerPlugin.LOG, 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.newDefaultVolumeAccessPolicy(eq(TENANT_ID),
Mockito.any(OzoneTenantRolePrincipal.class),
Mockito.any(OzoneTenantRolePrincipal.class)))
.thenReturn(newVolumeAccessPolicy(TENANT_ID, TENANT_ID));
when(omMultiTenantManager.newDefaultBucketAccessPolicy(eq(TENANT_ID),
Mockito.any(OzoneTenantRolePrincipal.class)))
.thenReturn(newBucketAccessPolicy(TENANT_ID, 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<>());
auth = new MultiTenantAccessAuthorizerRangerPlugin();
auth.init(conf);
}
@After
public void tearDown() {
bgSync.shutdown();
cleanupPoliciesRolesUsers();
omMetrics.unRegister();
framework().clearInlineMocks();
}
private AccessPolicy newVolumeAccessPolicy(String vol, String tenantId)
throws IOException {
OzoneTenantRolePrincipal principal = new OzoneTenantRolePrincipal(
OMMultiTenantManager.getDefaultUserRoleName(tenantId));
OzoneTenantRolePrincipal adminRole = new OzoneTenantRolePrincipal(
OMMultiTenantManager.getDefaultAdminRoleName(tenantId));
AccessPolicy tenantVolumeAccessPolicy = new RangerAccessPolicy(
OMMultiTenantManager.getDefaultBucketNamespacePolicyName(tenantId));
OzoneObjInfo obj = OzoneObjInfo.Builder.newBuilder()
.setResType(VOLUME).setStoreType(OZONE).setVolumeName(vol)
.setBucketName("").setKeyName("").build();
tenantVolumeAccessPolicy.addAccessPolicyElem(obj, principal, READ, ALLOW);
tenantVolumeAccessPolicy.addAccessPolicyElem(obj, principal, LIST, ALLOW);
tenantVolumeAccessPolicy.addAccessPolicyElem(obj, principal,
READ_ACL, ALLOW);
tenantVolumeAccessPolicy.addAccessPolicyElem(obj, adminRole, ALL, ALLOW);
return tenantVolumeAccessPolicy;
}
private AccessPolicy newBucketAccessPolicy(String vol, String tenantId)
throws IOException {
OzoneTenantRolePrincipal principal = new OzoneTenantRolePrincipal(
OMMultiTenantManager.getDefaultUserRoleName(tenantId));
AccessPolicy tenantVolumeAccessPolicy = new RangerAccessPolicy(
OMMultiTenantManager.getDefaultBucketPolicyName(tenantId));
OzoneObjInfo obj = OzoneObjInfo.Builder.newBuilder()
.setResType(BUCKET).setStoreType(OZONE).setVolumeName(vol)
.setBucketName("*").setKeyName("").build();
tenantVolumeAccessPolicy.addAccessPolicyElem(obj, principal, CREATE, ALLOW);
return tenantVolumeAccessPolicy;
}
long initBGSync() throws IOException {
bgSync = new OMRangerBGSyncService(ozoneManager,
ozoneManager.getMultiTenantManager(), auth,
TEST_SYNC_INTERVAL_SEC, TimeUnit.SECONDS, TEST_SYNC_TIMEOUT_SEC);
return bgSync.getLatestRangerServiceVersion();
}
public 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 OzoneTenantRolePrincipal adminRole = new OzoneTenantRolePrincipal(
OMMultiTenantManager.getDefaultAdminRoleName(tenantId));
final OzoneTenantRolePrincipal userRole = new OzoneTenantRolePrincipal(
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, userRole.getName(), adminRole.getName(),
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 admin role in Ranger: {}", adminRole.getName());
auth.createRole(adminRole.getName(), null);
String role1 = auth.getRole(adminRole);
rolesCreated.add(0, role1);
} catch (Exception e) {
Assert.fail(e.getMessage());
}
try {
LOG.info("Creating user role in Ranger: {}", userRole.getName());
auth.createRole(userRole.getName(), adminRole.getName());
String role2 = auth.getRole(userRole);
// Prepend user role (order matters when deleting due to dependency)
rolesCreated.add(0, role2);
} catch (Exception e) {
Assert.fail(e.getMessage());
}
try {
LOG.info("Creating user in Ranger: {}", USER_ALICE_SHORT);
auth.createUser(USER_ALICE_SHORT, "password1");
usersCreated.add(USER_ALICE_SHORT);
auth.assignUserToRole(USER_ALICE_SHORT, auth.getRole(userRole), false);
} catch (Exception e) {
Assert.fail(e.getMessage());
}
try {
LOG.info("Creating user in Ranger: {}", USER_BOB_SHORT);
auth.createUser(USER_BOB_SHORT, "password2");
usersCreated.add(USER_BOB_SHORT);
auth.assignUserToRole(USER_BOB_SHORT, auth.getRole(userRole), false);
} catch (Exception e) {
Assert.fail(e.getMessage());
}
try {
AccessPolicy tenant1VolumeAccessPolicy = newVolumeAccessPolicy(
volumeName, tenantId);
LOG.info("Creating VolumeAccess policy in Ranger: {}",
tenant1VolumeAccessPolicy.getPolicyName());
auth.createAccessPolicy(tenant1VolumeAccessPolicy);
policiesCreated.add(tenant1VolumeAccessPolicy.getPolicyName());
} catch (Exception e) {
Assert.fail(e.getMessage());
}
try {
AccessPolicy tenant1BucketCreatePolicy = newBucketAccessPolicy(
volumeName, tenantId);
LOG.info("Creating BucketAccess policy in Ranger: {}",
tenant1BucketCreatePolicy.getPolicyName());
auth.createAccessPolicy(tenant1BucketCreatePolicy);
policiesCreated.add(tenant1BucketCreatePolicy.getPolicyName());
} catch (Exception e) {
Assert.fail(e.getMessage());
}
}
public void cleanupPolicies() {
for (String name : policiesCreated) {
try {
LOG.info("Deleting policy: {}", name);
auth.deletePolicyByName(name);
} catch (Exception e) {
LOG.error(e.getMessage());
}
}
}
public void cleanupRoles() {
for (String roleObj : rolesCreated) {
final JsonObject jObj = new JsonParser().parse(roleObj).getAsJsonObject();
final String roleId = jObj.get("id").getAsString();
final String roleName = jObj.get("name").getAsString();
try {
LOG.info("Deleting role: {}", roleName);
auth.deleteRoleById(roleId);
} catch (Exception e) {
LOG.error(e.getMessage());
}
}
}
public void cleanupUsers() {
for (String user : usersCreated) {
try {
LOG.info("Deleting user: {}", user);
String userId = auth.getUserId(user);
auth.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.getLatestRangerServiceVersion();
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.getLatestRangerServiceVersion();
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) {
final AccessPolicy policyRead = auth.getAccessPolicyByName(policy);
Assert.assertNull("This policy should have been deleted from Ranger: " +
policy, policyRead);
}
for (String roleObj : rolesCreated) {
final String roleName = new JsonParser().parse(roleObj)
.getAsJsonObject().get("name").getAsString();
final String roleObjRead = auth.getRole(roleName);
Assert.assertNull("This role should have been deleted from Ranger: " +
roleName, roleObjRead);
}
}
/**
* 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.getLatestRangerServiceVersion();
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.getLatestRangerServiceVersion();
Assert.assertEquals(rangerSvcVersionAfter, dbSvcVersionAfter);
Assert.assertEquals(rangerSvcVersionAfter, rangerSvcVersionBefore);
if (dbSvcVersionBefore != -1L) {
Assert.assertEquals(dbSvcVersionBefore, dbSvcVersionAfter);
}
for (String policy : policiesCreated) {
try {
final AccessPolicy policyRead = auth.getAccessPolicyByName(policy);
Assert.assertEquals(policy, policyRead.getPolicyName());
} catch (Exception e) {
e.printStackTrace();
Assert.fail(e.getMessage());
}
}
for (String roleObj : rolesCreated) {
try {
final String roleName = new JsonParser().parse(roleObj)
.getAsJsonObject().get("name").getAsString();
String roleObjRead = auth.getRole(roleName);
final String roleNameReadBack = new JsonParser().parse(roleObjRead)
.getAsJsonObject().get("name").getAsString();
Assert.assertEquals(roleName, roleNameReadBack);
} 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.getLatestRangerServiceVersion();
Assert.assertTrue(rangerVersionAfterCreation >= startingRangerVersion);
// Delete a user from user role, expect Ranger sync thread to update it
String userRoleName = new JsonParser().parse(rolesCreated.get(0))
.getAsJsonObject().get("name").getAsString();
Assert.assertEquals(
OMMultiTenantManager.getDefaultUserRoleName(TENANT_ID), userRoleName);
auth.revokeUserFromRole(USER_BOB_SHORT, auth.getRole(userRoleName));
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.getLatestRangerServiceVersion();
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.getLatestRangerServiceVersion();
Assert.assertEquals(rangerSvcVersionAfter, dbSvcVersionAfter);
Assert.assertTrue(dbSvcVersionAfter > dbSvcVersionBefore);
Assert.assertTrue(rangerSvcVersionAfter > rangerSvcVersionBefore);
for (String policy : policiesCreated) {
final AccessPolicy verifier = auth.getAccessPolicyByName(policy);
Assert.assertNotNull("Policy should exist in Ranger: " + policy,
verifier);
Assert.assertEquals(policy, verifier.getPolicyName());
}
for (String role : rolesCreated) {
final String roleName = new JsonParser().parse(role).getAsJsonObject()
.get("name").getAsString();
if (!roleName.equals(userRoleName)) {
continue;
}
final String roleObjRead = auth.getRole(roleName);
final JsonObject jsonObj = new JsonParser().parse(roleObjRead)
.getAsJsonObject();
final JsonArray verifier = jsonObj.get("users").getAsJsonArray();
Assert.assertEquals(2, verifier.size());
// Verify that users are in the role
for (int i = 0; i < verifier.size(); ++i) {
String user = verifier.get(i).getAsJsonObject()
.get("name").getAsString();
Assert.assertTrue(userSet.contains(user));
userSet.remove(user);
}
Assert.assertTrue(userSet.isEmpty());
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.getLatestRangerServiceVersion();
Assert.assertTrue(rangerVersionAfterCreation >= startingRangerVersion);
// Delete both policies, expect Ranger sync thread to recover both
auth.deletePolicyByName(
OMMultiTenantManager.getDefaultBucketNamespacePolicyName(TENANT_ID));
auth.deletePolicyByName(
OMMultiTenantManager.getDefaultBucketPolicyName(TENANT_ID));
final long rangerSvcVersionBefore = bgSync.getLatestRangerServiceVersion();
// 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.getLatestRangerServiceVersion();
Assert.assertEquals(rangerSvcVersionAfter, dbSvcVersionAfter);
Assert.assertTrue(dbSvcVersionAfter > dbSvcVersionBefore);
Assert.assertTrue(rangerSvcVersionAfter > rangerSvcVersionBefore);
for (String policy : policiesCreated) {
try {
final AccessPolicy policyRead = auth.getAccessPolicyByName(policy);
Assert.assertEquals(policy, policyRead.getPolicyName());
} catch (Exception e) {
e.printStackTrace();
Assert.fail(e.getMessage());
}
}
for (String roleObj : rolesCreated) {
try {
final String roleName = new JsonParser().parse(roleObj)
.getAsJsonObject().get("name").getAsString();
String roleObjRead = auth.getRole(roleName);
final String roleNameReadBack = new JsonParser().parse(roleObjRead)
.getAsJsonObject().get("name").getAsString();
Assert.assertEquals(roleName, roleNameReadBack);
} catch (Exception e) {
e.printStackTrace();
Assert.fail(e.getMessage());
}
}
}
}