Skip to content

Commit

Permalink
fix comment
Browse files Browse the repository at this point in the history
  • Loading branch information
jerqi committed Sep 19, 2024
1 parent 0a0d6b3 commit 3f2ee03
Show file tree
Hide file tree
Showing 29 changed files with 845 additions and 41 deletions.
12 changes: 10 additions & 2 deletions api/src/main/java/org/apache/gravitino/authorization/Role.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,7 @@

/**
* The interface of a role. The role is the entity which has kinds of privileges. One role can have
* multiple privileges of one securable object. Gravitino chooses to bind one securable object to
* one role to avoid granting too many privileges to one role.
* multiple privileges of multiple securable objects.
*/
@Evolving
public interface Role extends Auditable {
Expand All @@ -53,4 +52,13 @@ public interface Role extends Auditable {
* @return The securable objects of the role.
*/
List<SecurableObject> securableObjects();

/**
* The securable objects count of the role.
*
* @return The scecurable objects count of the role.
*/
default int securableObjectsCount() {
return securableObjects().size();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/*
* 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.client;

import java.util.List;
import java.util.Map;
import java.util.function.Supplier;
import org.apache.gravitino.Audit;
import org.apache.gravitino.authorization.Role;
import org.apache.gravitino.authorization.SecurableObject;
import org.apache.gravitino.dto.authorization.RoleDTO;

/** Represents a generic role. This class is used for lazily requesting securable objects. */
class GenericRole implements Role {

private final RoleDTO roleDTO;
private final Supplier<List<SecurableObject>> securableObjectsSupplier;

GenericRole(RoleDTO roleDTO, GravitinoMetalake gravitinoMetalake) {
this.roleDTO = roleDTO;
this.securableObjectsSupplier =
new Supplier<List<SecurableObject>>() {
private boolean waitToRequest = true;
private List<SecurableObject> securableObjects;

@Override
public List<SecurableObject> get() {
if (waitToRequest) {
securableObjects = gravitinoMetalake.getRole(roleDTO.name()).securableObjects();
waitToRequest = false;
}

return securableObjects;
}
};
}

@Override
public Audit auditInfo() {
return roleDTO.auditInfo();
}

@Override
public String name() {
return roleDTO.name();
}

@Override
public Map<String, String> properties() {
return roleDTO.properties();
}

@Override
public List<SecurableObject> securableObjects() {
return securableObjectsSupplier.get();
}

@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof GenericRole)) {
return false;
}

GenericRole that = (GenericRole) obj;
return roleDTO.equals(that.roleDTO);
}

@Override
public int hashCode() {
return roleDTO.hashCode();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,26 @@ public void setOwner(MetadataObject object, String ownerName, Owner.Type ownerTy
getMetalake().setOwner(object, ownerName, ownerType);
}

/**
* Lists the role names.
*
* @return The role name list.
* @throws NoSuchMetalakeException If the Metalake with the given name does not exist.
*/
public String[] listRoleNames() throws NoSuchMetalakeException {
return getMetalake().listRoleNames();
}

/**
* Lists the roles.
*
* @return The Role list.
* @throws NoSuchMetalakeException If the Metalake with the given name does not exist.
*/
public Role[] listRoles() throws NoSuchMetalakeException {
return getMetalake().listRoles();
}

/**
* Creates a new builder for constructing a GravitinoClient.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
import org.apache.gravitino.dto.responses.NameListResponse;
import org.apache.gravitino.dto.responses.OwnerResponse;
import org.apache.gravitino.dto.responses.RemoveResponse;
import org.apache.gravitino.dto.responses.RoleListResponse;
import org.apache.gravitino.dto.responses.RoleResponse;
import org.apache.gravitino.dto.responses.SetResponse;
import org.apache.gravitino.dto.responses.TagListResponse;
Expand Down Expand Up @@ -100,9 +101,9 @@ public class GravitinoMetalake extends MetalakeDTO implements SupportsCatalogs,
private static final String API_METALAKES_GROUPS_PATH = "api/metalakes/%s/groups/%s";
private static final String API_METALAKES_ROLES_PATH = "api/metalakes/%s/roles/%s";
private static final String API_METALAKES_OWNERS_PATH = "api/metalakes/%s/owners/%s";
private static final String BLANK_PLACE_HOLDER = "";

private static final String API_METALAKES_TAGS_PATH = "api/metalakes/%s/tags";
private static final String BLANK_PLACE_HOLDER = "";

private final RESTClient restClient;

Expand Down Expand Up @@ -701,6 +702,46 @@ public Role createRole(
return resp.getRole();
}

/**
* Lists the role names.
*
* @return The role name list.
* @throws NoSuchMetalakeException If the Metalake with the given name does not exist.
*/
public String[] listRoleNames() {
NameListResponse resp =
restClient.get(
String.format(API_METALAKES_ROLES_PATH, this.name(), BLANK_PLACE_HOLDER),
NameListResponse.class,
Collections.emptyMap(),
ErrorHandlers.roleErrorHandler());
resp.validate();

return resp.getNames();
}

/**
* Lists the roles.
*
* @return The Role list.
* @throws NoSuchMetalakeException If the Metalake with the given name does not exist.
*/
public Role[] listRoles() {
Map<String, String> params = ImmutableMap.of("details", "true");
RoleListResponse resp =
restClient.get(
String.format(API_METALAKES_ROLES_PATH, this.name(), BLANK_PLACE_HOLDER),
params,
RoleListResponse.class,
Collections.emptyMap(),
ErrorHandlers.roleErrorHandler());
resp.validate();

return Arrays.stream(resp.getRoles())
.map(dto -> new GenericRole(dto, this))
.toArray(Role[]::new);
}

/**
* Grant roles to a user.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import java.time.Instant;
import java.util.Collections;
import java.util.Map;
import org.apache.gravitino.authorization.Privileges;
import org.apache.gravitino.authorization.Role;
import org.apache.gravitino.authorization.SecurableObject;
Expand All @@ -40,6 +42,8 @@
import org.apache.gravitino.dto.responses.DeleteResponse;
import org.apache.gravitino.dto.responses.ErrorResponse;
import org.apache.gravitino.dto.responses.MetalakeResponse;
import org.apache.gravitino.dto.responses.NameListResponse;
import org.apache.gravitino.dto.responses.RoleListResponse;
import org.apache.gravitino.dto.responses.RoleResponse;
import org.apache.gravitino.exceptions.NoSuchMetalakeException;
import org.apache.gravitino.exceptions.NoSuchRoleException;
Expand Down Expand Up @@ -211,6 +215,60 @@ public void testDeleteRoles() throws Exception {
Assertions.assertThrows(RuntimeException.class, () -> gravitinoClient.deleteRole(roleName));
}

@Test
public void testListRoleNames() throws Exception {
String rolePath = withSlash(String.format(API_METALAKES_ROLES_PATH, metalakeName, ""));

NameListResponse listResponse = new NameListResponse(new String[] {"role1", "role2"});
buildMockResource(Method.GET, rolePath, null, listResponse, SC_OK);

Assertions.assertArrayEquals(new String[] {"role1", "role2"}, gravitinoClient.listRoleNames());

ErrorResponse errRespNoMetalake =
ErrorResponse.notFound(NoSuchMetalakeException.class.getSimpleName(), "metalake not found");
buildMockResource(Method.GET, rolePath, null, errRespNoMetalake, SC_NOT_FOUND);
Exception ex =
Assertions.assertThrows(
NoSuchMetalakeException.class, () -> gravitinoClient.listRoleNames());
Assertions.assertEquals("metalake not found", ex.getMessage());

// Test RuntimeException
ErrorResponse errResp = ErrorResponse.internalError("internal error");
buildMockResource(Method.GET, rolePath, null, errResp, SC_SERVER_ERROR);
Assertions.assertThrows(RuntimeException.class, () -> gravitinoClient.listRoleNames());
}

@Test
public void testListRoles() throws Exception {
String rolePath = withSlash(String.format(API_METALAKES_ROLES_PATH, metalakeName, ""));
RoleDTO role1 = mockRoleDTO("role1");
RoleDTO role2 = mockRoleDTO("role2");
Map<String, String> params = Collections.singletonMap("details", "true");
RoleListResponse listResponse = new RoleListResponse(new RoleDTO[] {role1, role2});
buildMockResource(Method.GET, rolePath, params, null, listResponse, SC_OK);
String role1Path = withSlash(String.format(API_METALAKES_ROLES_PATH, metalakeName, "role1"));
buildMockResource(Method.GET, role1Path, null, new RoleResponse(role1), SC_OK);
String role2Path = withSlash(String.format(API_METALAKES_ROLES_PATH, metalakeName, "role2"));
buildMockResource(Method.GET, role2Path, null, new RoleResponse(role2), SC_OK);

Role[] roles = gravitinoClient.listRoles();
Assertions.assertEquals(2, roles.length);
assertRole(role1, roles[0]);
assertRole(role2, roles[1]);

ErrorResponse errRespNoMetalake =
ErrorResponse.notFound(NoSuchMetalakeException.class.getSimpleName(), "metalake not found");
buildMockResource(Method.GET, rolePath, params, null, errRespNoMetalake, SC_NOT_FOUND);
Exception ex =
Assertions.assertThrows(NoSuchMetalakeException.class, () -> gravitinoClient.listRoles());
Assertions.assertEquals("metalake not found", ex.getMessage());

// Test RuntimeException
ErrorResponse errResp = ErrorResponse.internalError("internal error");
buildMockResource(Method.GET, rolePath, params, null, errResp, SC_SERVER_ERROR);
Assertions.assertThrows(RuntimeException.class, () -> gravitinoClient.listRoles());
}

private RoleDTO mockRoleDTO(String name) {
SecurableObject securableObject =
SecurableObjects.ofCatalog("catalog", Lists.newArrayList(Privileges.UseCatalog.allow()));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import com.google.common.collect.Maps;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.apache.gravitino.Configs;
Expand Down Expand Up @@ -162,6 +163,21 @@ void testManageRoles() {

Assertions.assertEquals(roleName, role.name());
Assertions.assertEquals(properties, role.properties());
assertSecurableObjects(Lists.newArrayList(metalakeObject), role.securableObjects());

// List roles
String anotherRoleName = "another-role";
Role anotherRole =
metalake.createRole(anotherRoleName, properties, Lists.newArrayList(metalakeObject));
String[] roleNames = metalake.listRoleNames();
Assertions.assertEquals(
Lists.newArrayList(anotherRoleName, roleName), Arrays.asList(roleNames));
Role[] roles = metalake.listRoles();
Assertions.assertEquals(
Lists.newArrayList(anotherRoleName, roleName),
Arrays.stream(roles).map(Role::name).collect(Collectors.toList()));
assertSecurableObjects(role.securableObjects(), roles[0].securableObjects());
assertSecurableObjects(anotherRole.securableObjects(), roles[1].securableObjects());

// Verify the object
Assertions.assertEquals(1, role.securableObjects().size());
Expand Down Expand Up @@ -289,4 +305,22 @@ void testManageGroupPermissions() {
metalake.removeGroup(groupName);
metalake.deleteRole(roleName);
}

private static void assertSecurableObjects(
List<SecurableObject> expect, List<SecurableObject> actual) {
Assertions.assertEquals(expect.size(), actual.size());
for (int index = 0; index < expect.size(); index++) {
Assertions.assertEquals(expect.get(index).fullName(), actual.get(index).fullName());
Assertions.assertEquals(expect.get(index).type(), actual.get(index).type());
List<Privilege> expectPrivileges = expect.get(index).privileges();
List<Privilege> actualPrivileges = actual.get(index).privileges();
Assertions.assertEquals(expectPrivileges.size(), actualPrivileges.size());
for (int priIndex = 0; priIndex < expectPrivileges.size(); priIndex++) {
Assertions.assertEquals(
expectPrivileges.get(priIndex).name(), actualPrivileges.get(priIndex).name());
Assertions.assertEquals(
actualPrivileges.get(priIndex).condition(), actualPrivileges.get(priIndex).condition());
}
}
}
}
Loading

0 comments on commit 3f2ee03

Please sign in to comment.