Skip to content

Commit

Permalink
[apache#4236] feat(core): Supports the post-hook for the managers or …
Browse files Browse the repository at this point in the history
…dispatcher (apache#4239)

### What changes were proposed in this pull request?
Supports the post-hook for the managers or dispatcher.
For example, after we create a securable object, we should set an owner
for it. We can add a specific post hook to support it.
This pull request uses Java dynamic proxy mechanism to support this
feature. We only support post-hook now, we can support pre-hook in the
future.

### Why are the changes needed?

Fix: apache#4236 

### Does this PR introduce _any_ user-facing change?
No.

### How was this patch tested?
Add a new ut.
  • Loading branch information
jerqi authored Jul 31, 2024
1 parent 4d8e0f3 commit 851c463
Show file tree
Hide file tree
Showing 18 changed files with 579 additions and 167 deletions.
57 changes: 45 additions & 12 deletions core/src/main/java/org/apache/gravitino/GravitinoEnv.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@
package org.apache.gravitino;

import com.google.common.base.Preconditions;
import org.apache.gravitino.authorization.AccessControlDispatcher;
import org.apache.gravitino.authorization.AccessControlManager;
import org.apache.gravitino.authorization.AuthorizationUtils;
import org.apache.gravitino.auxiliary.AuxiliaryServiceManager;
import org.apache.gravitino.catalog.CatalogDispatcher;
import org.apache.gravitino.catalog.CatalogManager;
Expand All @@ -39,6 +41,8 @@
import org.apache.gravitino.catalog.TopicDispatcher;
import org.apache.gravitino.catalog.TopicNormalizeDispatcher;
import org.apache.gravitino.catalog.TopicOperationDispatcher;
import org.apache.gravitino.hook.DispatcherHookHelper;
import org.apache.gravitino.hook.DispatcherHooks;
import org.apache.gravitino.listener.CatalogEventDispatcher;
import org.apache.gravitino.listener.EventBus;
import org.apache.gravitino.listener.EventListenerManager;
Expand Down Expand Up @@ -87,7 +91,7 @@ public class GravitinoEnv {

private MetalakeDispatcher metalakeDispatcher;

private AccessControlManager accessControlManager;
private AccessControlDispatcher accessControlDispatcher;

private IdGenerator idGenerator;

Expand Down Expand Up @@ -264,8 +268,8 @@ public LockManager lockManager() {
*
* @return The AccessControlManager instance.
*/
public AccessControlManager accessControlManager() {
return accessControlManager;
public AccessControlDispatcher accessControlDispatcher() {
return accessControlDispatcher;
}

/**
Expand Down Expand Up @@ -337,29 +341,33 @@ private void initGravitinoServerComponents() {
this.idGenerator = new RandomIdGenerator();

// Create and initialize metalake related modules
MetalakeManager metalakeManager = new MetalakeManager(entityStore, idGenerator);
MetalakeDispatcher metalakeManager = new MetalakeManager(entityStore, idGenerator);
MetalakeNormalizeDispatcher metalakeNormalizeDispatcher =
new MetalakeNormalizeDispatcher(metalakeManager);
new MetalakeNormalizeDispatcher(installDispatcherHooks(metalakeManager));
this.metalakeDispatcher = new MetalakeEventDispatcher(eventBus, metalakeNormalizeDispatcher);

// Create and initialize Catalog related modules
this.catalogManager = new CatalogManager(config, entityStore, idGenerator);
CatalogNormalizeDispatcher catalogNormalizeDispatcher =
new CatalogNormalizeDispatcher(catalogManager);
new CatalogNormalizeDispatcher(installDispatcherHooks((CatalogDispatcher) catalogManager));
this.catalogDispatcher = new CatalogEventDispatcher(eventBus, catalogNormalizeDispatcher);

SchemaOperationDispatcher schemaOperationDispatcher =
new SchemaOperationDispatcher(catalogManager, entityStore, idGenerator);
SchemaNormalizeDispatcher schemaNormalizeDispatcher =
new SchemaNormalizeDispatcher(schemaOperationDispatcher, catalogManager);
new SchemaNormalizeDispatcher(
installDispatcherHooks((SchemaDispatcher) schemaOperationDispatcher), catalogManager);
this.schemaDispatcher = new SchemaEventDispatcher(eventBus, schemaNormalizeDispatcher);

TableOperationDispatcher tableOperationDispatcher =
new TableOperationDispatcher(catalogManager, entityStore, idGenerator);
TableNormalizeDispatcher tableNormalizeDispatcher =
new TableNormalizeDispatcher(tableOperationDispatcher, catalogManager);
new TableNormalizeDispatcher(
installDispatcherHooks((TableDispatcher) tableOperationDispatcher), catalogManager);
this.tableDispatcher = new TableEventDispatcher(eventBus, tableNormalizeDispatcher);

// TODO: We can install hooks when we need, we only supports ownership post hook,
// partition doesn't have ownership, so we don't need it now.
PartitionOperationDispatcher partitionOperationDispatcher =
new PartitionOperationDispatcher(catalogManager, entityStore, idGenerator);
PartitionNormalizeDispatcher partitionNormalizeDispatcher =
Expand All @@ -369,21 +377,25 @@ private void initGravitinoServerComponents() {
FilesetOperationDispatcher filesetOperationDispatcher =
new FilesetOperationDispatcher(catalogManager, entityStore, idGenerator);
FilesetNormalizeDispatcher filesetNormalizeDispatcher =
new FilesetNormalizeDispatcher(filesetOperationDispatcher, catalogManager);
new FilesetNormalizeDispatcher(
installDispatcherHooks((FilesetDispatcher) filesetOperationDispatcher), catalogManager);
this.filesetDispatcher = new FilesetEventDispatcher(eventBus, filesetNormalizeDispatcher);

TopicOperationDispatcher topicOperationDispatcher =
new TopicOperationDispatcher(catalogManager, entityStore, idGenerator);
TopicNormalizeDispatcher topicNormalizeDispatcher =
new TopicNormalizeDispatcher(topicOperationDispatcher, catalogManager);
new TopicNormalizeDispatcher(
installDispatcherHooks((TopicDispatcher) topicOperationDispatcher), catalogManager);
this.topicDispatcher = new TopicEventDispatcher(eventBus, topicNormalizeDispatcher);

// Create and initialize access control related modules
boolean enableAuthorization = config.get(Configs.ENABLE_AUTHORIZATION);
if (enableAuthorization) {
this.accessControlManager = new AccessControlManager(entityStore, idGenerator, config);
this.accessControlDispatcher =
installDispatcherHooks(
(AccessControlDispatcher) new AccessControlManager(entityStore, idGenerator, config));
} else {
this.accessControlManager = null;
this.accessControlDispatcher = null;
}

this.auxServiceManager = new AuxiliaryServiceManager();
Expand All @@ -395,4 +407,25 @@ private void initGravitinoServerComponents() {
// Tag manager
this.tagManager = new TagManager(idGenerator, entityStore);
}

// Provides a universal entrance to install dispatcher hooks. This method
// focuses the logic of installing hooks.
// We should reuse the ability of (Metalake|Schema|Table|Fileset|...)NormalizeDispatcher to avoid
// solving
// normalization names, this is useful for pre-hooks.
// so we can't install the hooks for the outside of
// (Metalake|Schema|Table|Fileset|...)NormalizeDispatcher.
private <T> T installDispatcherHooks(T manager) {
boolean enableAuthorization = config.get(Configs.ENABLE_AUTHORIZATION);
DispatcherHooks hooks = new DispatcherHooks();
if (enableAuthorization) {
AuthorizationUtils.prepareAuthorizationHooks(manager, hooks);
}

if (hooks.isEmpty()) {
return manager;
}

return DispatcherHookHelper.installHooks(manager, hooks);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,222 @@
/*
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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.gravitino.authorization;

import java.util.List;
import java.util.Map;
import org.apache.gravitino.exceptions.GroupAlreadyExistsException;
import org.apache.gravitino.exceptions.NoSuchGroupException;
import org.apache.gravitino.exceptions.NoSuchMetalakeException;
import org.apache.gravitino.exceptions.NoSuchRoleException;
import org.apache.gravitino.exceptions.NoSuchUserException;
import org.apache.gravitino.exceptions.RoleAlreadyExistsException;
import org.apache.gravitino.exceptions.UserAlreadyExistsException;

/**
* This interface is related to the access control. This interface is mainly used for
* LifecycleHooks. The lifecycleHooks used the InvocationHandler. The InvocationHandler can only
* hook the interfaces.
*/
public interface AccessControlDispatcher {
/**
* Adds a new User.
*
* @param metalake The Metalake of the User.
* @param user The name of the User.
* @return The added User instance.
* @throws UserAlreadyExistsException If a User with the same name already exists.
* @throws NoSuchMetalakeException If the Metalake with the given name does not exist.
* @throws RuntimeException If adding the User encounters storage issues.
*/
User addUser(String metalake, String user)
throws UserAlreadyExistsException, NoSuchMetalakeException;

/**
* Removes a User.
*
* @param metalake The Metalake of the User.
* @param user The name of the User.
* @return True if the User was successfully removed, false only when there's no such user,
* otherwise it will throw an exception.
* @throws NoSuchMetalakeException If the Metalake with the given name does not exist.
* @throws RuntimeException If removing the User encounters storage issues.
*/
boolean removeUser(String metalake, String user) throws NoSuchMetalakeException;

/**
* Gets a User.
*
* @param metalake The Metalake of the User.
* @param user The name of the User.
* @return The getting User instance.
* @throws NoSuchUserException If the User with the given name does not exist.
* @throws NoSuchMetalakeException If the Metalake with the given name does not exist.
* @throws RuntimeException If getting the User encounters storage issues.
*/
User getUser(String metalake, String user) throws NoSuchUserException, NoSuchMetalakeException;

/**
* Adds a new Group.
*
* @param metalake The Metalake of the Group.
* @param group The name of the Group.
* @return The Added Group instance.
* @throws GroupAlreadyExistsException If a Group with the same name already exists.
* @throws NoSuchMetalakeException If the Metalake with the given name does not exist.
* @throws RuntimeException If adding the Group encounters storage issues.
*/
Group addGroup(String metalake, String group)
throws GroupAlreadyExistsException, NoSuchMetalakeException;

/**
* Removes a Group.
*
* @param metalake The Metalake of the Group.
* @param group THe name of the Group.
* @return True if the Group was successfully removed, false only when there's no such group,
* otherwise it will throw an exception.
* @throws NoSuchMetalakeException If the Metalake with the given name does not exist.
* @throws RuntimeException If removing the Group encounters storage issues.
*/
boolean removeGroup(String metalake, String group) throws NoSuchMetalakeException;

/**
* Gets a Group.
*
* @param metalake The Metalake of the Group.
* @param group The name of the Group.
* @return The getting Group instance.
* @throws NoSuchGroupException If the Group with the given name does not exist.
* @throws NoSuchMetalakeException If the Metalake with the given name does not exist.
* @throws RuntimeException If getting the Group encounters storage issues.
*/
Group getGroup(String metalake, String group)
throws NoSuchGroupException, NoSuchMetalakeException;

/**
* Grant roles to a user.
*
* @param metalake The metalake of the User.
* @param user The name of the User.
* @param roles The names of the Role.
* @return The User after granted.
* @throws NoSuchUserException If the User with the given name does not exist.
* @throws NoSuchRoleException If the Role with the given name does not exist.
* @throws NoSuchMetalakeException If the Metalake with the given name does not exist.
* @throws RuntimeException If granting roles to a user encounters storage issues.
*/
User grantRolesToUser(String metalake, List<String> roles, String user)
throws NoSuchUserException, NoSuchRoleException, NoSuchMetalakeException;

/**
* Grant roles to a group.
*
* @param metalake The metalake of the Group.
* @param group The name of the Group.
* @param roles The names of the Role.
* @return The Group after granted.
* @throws NoSuchGroupException If the Group with the given name does not exist.
* @throws NoSuchRoleException If the Role with the given name does not exist.
* @throws NoSuchMetalakeException If the Metalake with the given name does not exist.
* @throws RuntimeException If granting roles to a group encounters storage issues.
*/
Group grantRolesToGroup(String metalake, List<String> roles, String group)
throws NoSuchGroupException, NoSuchRoleException, NoSuchMetalakeException;

/**
* Revoke roles from a group.
*
* @param metalake The metalake of the Group.
* @param group The name of the Group.
* @param roles The name of the Role.
* @return The Group after revoked.
* @throws NoSuchGroupException If the Group with the given name does not exist.
* @throws NoSuchRoleException If the Role with the given name does not exist.
* @throws NoSuchMetalakeException If the Metalake with the given name does not exist.
* @throws RuntimeException If revoking roles from a group encounters storage issues.
*/
Group revokeRolesFromGroup(String metalake, List<String> roles, String group)
throws NoSuchGroupException, NoSuchRoleException, NoSuchMetalakeException;

/**
* Revoke roles from a user.
*
* @param metalake The metalake of the User.
* @param user The name of the User.
* @param roles The name of the Role.
* @return The User after revoked.
* @throws NoSuchUserException If the User with the given name does not exist.
* @throws NoSuchRoleException If the Role with the given name does not exist.
* @throws NoSuchMetalakeException If the Metalake with the given name does not exist.
* @throws RuntimeException If revoking roles from a user encounters storage issues.
*/
User revokeRolesFromUser(String metalake, List<String> roles, String user)
throws NoSuchUserException, NoSuchRoleException, NoSuchMetalakeException;

/**
* Judges whether the user is the service admin.
*
* @param user the name of the user
* @return True if the user is service admin, otherwise false.
*/
boolean isServiceAdmin(String user);

/**
* Creates a new Role.
*
* @param metalake The Metalake of the Role.
* @param role The name of the Role.
* @param properties The properties of the Role.
* @param securableObjects The securable objects of the Role.
* @return The created Role instance.
* @throws RoleAlreadyExistsException If a Role with the same name already exists.
* @throws NoSuchMetalakeException If the Metalake with the given name does not exist.
* @throws RuntimeException If creating the Role encounters storage issues.
*/
Role createRole(
String metalake,
String role,
Map<String, String> properties,
List<SecurableObject> securableObjects)
throws RoleAlreadyExistsException, NoSuchMetalakeException;

/**
* Gets a Role.
*
* @param metalake The Metalake of the Role.
* @param role The name of the Role.
* @return The getting Role instance.
* @throws NoSuchRoleException If the Role with the given name does not exist.
* @throws NoSuchMetalakeException If the Metalake with the given name does not exist.
* @throws RuntimeException If getting the Role encounters storage issues.
*/
Role getRole(String metalake, String role) throws NoSuchRoleException, NoSuchMetalakeException;

/**
* Deletes a Role.
*
* @param metalake The Metalake of the Role.
* @param role The name of the Role.
* @return True if the Role was successfully deleted, false only when there's no such role,
* otherwise it will throw an exception.
* @throws NoSuchMetalakeException If the Metalake with the given name does not exist.
* @throws RuntimeException If deleting the Role encounters storage issues.
*/
public boolean deleteRole(String metalake, String role) throws NoSuchMetalakeException;
}
Loading

0 comments on commit 851c463

Please sign in to comment.