This is an automated email from the ASF dual-hosted git repository.
fanng pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/gravitino.git
The following commit(s) were added to refs/heads/main by this push:
new b6a61bafb5 [#6760] test(core): Support role failure event to Gravitino
server (#6866)
b6a61bafb5 is described below
commit b6a61bafb5d1e7f15c8336ac3e7d523dbdfd5831
Author: Lord of Abyss <[email protected]>
AuthorDate: Fri Apr 11 08:33:22 2025 +0800
[#6760] test(core): Support role failure event to Gravitino server (#6866)
### What changes were proposed in this pull request?
Support role failure event to Gravitino server
1. Support role failure event to Gravitino server
2. Refactor the `EventBus#dispatchEvent` method using the Visitor design
pattern to eliminate `instanceof` checks, improve extensibility, and
ensure that unhandled event types can be detected at compile time.
### Why are the changes needed?
Fix: #6760
### Does this PR introduce _any_ user-facing change?
No.
### How was this patch tested?
local test.
---
.../api/event/AccessControlEventDispatcher.java | 26 ++-
.../listener/api/event/CreateRoleFailureEvent.java | 66 +++++++
.../listener/api/event/DeleteRoleFailureEvent.java | 66 +++++++
.../listener/api/event/GetRoleFailureEvent.java | 65 +++++++
.../api/event/GrantPrivilegesFailureEvent.java | 100 ++++++++++
.../api/event/ListRoleNamesFailureEvent.java | 82 +++++++++
.../api/event/RevokePrivilegesFailureEvent.java | 99 ++++++++++
.../listener/api/event/RoleFailureEvent.java | 43 +++++
.../gravitino/listener/api/info/RoleInfo.java | 15 ++
.../listener/api/event/TestRoleEvent.java | 202 ++++++++++++++++++++-
docs/gravitino-server-config.md | 26 +--
11 files changed, 762 insertions(+), 28 deletions(-)
diff --git
a/core/src/main/java/org/apache/gravitino/listener/api/event/AccessControlEventDispatcher.java
b/core/src/main/java/org/apache/gravitino/listener/api/event/AccessControlEventDispatcher.java
index cd5d1613f3..cecf20de50 100644
---
a/core/src/main/java/org/apache/gravitino/listener/api/event/AccessControlEventDispatcher.java
+++
b/core/src/main/java/org/apache/gravitino/listener/api/event/AccessControlEventDispatcher.java
@@ -319,13 +319,7 @@ public class AccessControlEventDispatcher implements
AccessControlDispatcher {
/** {@inheritDoc} */
@Override
public boolean isServiceAdmin(String user) {
- try {
- // TODO: add Event
- return dispatcher.isServiceAdmin(user);
- } catch (Exception e) {
- // TODO: add failure event
- throw e;
- }
+ return dispatcher.isServiceAdmin(user);
}
/** {@inheritDoc} */
@@ -346,7 +340,9 @@ public class AccessControlEventDispatcher implements
AccessControlDispatcher {
return roleObject;
} catch (Exception e) {
- // TODO: add failure event
+ eventBus.dispatchEvent(
+ new CreateRoleFailureEvent(
+ initiator, metalake, e, new RoleInfo(role, properties,
securableObjects)));
throw e;
}
}
@@ -364,7 +360,7 @@ public class AccessControlEventDispatcher implements
AccessControlDispatcher {
return roleObject;
} catch (Exception e) {
- // TODO: add failure event
+ eventBus.dispatchEvent(new GetRoleFailureEvent(initiator, metalake, e,
role));
throw e;
}
}
@@ -381,7 +377,7 @@ public class AccessControlEventDispatcher implements
AccessControlDispatcher {
return isExists;
} catch (Exception e) {
- // TODO: add failure event
+ eventBus.dispatchEvent(new DeleteRoleFailureEvent(initiator, metalake,
e, role));
throw e;
}
}
@@ -398,7 +394,7 @@ public class AccessControlEventDispatcher implements
AccessControlDispatcher {
return roleNames;
} catch (Exception e) {
- // TODO: add failure event
+ eventBus.dispatchEvent(new ListRoleNamesFailureEvent(initiator,
metalake, e));
throw e;
}
}
@@ -416,7 +412,7 @@ public class AccessControlEventDispatcher implements
AccessControlDispatcher {
return roleNames;
} catch (Exception e) {
- // TODO: add failure event
+ eventBus.dispatchEvent(new ListRoleNamesFailureEvent(initiator,
metalake, e, object));
throw e;
}
}
@@ -438,7 +434,8 @@ public class AccessControlEventDispatcher implements
AccessControlDispatcher {
return roleObject;
} catch (Exception e) {
- // TODO: add failure event
+ eventBus.dispatchEvent(
+ new GrantPrivilegesFailureEvent(initiator, metalake, e, role,
object, privileges));
throw e;
}
}
@@ -460,7 +457,8 @@ public class AccessControlEventDispatcher implements
AccessControlDispatcher {
return roleObject;
} catch (Exception e) {
- // TODO: add failure event
+ eventBus.dispatchEvent(
+ new RevokePrivilegesFailureEvent(initiator, metalake, e, role,
object, privileges));
throw e;
}
}
diff --git
a/core/src/main/java/org/apache/gravitino/listener/api/event/CreateRoleFailureEvent.java
b/core/src/main/java/org/apache/gravitino/listener/api/event/CreateRoleFailureEvent.java
new file mode 100644
index 0000000000..d3080bed62
--- /dev/null
+++
b/core/src/main/java/org/apache/gravitino/listener/api/event/CreateRoleFailureEvent.java
@@ -0,0 +1,66 @@
+/*
+ * 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.listener.api.event;
+
+import org.apache.gravitino.annotation.DeveloperApi;
+import org.apache.gravitino.listener.api.info.RoleInfo;
+import org.apache.gravitino.utils.NameIdentifierUtil;
+
+/**
+ * Represents an event triggered when an attempt to create a role in a
metalake fails due to an
+ * exception.
+ */
+@DeveloperApi
+public class CreateRoleFailureEvent extends RoleFailureEvent {
+ private final RoleInfo createRoleRequest;
+ /**
+ * Constructs a new {@code CreateRoleFailureEvent} instance.
+ *
+ * @param initiator the user who initiated the event.
+ * @param metalake the target metalake context for the role creation
+ * @param exception the exception that caused the failure
+ * @param createRoleRequest the role information that failed to be created
+ */
+ public CreateRoleFailureEvent(
+ String initiator, String metalake, Exception exception, RoleInfo
createRoleRequest) {
+ super(initiator, NameIdentifierUtil.ofRole(metalake,
createRoleRequest.roleName()), exception);
+
+ this.createRoleRequest = createRoleRequest;
+ }
+
+ /**
+ * Returns the role information that failed to be created.
+ *
+ * @return The {@link RoleInfo} instance.
+ */
+ public RoleInfo createRoleRequest() {
+ return createRoleRequest;
+ }
+
+ /**
+ * Returns the operation type of this event.
+ *
+ * @return the operation type.
+ */
+ @Override
+ public OperationType operationType() {
+ return OperationType.CREATE_ROLE;
+ }
+}
diff --git
a/core/src/main/java/org/apache/gravitino/listener/api/event/DeleteRoleFailureEvent.java
b/core/src/main/java/org/apache/gravitino/listener/api/event/DeleteRoleFailureEvent.java
new file mode 100644
index 0000000000..a020030a2e
--- /dev/null
+++
b/core/src/main/java/org/apache/gravitino/listener/api/event/DeleteRoleFailureEvent.java
@@ -0,0 +1,66 @@
+/*
+ * 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.listener.api.event;
+
+import org.apache.gravitino.annotation.DeveloperApi;
+import org.apache.gravitino.utils.NameIdentifierUtil;
+
+/**
+ * Represents an event triggered when an attempt to delete a role from a
metalake fails due to an
+ * exception.
+ */
+@DeveloperApi
+public class DeleteRoleFailureEvent extends RoleFailureEvent {
+ private final String roleName;
+
+ /**
+ * Constructs a new {@code DeleteRoleFailureEvent} instance.
+ *
+ * @param user the user who initiated the deletion attempt
+ * @param metalake the target metalake from which the role is to be deleted
+ * @param exception the exception that caused the failure
+ * @param roleName the name of the role intended for deletion
+ */
+ protected DeleteRoleFailureEvent(
+ String user, String metalake, Exception exception, String roleName) {
+ super(user, NameIdentifierUtil.ofRole(metalake, roleName), exception);
+
+ this.roleName = roleName;
+ }
+
+ /**
+ * Returns the name of the role that was intended for deletion.
+ *
+ * @return the name of the role
+ */
+ public String roleName() {
+ return roleName;
+ }
+
+ /**
+ * Returns the operation type of this event.
+ *
+ * @return the operation type.
+ */
+ @Override
+ public OperationType operationType() {
+ return OperationType.DELETE_ROLE;
+ }
+}
diff --git
a/core/src/main/java/org/apache/gravitino/listener/api/event/GetRoleFailureEvent.java
b/core/src/main/java/org/apache/gravitino/listener/api/event/GetRoleFailureEvent.java
new file mode 100644
index 0000000000..87eb60ff74
--- /dev/null
+++
b/core/src/main/java/org/apache/gravitino/listener/api/event/GetRoleFailureEvent.java
@@ -0,0 +1,65 @@
+/*
+ * 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.listener.api.event;
+
+import org.apache.gravitino.annotation.DeveloperApi;
+import org.apache.gravitino.utils.NameIdentifierUtil;
+
+/**
+ * Represents an event triggered when an attempt to retrieve a role from a
metalake fails due to an
+ * exception.
+ */
+@DeveloperApi
+public class GetRoleFailureEvent extends RoleFailureEvent {
+ private final String roleName;
+
+ /**
+ * Constructs a new {@code GetRoleFailureEvent} instance.
+ *
+ * @param user the user who initiated the retrieval attempt
+ * @param metalake the metalake from which the role is being retrieved
+ * @param exception the exception that occurred during role retrieval
+ * @param roleName the name of the role being retrieved
+ */
+ public GetRoleFailureEvent(String user, String metalake, Exception
exception, String roleName) {
+ super(user, NameIdentifierUtil.ofRole(metalake, roleName), exception);
+
+ this.roleName = roleName;
+ }
+
+ /**
+ * Returns the name of the role that was attempted to be retrieved.
+ *
+ * @return the role name
+ */
+ public String roleName() {
+ return roleName;
+ }
+
+ /**
+ * Returns the operation type of this event.
+ *
+ * @return the operation type.
+ */
+ @Override
+ public OperationType operationType() {
+ return OperationType.GET_ROLE;
+ }
+}
diff --git
a/core/src/main/java/org/apache/gravitino/listener/api/event/GrantPrivilegesFailureEvent.java
b/core/src/main/java/org/apache/gravitino/listener/api/event/GrantPrivilegesFailureEvent.java
new file mode 100644
index 0000000000..fab59eb065
--- /dev/null
+++
b/core/src/main/java/org/apache/gravitino/listener/api/event/GrantPrivilegesFailureEvent.java
@@ -0,0 +1,100 @@
+/*
+ * 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.listener.api.event;
+
+import com.google.common.collect.ImmutableSet;
+import java.util.Set;
+import org.apache.gravitino.MetadataObject;
+import org.apache.gravitino.annotation.DeveloperApi;
+import org.apache.gravitino.authorization.Privilege;
+import org.apache.gravitino.utils.NameIdentifierUtil;
+
+/**
+ * Represents an event triggered when an attempt to grant privileges to a role
fails due to an
+ * exception.
+ */
+@DeveloperApi
+public class GrantPrivilegesFailureEvent extends RoleFailureEvent {
+
+ private final String roleName;
+ private final MetadataObject metadataObject;
+ private final Set<Privilege> privileges;
+
+ /**
+ * Constructs a new {@code GrantPrivilegesFailureEvent} instance.
+ *
+ * @param user the name of the user who triggered the event
+ * @param metalake the name of the metalake
+ * @param exception the exception that occurred while granting privileges
+ * @param roleName the name of the role to which privileges were being
granted
+ * @param metadataObject the {@code MetadataObject} instance associated with
the role
+ * @param privileges the set of privileges intended to be granted; if {@code
null}, an empty set
+ * is used
+ */
+ public GrantPrivilegesFailureEvent(
+ String user,
+ String metalake,
+ Exception exception,
+ String roleName,
+ MetadataObject metadataObject,
+ Set<Privilege> privileges) {
+ super(user, NameIdentifierUtil.ofRole(metalake, roleName), exception);
+ this.roleName = roleName;
+ this.metadataObject = metadataObject;
+ this.privileges = privileges == null ? ImmutableSet.of() :
ImmutableSet.copyOf(privileges);
+ }
+
+ /**
+ * Returns the name of the role.
+ *
+ * @return the name of the role to which privileges were intended to be
granted
+ */
+ public String roleName() {
+ return roleName;
+ }
+
+ /**
+ * Returns the associated {@code MetadataObject} instance.
+ *
+ * @return the {@code MetadataObject} instance related to the role
+ */
+ public MetadataObject object() {
+ return metadataObject;
+ }
+
+ /**
+ * Returns the set of privileges intended to be granted.
+ *
+ * @return an immutable set of privileges
+ */
+ public Set<Privilege> privileges() {
+ return privileges;
+ }
+
+ /**
+ * Returns the operation type of this event.
+ *
+ * @return the operation type.
+ */
+ @Override
+ public OperationType operationType() {
+ return OperationType.GRANT_PRIVILEGES;
+ }
+}
diff --git
a/core/src/main/java/org/apache/gravitino/listener/api/event/ListRoleNamesFailureEvent.java
b/core/src/main/java/org/apache/gravitino/listener/api/event/ListRoleNamesFailureEvent.java
new file mode 100644
index 0000000000..e95c63ac0b
--- /dev/null
+++
b/core/src/main/java/org/apache/gravitino/listener/api/event/ListRoleNamesFailureEvent.java
@@ -0,0 +1,82 @@
+/*
+ * 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.listener.api.event;
+
+import java.util.Optional;
+import org.apache.gravitino.MetadataObject;
+import org.apache.gravitino.annotation.DeveloperApi;
+import org.apache.gravitino.utils.NameIdentifierUtil;
+
+/**
+ * Represents an event triggered when an attempt to list role names for a
metalake fails due to an
+ * exception.
+ */
+@DeveloperApi
+public class ListRoleNamesFailureEvent extends RoleFailureEvent {
+ private final Optional<MetadataObject> metadataObject;
+
+ /**
+ * Constructs a new {@code ListRoleNamesFailureEvent} instance with no
associated {@code
+ * MetadataObject}.
+ *
+ * @param user the user who initiated the operation
+ * @param metalake the name of the metalake for which role names were being
listed
+ * @param exception the exception that occurred during the operation
+ */
+ public ListRoleNamesFailureEvent(String user, String metalake, Exception
exception) {
+ super(user, NameIdentifierUtil.ofMetalake(metalake), exception);
+
+ this.metadataObject = Optional.empty();
+ }
+
+ /**
+ * Construct a new {@link ListRoleNamesFailureEvent} instance with the
specified arguments.
+ *
+ * @param user The user who initiated the event.
+ * @param metalake The name of the metalake for which role names are being
listed.
+ * @param exception The exception that occurred while listing role names.
+ * @param metadataObject The {@link MetadataObject} instance related to the
role names being
+ * listed, if present.
+ */
+ public ListRoleNamesFailureEvent(
+ String user, String metalake, Exception exception, MetadataObject
metadataObject) {
+ super(user, NameIdentifierUtil.ofMetalake(metalake), exception);
+ this.metadataObject = Optional.of(metadataObject);
+ }
+
+ /**
+ * Returns the associated {@code MetadataObject} instance.
+ *
+ * @return an {@code Optional} containing the {@code MetadataObject} if
present, otherwise empty
+ */
+ public Optional<MetadataObject> metadataObject() {
+ return metadataObject;
+ }
+
+ /**
+ * Returns the operation type of this event.
+ *
+ * @return the operation type.
+ */
+ @Override
+ public OperationType operationType() {
+ return OperationType.LIST_ROLE_NAMES;
+ }
+}
diff --git
a/core/src/main/java/org/apache/gravitino/listener/api/event/RevokePrivilegesFailureEvent.java
b/core/src/main/java/org/apache/gravitino/listener/api/event/RevokePrivilegesFailureEvent.java
new file mode 100644
index 0000000000..d934614d62
--- /dev/null
+++
b/core/src/main/java/org/apache/gravitino/listener/api/event/RevokePrivilegesFailureEvent.java
@@ -0,0 +1,99 @@
+/*
+ * 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.listener.api.event;
+
+import com.google.common.collect.ImmutableSet;
+import java.util.Set;
+import org.apache.gravitino.MetadataObject;
+import org.apache.gravitino.annotation.DeveloperApi;
+import org.apache.gravitino.authorization.Privilege;
+import org.apache.gravitino.utils.NameIdentifierUtil;
+
+/**
+ * Represents an event triggered when an attempt to revoke privileges from a
role fails due to an
+ * exception.
+ */
+@DeveloperApi
+public class RevokePrivilegesFailureEvent extends RoleFailureEvent {
+ private final String roleName;
+ private final MetadataObject metadataObject;
+ private final Set<Privilege> privileges;
+
+ /**
+ * Constructs a new {@code RevokePrivilegesFailureEvent} instance.
+ *
+ * @param user the user who initiated the event
+ * @param metalake the name of the metalake
+ * @param exception the exception that occurred during the revocation attempt
+ * @param roleName the name of the role from which privileges were attempted
to be revoked
+ * @param metadataObject the {@code MetadataObject} instance associated with
the role
+ * @param privileges the set of privileges intended to be revoked; if {@code
null}, an empty set
+ * is used
+ */
+ public RevokePrivilegesFailureEvent(
+ String user,
+ String metalake,
+ Exception exception,
+ String roleName,
+ MetadataObject metadataObject,
+ Set<Privilege> privileges) {
+ super(user, NameIdentifierUtil.ofRole(metalake, roleName), exception);
+ this.roleName = roleName;
+ this.metadataObject = metadataObject;
+ this.privileges = privileges == null ? ImmutableSet.of() :
ImmutableSet.copyOf(privileges);
+ }
+
+ /**
+ * Returns the name of the role from which privileges were attempted to be
revoked.
+ *
+ * @return the role name
+ */
+ public String roleName() {
+ return roleName;
+ }
+
+ /**
+ * Returns the associated {@code MetadataObject} instance.
+ *
+ * @return the {@code MetadataObject} instance linked to the role
+ */
+ public MetadataObject metadataObject() {
+ return metadataObject;
+ }
+
+ /**
+ * Returns the set of privileges intended to be revoked.
+ *
+ * @return an immutable set of privileges
+ */
+ public Set<Privilege> privileges() {
+ return privileges;
+ }
+
+ /**
+ * Returns the operation type of this event.
+ *
+ * @return the operation type.
+ */
+ @Override
+ public OperationType operationType() {
+ return OperationType.REVOKE_PRIVILEGES;
+ }
+}
diff --git
a/core/src/main/java/org/apache/gravitino/listener/api/event/RoleFailureEvent.java
b/core/src/main/java/org/apache/gravitino/listener/api/event/RoleFailureEvent.java
new file mode 100644
index 0000000000..359e68e435
--- /dev/null
+++
b/core/src/main/java/org/apache/gravitino/listener/api/event/RoleFailureEvent.java
@@ -0,0 +1,43 @@
+/*
+ * 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.listener.api.event;
+
+import org.apache.gravitino.NameIdentifier;
+import org.apache.gravitino.annotation.DeveloperApi;
+
+/**
+ * Represents an event that occurs when a role operation fails due to an
exception. This event
+ * contains the role information, a unique identifier for the operation, and
the exception that
+ * caused the failure.
+ */
+@DeveloperApi
+public abstract class RoleFailureEvent extends FailureEvent {
+
+ /**
+ * Constructs a new {@code RoleFailureEvent} instance.
+ *
+ * @param user the user who initiated the operation
+ * @param identifier the unique identifier associated with the operation
+ * @param exception the exception that caused the failure
+ */
+ protected RoleFailureEvent(String user, NameIdentifier identifier, Exception
exception) {
+ super(user, identifier, exception);
+ }
+}
diff --git
a/core/src/main/java/org/apache/gravitino/listener/api/info/RoleInfo.java
b/core/src/main/java/org/apache/gravitino/listener/api/info/RoleInfo.java
index c89fd5233d..59865dcec6 100644
--- a/core/src/main/java/org/apache/gravitino/listener/api/info/RoleInfo.java
+++ b/core/src/main/java/org/apache/gravitino/listener/api/info/RoleInfo.java
@@ -51,6 +51,21 @@ public class RoleInfo {
: ImmutableList.copyOf(roleObject.securableObjects());
}
+ /**
+ * Constructs a new {@code RoleInfo} instance using the given arguments.
+ *
+ * @param roleName The role name.
+ * @param properties The properties associated with the role.
+ * @param securableObjects The securable objects that belong to the role.
+ */
+ public RoleInfo(
+ String roleName, Map<String, String> properties, List<SecurableObject>
securableObjects) {
+ this.roleName = roleName;
+ this.properties = properties == null ? ImmutableMap.of() :
ImmutableMap.copyOf(properties);
+ this.securableObjects =
+ securableObjects == null ? ImmutableList.of() :
ImmutableList.copyOf(securableObjects);
+ }
+
/**
* Returns the role name.
*
diff --git
a/core/src/test/java/org/apache/gravitino/listener/api/event/TestRoleEvent.java
b/core/src/test/java/org/apache/gravitino/listener/api/event/TestRoleEvent.java
index c4d63ffbfa..697c3836bd 100644
---
a/core/src/test/java/org/apache/gravitino/listener/api/event/TestRoleEvent.java
+++
b/core/src/test/java/org/apache/gravitino/listener/api/event/TestRoleEvent.java
@@ -101,6 +101,24 @@ public class TestRoleEvent {
Assertions.assertEquals(roleName, roleInfo.roleName());
Assertions.assertEquals(properties, roleInfo.properties());
Assertions.assertEquals(securableObjects, roleInfo.securableObjects());
+
+ Assertions.assertThrows(
+ UnsupportedOperationException.class, () ->
roleInfo.securableObjects().add(null));
+
+ Assertions.assertThrows(
+ UnsupportedOperationException.class, () ->
roleInfo.properties().put("test", "test"));
+ }
+
+ @Test
+ void testRoleInfoWithNullSecurableObjects() {
+ RoleInfo roleInfo = new RoleInfo("test_role", ImmutableMap.of("comment",
"test comment"), null);
+ Assertions.assertEquals("test_role", roleInfo.roleName());
+ Assertions.assertEquals(ImmutableMap.of("comment", "test comment"),
roleInfo.properties());
+ Assertions.assertThrows(
+ UnsupportedOperationException.class, () ->
roleInfo.properties().put("testKey", "testVal"));
+ Assertions.assertEquals(Collections.emptyList(),
roleInfo.securableObjects());
+ Assertions.assertThrows(
+ UnsupportedOperationException.class, () ->
roleInfo.securableObjects().add(null));
}
@Test
@@ -142,6 +160,50 @@ public class TestRoleEvent {
validateRoleInfo(roleInfo, roleObject);
}
+ @Test
+ void testCreateRoleFailureEvent() {
+ Assertions.assertThrowsExactly(
+ GravitinoRuntimeException.class,
+ () -> failureDispatcher.createRole(METALAKE, roleName, properties,
securableObjects));
+
+ // validate event
+ Event event = dummyEventListener.popPostEvent();
+ Assertions.assertEquals(CreateRoleFailureEvent.class, event.getClass());
+ Assertions.assertEquals(OperationStatus.FAILURE, event.operationStatus());
+ Assertions.assertEquals(OperationType.CREATE_ROLE, event.operationType());
+
+ CreateRoleFailureEvent createRoleFailureEvent = (CreateRoleFailureEvent)
event;
+ Assertions.assertEquals(
+ NameIdentifierUtil.ofRole(METALAKE, roleName),
createRoleFailureEvent.identifier());
+ RoleInfo roleInfo = createRoleFailureEvent.createRoleRequest();
+ Assertions.assertEquals(roleName, roleInfo.roleName());
+ Assertions.assertEquals(properties, roleInfo.properties());
+ Assertions.assertEquals(securableObjects, roleInfo.securableObjects());
+ }
+
+ @Test
+ void testCreateRoleFailureEventWithNullSecurableObjects() {
+ Assertions.assertThrowsExactly(
+ GravitinoRuntimeException.class,
+ () -> failureDispatcher.createRole(METALAKE, roleName, properties,
null));
+
+ // Validate event
+ Event event = dummyEventListener.popPostEvent();
+ Assertions.assertEquals(CreateRoleFailureEvent.class, event.getClass());
+ Assertions.assertEquals(OperationStatus.FAILURE, event.operationStatus());
+ CreateRoleFailureEvent createRoleFailureEvent = (CreateRoleFailureEvent)
event;
+ Assertions.assertEquals(
+ NameIdentifierUtil.ofRole(METALAKE, roleName),
createRoleFailureEvent.identifier());
+
+ RoleInfo roleInfo = createRoleFailureEvent.createRoleRequest();
+ Assertions.assertEquals(roleName, roleInfo.roleName());
+ Assertions.assertEquals(properties, roleInfo.properties());
+ Assertions.assertNotNull(roleInfo.securableObjects());
+ Assertions.assertTrue(roleInfo.securableObjects().isEmpty());
+ Assertions.assertThrows(
+ UnsupportedOperationException.class, () ->
roleInfo.securableObjects().add(null));
+ }
+
@Test
void testDeleteRolePreEvent() {
dispatcher.deleteRole(METALAKE, roleName);
@@ -191,6 +253,23 @@ public class TestRoleEvent {
Assertions.assertEquals(otherRoleName, deleteRoleEvent.roleName());
}
+ @Test
+ void testDeleteRoleFailureEvent() {
+ Assertions.assertThrowsExactly(
+ GravitinoRuntimeException.class, () ->
failureDispatcher.deleteRole(METALAKE, roleName));
+
+ // validate event
+ Event event = dummyEventListener.popPostEvent();
+ Assertions.assertEquals(DeleteRoleFailureEvent.class, event.getClass());
+ Assertions.assertEquals(OperationStatus.FAILURE, event.operationStatus());
+ Assertions.assertEquals(OperationType.DELETE_ROLE, event.operationType());
+
+ DeleteRoleFailureEvent deleteRoleFailureEvent = (DeleteRoleFailureEvent)
event;
+ Assertions.assertEquals(
+ NameIdentifierUtil.ofRole(METALAKE, roleName),
deleteRoleFailureEvent.identifier());
+ Assertions.assertEquals(roleName, deleteRoleFailureEvent.roleName());
+ }
+
@Test
void testGetRolePreEvent() {
dispatcher.getRole(METALAKE, roleName);
@@ -225,6 +304,23 @@ public class TestRoleEvent {
validateRoleInfo(roleInfo, roleName, properties, securableObjects);
}
+ @Test
+ void testGetRoleFailureEvent() {
+ Assertions.assertThrowsExactly(
+ GravitinoRuntimeException.class, () ->
failureDispatcher.getRole(METALAKE, roleName));
+
+ // validate event
+ Event event = dummyEventListener.popPostEvent();
+ Assertions.assertEquals(GetRoleFailureEvent.class, event.getClass());
+ Assertions.assertEquals(OperationStatus.FAILURE, event.operationStatus());
+ Assertions.assertEquals(OperationType.GET_ROLE, event.operationType());
+
+ GetRoleFailureEvent getRoleFailureEvent = (GetRoleFailureEvent) event;
+ Assertions.assertEquals(
+ NameIdentifierUtil.ofRole(METALAKE, roleName),
getRoleFailureEvent.identifier());
+ Assertions.assertEquals(roleName, getRoleFailureEvent.roleName());
+ }
+
@Test
void testListRolesPreEvent() {
dispatcher.listRoleNames(METALAKE);
@@ -255,6 +351,22 @@ public class TestRoleEvent {
Assertions.assertFalse(listRoleNamesEvent.object().isPresent());
}
+ @Test
+ void testListRolesFailureEvent() {
+ Assertions.assertThrowsExactly(
+ GravitinoRuntimeException.class, () ->
failureDispatcher.listRoleNames(METALAKE));
+
+ // validate event
+ Event event = dummyEventListener.popPostEvent();
+ Assertions.assertEquals(ListRoleNamesFailureEvent.class, event.getClass());
+ Assertions.assertEquals(OperationStatus.FAILURE, event.operationStatus());
+ Assertions.assertEquals(OperationType.LIST_ROLE_NAMES,
event.operationType());
+
+ ListRoleNamesFailureEvent listRoleNamesFailureEvent =
(ListRoleNamesFailureEvent) event;
+ Assertions.assertEquals(identifier,
listRoleNamesFailureEvent.identifier());
+
Assertions.assertFalse(listRoleNamesFailureEvent.metadataObject().isPresent());
+ }
+
@Test
void testListRolesFromObjectPreEvent() {
dispatcher.listRoleNamesByObject(METALAKE, securableObjects.get(0));
@@ -288,7 +400,26 @@ public class TestRoleEvent {
}
@Test
- void testGrantPrivilegesToRole() {
+ void testListRoleFromObjectFailureEvent() {
+ Assertions.assertThrowsExactly(
+ GravitinoRuntimeException.class,
+ () -> failureDispatcher.listRoleNamesByObject(METALAKE,
securableObjects.get(0)));
+
+ // validate event
+ Event event = dummyEventListener.popPostEvent();
+ Assertions.assertEquals(ListRoleNamesFailureEvent.class, event.getClass());
+ Assertions.assertEquals(OperationStatus.FAILURE, event.operationStatus());
+ Assertions.assertEquals(OperationType.LIST_ROLE_NAMES,
event.operationType());
+
+ ListRoleNamesFailureEvent listRoleNamesFailureEvent =
(ListRoleNamesFailureEvent) event;
+ Assertions.assertEquals(identifier,
listRoleNamesFailureEvent.identifier());
+
Assertions.assertTrue(listRoleNamesFailureEvent.metadataObject().isPresent());
+ Assertions.assertEquals(
+ securableObjects.get(0),
listRoleNamesFailureEvent.metadataObject().get());
+ }
+
+ @Test
+ void testGrantPrivilegesToRolePreEvent() {
dispatcher.grantPrivilegeToRole(METALAKE, roleName, metadataObject,
privileges);
// validate pre-event
@@ -322,6 +453,52 @@ public class TestRoleEvent {
validateRoleInfo(roleInfo, roleName, properties, securableObjects);
}
+ @Test
+ void testGrantPrivilegesToRoleFailureEvent() {
+ Assertions.assertThrowsExactly(
+ GravitinoRuntimeException.class,
+ () ->
+ failureDispatcher.grantPrivilegeToRole(METALAKE, roleName,
metadataObject, privileges));
+
+ // validate event
+ Event event = dummyEventListener.popPostEvent();
+ Assertions.assertEquals(GrantPrivilegesFailureEvent.class,
event.getClass());
+ Assertions.assertEquals(OperationStatus.FAILURE, event.operationStatus());
+ Assertions.assertEquals(OperationType.GRANT_PRIVILEGES,
event.operationType());
+
+ GrantPrivilegesFailureEvent grantPrivilegesFailureEvent =
(GrantPrivilegesFailureEvent) event;
+ Assertions.assertEquals(
+ NameIdentifierUtil.ofRole(METALAKE, roleName),
grantPrivilegesFailureEvent.identifier());
+ Assertions.assertEquals(roleName, grantPrivilegesFailureEvent.roleName());
+ Assertions.assertEquals(metadataObject,
grantPrivilegesFailureEvent.object());
+ Assertions.assertEquals(privileges,
grantPrivilegesFailureEvent.privileges());
+ }
+
+ @Test
+ void testGrantPrivilegesFailureEventWithNullPrivileges() {
+ Assertions.assertThrowsExactly(
+ GravitinoRuntimeException.class,
+ () -> failureDispatcher.grantPrivilegeToRole(METALAKE, roleName,
metadataObject, null));
+
+ // validate event
+ Event event = dummyEventListener.popPostEvent();
+ Assertions.assertEquals(GrantPrivilegesFailureEvent.class,
event.getClass());
+ Assertions.assertEquals(OperationStatus.FAILURE, event.operationStatus());
+ Assertions.assertEquals(OperationType.GRANT_PRIVILEGES,
event.operationType());
+
+ GrantPrivilegesFailureEvent grantPrivilegesFailureEvent =
(GrantPrivilegesFailureEvent) event;
+ Assertions.assertEquals(
+ NameIdentifierUtil.ofRole(METALAKE, roleName),
grantPrivilegesFailureEvent.identifier());
+ Assertions.assertEquals(roleName, grantPrivilegesFailureEvent.roleName());
+ Assertions.assertEquals(metadataObject,
grantPrivilegesFailureEvent.object());
+ Assertions.assertNotNull(grantPrivilegesFailureEvent.privileges());
+ Assertions.assertTrue(grantPrivilegesFailureEvent.privileges().isEmpty());
+
+ Assertions.assertThrows(
+ UnsupportedOperationException.class,
+ () -> grantPrivilegesFailureEvent.privileges().add(null));
+ }
+
@Test
void testRevokePrivilegesFromRolePreEvent() {
dispatcher.revokePrivilegesFromRole(METALAKE, roleName, metadataObject,
privileges);
@@ -357,6 +534,29 @@ public class TestRoleEvent {
validateRoleInfo(roleInfo, roleName, properties, securableObjects);
}
+ @Test
+ void testRevokePrivilegesFromRoleFailureEvent() {
+ Assertions.assertThrowsExactly(
+ GravitinoRuntimeException.class,
+ () ->
+ failureDispatcher.revokePrivilegesFromRole(
+ METALAKE, roleName, metadataObject, privileges));
+
+ // validate event
+ Event event = dummyEventListener.popPostEvent();
+ Assertions.assertEquals(RevokePrivilegesFailureEvent.class,
event.getClass());
+ Assertions.assertEquals(OperationStatus.FAILURE, event.operationStatus());
+ Assertions.assertEquals(OperationType.REVOKE_PRIVILEGES,
event.operationType());
+
+ RevokePrivilegesFailureEvent revokePrivilegesFailureEvent =
+ (RevokePrivilegesFailureEvent) event;
+ Assertions.assertEquals(
+ NameIdentifierUtil.ofRole(METALAKE, roleName),
revokePrivilegesFailureEvent.identifier());
+ Assertions.assertEquals(roleName, revokePrivilegesFailureEvent.roleName());
+ Assertions.assertEquals(metadataObject,
revokePrivilegesFailureEvent.metadataObject());
+ Assertions.assertEquals(privileges,
revokePrivilegesFailureEvent.privileges());
+ }
+
private AccessControlEventDispatcher mockRoleDispatcher() {
AccessControlEventDispatcher dispatcher =
mock(AccessControlEventDispatcher.class);
Group mockGroup = getMockGroup(groupName, ImmutableList.of(roleName,
otherRoleName));
diff --git a/docs/gravitino-server-config.md b/docs/gravitino-server-config.md
index de56789997..5c41b8aa3c 100644
--- a/docs/gravitino-server-config.md
+++ b/docs/gravitino-server-config.md
@@ -118,20 +118,20 @@ Gravitino triggers a pre-event before the operation, a
post-event after the comp
##### Post-event
-| Operation type | Post-event
[...]
-|-------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
[...]
-| table operation | `CreateTableEvent`, `AlterTableEvent`,
`DropTableEvent`, `LoadTableEvent`, `ListTableEvent`, `PurgeTableFailureEvent`,
`CreateTableFailureEvent`, `AlterTableFailureEvent`, `DropTableFailureEvent`,
`LoadTableFailureEvent`, `ListTableFailureEvent`, `PurgeTableFailureEvent`
[...]
-| fileset operation | `CreateFileSetEvent`,
`AlterFileSetEvent`, `DropFileSetEvent`, `LoadFileSetEvent`,
`ListFileSetEvent`, `CreateFileSetFailureEvent`, `AlterFileSetFailureEvent`,
`DropFileSetFailureEvent`, `LoadFileSetFailureEvent`, `ListFileSetFailureEvent`
[...]
-| topic operation | `CreateTopicEvent`, `AlterTopicEvent`,
`DropTopicEvent`, `LoadTopicEvent`, `ListTopicEvent`,
`CreateTopicFailureEvent`, `AlterTopicFailureEvent`, `DropTopicFailureEvent`,
`LoadTopicFailureEvent`, `ListTopicFailureEvent`
[...]
-| schema operation | `CreateSchemaEvent`,
`AlterSchemaEvent`, `DropSchemaEvent`, `LoadSchemaEvent`, `ListSchemaEvent`,
`CreateSchemaFailureEvent`, `AlterSchemaFailureEvent`,
`DropSchemaFailureEvent`, `LoadSchemaFailureEvent`, `ListSchemaFailureEvent`
[...]
-| catalog operation | `CreateCatalogEvent`,
`AlterCatalogEvent`, `DropCatalogEvent`, `LoadCatalogEvent`,
`ListCatalogEvent`, `CreateCatalogFailureEvent`, `AlterCatalogFailureEvent`,
`DropCatalogFailureEvent`, `LoadCatalogFailureEvent`, `ListCatalogFailureEvent`
[...]
-| metalake operation | `CreateMetalakeEvent`,
`AlterMetalakeEvent`, `DropMetalakeEvent`, `LoadMetalakeEvent`,
`ListMetalakeEvent`, `CreateMetalakeFailureEvent`, `AlterMetalakeFailureEvent`,
`DropMetalakeFailureEvent`, `LoadMetalakeFailureEvent`,
`ListMetalakeFailureEvent`
[...]
-| Iceberg REST server table operation | `IcebergCreateTableEvent`,
`IcebergUpdateTableEvent`, `IcebergDropTableEvent`, `IcebergLoadTableEvent`,
`IcebergListTableEvent`, `IcebergTableExistsEvent`, `IcebergRenameTableEvent`,
`IcebergCreateTableFailureEvent`, `IcebergUpdateTableFailureEvent`,
`IcebergDropTableFailureEvent`, `IcebergLoadTableFailureEvent`,
`IcebergListTableFailureEvent`, `IcebergRenameTableFailureEvent`,
`IcebergTableExistsFailureEvent` [...]
+| Operation type | Post-event
[...]
+|-------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
[...]
+| table operation | `CreateTableEvent`, `AlterTableEvent`,
`DropTableEvent`, `LoadTableEvent`, `ListTableEvent`, `PurgeTableFailureEvent`,
`CreateTableFailureEvent`, `AlterTableFailureEvent`, `DropTableFailureEvent`,
`LoadTableFailureEvent`, `ListTableFailureEvent`, `PurgeTableFailureEvent`
[...]
+| fileset operation | `CreateFileSetEvent`,
`AlterFileSetEvent`, `DropFileSetEvent`, `LoadFileSetEvent`,
`ListFileSetEvent`, `CreateFileSetFailureEvent`, `AlterFileSetFailureEvent`,
`DropFileSetFailureEvent`, `LoadFileSetFailureEvent`, `ListFileSetFailureEvent`
[...]
+| topic operation | `CreateTopicEvent`, `AlterTopicEvent`,
`DropTopicEvent`, `LoadTopicEvent`, `ListTopicEvent`,
`CreateTopicFailureEvent`, `AlterTopicFailureEvent`, `DropTopicFailureEvent`,
`LoadTopicFailureEvent`, `ListTopicFailureEvent`
[...]
+| schema operation | `CreateSchemaEvent`,
`AlterSchemaEvent`, `DropSchemaEvent`, `LoadSchemaEvent`, `ListSchemaEvent`,
`CreateSchemaFailureEvent`, `AlterSchemaFailureEvent`,
`DropSchemaFailureEvent`, `LoadSchemaFailureEvent`, `ListSchemaFailureEvent`
[...]
+| catalog operation | `CreateCatalogEvent`,
`AlterCatalogEvent`, `DropCatalogEvent`, `LoadCatalogEvent`,
`ListCatalogEvent`, `CreateCatalogFailureEvent`, `AlterCatalogFailureEvent`,
`DropCatalogFailureEvent`, `LoadCatalogFailureEvent`, `ListCatalogFailureEvent`
[...]
+| metalake operation | `CreateMetalakeEvent`,
`AlterMetalakeEvent`, `DropMetalakeEvent`, `LoadMetalakeEvent`,
`ListMetalakeEvent`, `CreateMetalakeFailureEvent`, `AlterMetalakeFailureEvent`,
`DropMetalakeFailureEvent`, `LoadMetalakeFailureEvent`,
`ListMetalakeFailureEvent`
[...]
+| Iceberg REST server table operation | `IcebergCreateTableEvent`,
`IcebergUpdateTableEvent`, `IcebergDropTableEvent`, `IcebergLoadTableEvent`,
`IcebergListTableEvent`, `IcebergTableExistsEvent`, `IcebergRenameTableEvent`,
`IcebergCreateTableFailureEvent`, `IcebergUpdateTableFailureEvent`,
`IcebergDropTableFailureEvent`, `IcebergLoadTableFailureEvent`,
`IcebergListTableFailureEvent`, `IcebergRenameTableFailureEvent`,
`IcebergTableExistsFailureEvent` [...]
| tag operation | `ListTagsEvent`, `ListTagsInfoEvent`,
`CreateTagEvent`, `GetTagEvent`, `AlterTagEvent`, `DeleteTagEvent`,
`ListMetadataObjectsForTagEvent`, `ListTagsForMetadataObjectEvent`,
`ListTagsInfoForMetadataObjectEvent`, `AssociateTagsForMetadataObjectEvent`,
`GetTagForMetadataObjectEvent`, `ListTagsFailureEvent`,
`ListTagInfoFailureEvent`, `CreateTagFailureEvent`, `GetTagFailureEvent`,
`AlterTagFailureEvent`, `DeleteTagFailureEvent`, `ListMetadataObjectsFo [...]
-| model operation | `DeleteModelEvent`,
`DeleteModelVersionEvent`, `GetModelEvent`, `GetModelVersionEvent`,
`LinkModelVersionEvent`, `ListModelEvent`, `ListModelVersionsEvent`,
`RegisterAndLinkModelEvent`, `RegisterModelEvent`, `DeleteModelFailureEvent`,
`DeleteModelVersionFailureEvent`, `GetModelFailureEvent`,
`GetModelVersionFailureEvent`, `LinkModelVersionFailureEvent`,
`ListModelFailureEvent`, `ListModelVersionFailureEvent`,
`RegisterAndLinkModelFailureEvent`, [...]
-| user operation | `AddUserEvent`, `GetUserEvent`,
`ListUserNamesEvent`, `ListUsersEvent`, `RemoveUserEvent`,
`GrantUserRolesEvent`, `RevokeUserRolesEvent`, `AddUserFailureEvent`,
`GetUserFailureEvent`, `GrantUserRolesFailureEvent`,
`ListUserNamesFailureEvent`, `ListUsersFailureEvent`, `RemoveUserFailureEvent`,
`RevokeUserRolesFailureEvent`
[...]
-| group operation | `AddGroupEvent`, `GetGroupEvent`,
`ListGroupNamesEvent`, `ListGroupsEvent`, `RemoveGroupEvent`,
`GrantGroupRolesEvent`, `RevokeGroupRolesEvent`, `AddGroupFailureEvent`,
`GetGroupFailureEvent`, `GrantGroupRolesFailureEvent`,
`ListGroupNamesFailureEvent`, `ListGroupsFailureEvent`,
`RemoveGroupFailureEvent`, `RevokeGroupRolesFailureEvent`
[...]
-| role operation | `CreateRoleEvent`, `DeleteRoleEvent`,
`GetRoleEvent`, `GrantPrivilegesEvent`, `ListRoleNamesEvent`,
`RevokePrivilegesEvent`
[...]
+| model operation | `DeleteModelEvent`,
`DeleteModelVersionEvent`, `GetModelEvent`, `GetModelVersionEvent`,
`LinkModelVersionEvent`, `ListModelEvent`, `ListModelVersionsEvent`,
`RegisterAndLinkModelEvent`, `RegisterModelEvent`, `DeleteModelFailureEvent`,
`DeleteModelVersionFailureEvent`, `GetModelFailureEvent`,
`GetModelVersionFailureEvent`, `LinkModelVersionFailureEvent`,
`ListModelFailureEvent`, `ListModelVersionFailureEvent`,
`RegisterAndLinkModelFailureEvent`, [...]
+| user operation | `AddUserEvent`, `GetUserEvent`,
`ListUserNamesEvent`, `ListUsersEvent`, `RemoveUserEvent`,
`GrantUserRolesEvent`, `RevokeUserRolesEvent`, `AddUserFailureEvent`,
`GetUserFailureEvent`, `GrantUserRolesFailureEvent`,
`ListUserNamesFailureEvent`, `ListUsersFailureEvent`, `RemoveUserFailureEvent`,
`RevokeUserRolesFailureEvent`
[...]
+| group operation | `AddGroupEvent`, `GetGroupEvent`,
`ListGroupNamesEvent`, `ListGroupsEvent`, `RemoveGroupEvent`,
`GrantGroupRolesEvent`, `RevokeGroupRolesEvent`, `AddGroupFailureEvent`,
`GetGroupFailureEvent`, `GrantGroupRolesFailureEvent`,
`ListGroupNamesFailureEvent`, `ListGroupsFailureEvent`,
`RemoveGroupFailureEvent`, `RevokeGroupRolesFailureEvent`
[...]
+| role operation | `CreateRoleEvent`, `DeleteRoleEvent`,
`GetRoleEvent`, `GrantPrivilegesEvent`, `ListRoleNamesEvent`,
`RevokePrivilegesEvent`, `CreateRoleFailureEvent`, `DeleteRoleFailureEvent`,
`GetRoleFailureEvent`, `GrantPrivilegesFailureEvent`,
`ListRoleNamesFailureEvent`, `RevokePrivilegesFailureEvent`
[...]