Skip to content

Commit

Permalink
Add ListRoles
Browse files Browse the repository at this point in the history
  • Loading branch information
jerqi committed Jul 16, 2024
1 parent 6990036 commit a57e4e3
Show file tree
Hide file tree
Showing 16 changed files with 586 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import com.google.common.base.Preconditions;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
Expand All @@ -45,8 +46,10 @@
import org.apache.gravitino.dto.responses.GroupResponse;
import org.apache.gravitino.dto.responses.MetalakeListResponse;
import org.apache.gravitino.dto.responses.MetalakeResponse;
import org.apache.gravitino.dto.responses.NameListResponse;
import org.apache.gravitino.dto.responses.RemoveResponse;
import org.apache.gravitino.dto.responses.RoleResponse;
import org.apache.gravitino.dto.responses.UserListResponse;
import org.apache.gravitino.dto.responses.UserResponse;
import org.apache.gravitino.exceptions.GroupAlreadyExistsException;
import org.apache.gravitino.exceptions.MetalakeAlreadyExistsException;
Expand Down Expand Up @@ -262,6 +265,48 @@ public User getUser(String metalake, String user)
return resp.getUser();
}

/**
* Lists the usernames.
*
* @param metalake The Metalake of the User.
* @return The username list.
* @throws NoSuchMetalakeException If the Metalake with the given name does not exist.
*/
public String[] listUserNames(String metalake) throws NoSuchMetalakeException {
NameListResponse resp =
restClient.get(
String.format(API_METALAKES_USERS_PATH, metalake, BLANK_PLACE_HOLDER),
NameListResponse.class,
Collections.emptyMap(),
ErrorHandlers.userErrorHandler());
resp.validate();

return resp.getNames();
}

/**
* Lists the users.
*
* @param metalake The Metalake of the User.
* @return The User list.
* @throws NoSuchMetalakeException If the Metalake with the given name does not exist.
*/
public User[] listUsers(String metalake) {
Map<String, String> params = new HashMap<>();
params.put("details", "true");

UserListResponse resp =
restClient.get(
String.format(API_METALAKES_USERS_PATH, metalake, BLANK_PLACE_HOLDER),
params,
UserListResponse.class,
Collections.emptyMap(),
ErrorHandlers.userErrorHandler());
resp.validate();

return resp.getUsers();
}

/**
* Adds a new Group.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
import static org.apache.hc.core5.http.HttpStatus.SC_SERVER_ERROR;

import java.time.Instant;
import java.util.Collections;
import java.util.Map;
import org.apache.gravitino.authorization.Group;
import org.apache.gravitino.authorization.User;
import org.apache.gravitino.dto.AuditDTO;
Expand All @@ -33,7 +35,9 @@
import org.apache.gravitino.dto.requests.UserAddRequest;
import org.apache.gravitino.dto.responses.ErrorResponse;
import org.apache.gravitino.dto.responses.GroupResponse;
import org.apache.gravitino.dto.responses.NameListResponse;
import org.apache.gravitino.dto.responses.RemoveResponse;
import org.apache.gravitino.dto.responses.UserListResponse;
import org.apache.gravitino.dto.responses.UserResponse;
import org.apache.gravitino.exceptions.GroupAlreadyExistsException;
import org.apache.gravitino.exceptions.NoSuchGroupException;
Expand Down Expand Up @@ -155,6 +159,58 @@ public void testRemoveUsers() throws Exception {
RuntimeException.class, () -> client.removeUser(metalakeName, username));
}

@Test
public void testListUserNames() throws Exception {
String userPath = withSlash(String.format(API_METALAKES_USERS_PATH, metalakeName, ""));

NameListResponse listResponse = new NameListResponse(new String[] {"user1", "user2"});
buildMockResource(Method.GET, userPath, null, listResponse, SC_OK);

Assertions.assertArrayEquals(
new String[] {"user1", "user2"}, client.listUserNames(metalakeName));

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

// Test RuntimeException
ErrorResponse errResp = ErrorResponse.internalError("internal error");
buildMockResource(Method.GET, userPath, null, errResp, SC_SERVER_ERROR);
Assertions.assertThrows(RuntimeException.class, () -> client.listUserNames(metalakeName));
}

@Test
public void testListUsers() throws Exception {
String userPath = withSlash(String.format(API_METALAKES_USERS_PATH, metalakeName, ""));
UserDTO user1 = mockUserDTO("user1");
UserDTO user2 = mockUserDTO("user2");
Map<String, String> params = Collections.singletonMap("details", "true");
UserListResponse listResponse = new UserListResponse(new UserDTO[] {user1, user2});
buildMockResource(Method.GET, userPath, params, null, listResponse, SC_OK);

User[] users = client.listUsers(metalakeName);
Assertions.assertEquals(2, users.length);
assertUser(user1, users[0]);
assertUser(user2, users[1]);

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

// Test RuntimeException
ErrorResponse errResp = ErrorResponse.internalError("internal error");
buildMockResource(Method.GET, userPath, params, null, errResp, SC_SERVER_ERROR);
Assertions.assertThrows(RuntimeException.class, () -> client.listUsers(metalakeName));
}

@Test
public void testAddGroups() throws Exception {
String groupName = "group";
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* 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.dto.responses;

import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.ToString;

/** Represents a response containing a list of names. */
@Getter
@ToString
@EqualsAndHashCode(callSuper = true)
public class NameListResponse extends BaseResponse {

@JsonProperty("names")
private final String[] names;

/**
* Constructor for NameListResponse.
*
* @param names The array of names.
*/
public NameListResponse(String[] names) {
super(0);
this.names = names;
}

/**
* This is the constructor that is used by Jackson deserializer to create an instance of
* NameListResponse.
*/
public NameListResponse() {
super(0);
this.names = null;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* 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.dto.responses;

import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.ToString;
import org.apache.gravitino.dto.authorization.UserDTO;

/** Represents a response containing a list of users. */
@Getter
@ToString
@EqualsAndHashCode(callSuper = true)
public class UserListResponse extends BaseResponse {

@JsonProperty("users")
private final UserDTO[] users;

/**
* Constructor for UserListResponse.
*
* @param users The array of users.
*/
public UserListResponse(UserDTO[] users) {
super(0);
this.users = users;
}

/**
* This is the constructor that is used by Jackson deserializer to create an instance of
* UserListResponse.
*/
public UserListResponse() {
super(0);
this.users = null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -628,6 +628,19 @@ public static CatalogDTO[] toDTOs(Catalog[] catalogs) {
return Arrays.stream(catalogs).map(DTOConverters::toDTO).toArray(CatalogDTO[]::new);
}

/**
* Converts an array of Users to an array of UserDTOs.
*
* @param users The users to be converted.
* @return The array of UserDTOs.
*/
public static UserDTO[] toDTOs(User[] users) {
if (ArrayUtils.isEmpty(users)) {
return new UserDTO[0];
}
return Arrays.stream(users).map(DTOConverters::toDTO).toArray(UserDTO[]::new);
}

/**
* Converts a DistributionDTO to a Distribution.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,14 @@ public User getUser(String metalake, String user)
return doWithNonAdminLock(() -> userGroupManager.getUser(metalake, user));
}

public String[] listUserNames(String metalake) throws NoSuchMetalakeException {
return userGroupManager.listUserNames(metalake);
}

public User[] listUsers(String metalake) throws NoSuchMetalakeException {
return userGroupManager.listUsers(metalake);
}

/**
* Adds a new Group.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,11 @@
import org.apache.gravitino.Entity;
import org.apache.gravitino.EntityAlreadyExistsException;
import org.apache.gravitino.EntityStore;
import org.apache.gravitino.Namespace;
import org.apache.gravitino.exceptions.GroupAlreadyExistsException;
import org.apache.gravitino.exceptions.NoSuchEntityException;
import org.apache.gravitino.exceptions.NoSuchGroupException;
import org.apache.gravitino.exceptions.NoSuchMetalakeException;
import org.apache.gravitino.exceptions.NoSuchUserException;
import org.apache.gravitino.exceptions.UserAlreadyExistsException;
import org.apache.gravitino.meta.AuditInfo;
Expand All @@ -46,6 +48,7 @@
class UserGroupManager {

private static final Logger LOG = LoggerFactory.getLogger(UserGroupManager.class);
private static final String METALAKE_DOES_NOT_EXIST_MSG = "Metalake %s does not exist";

private final EntityStore store;
private final IdGenerator idGenerator;
Expand Down Expand Up @@ -109,6 +112,37 @@ User getUser(String metalake, String user) throws NoSuchUserException {
}
}

String[] listUserNames(String metalake) {
try {
AuthorizationUtils.checkMetalakeExists(metalake);
Namespace namespace = AuthorizationUtils.ofUserNamespace(metalake);
return store.list(namespace, UserEntity.class, Entity.EntityType.USER).stream()
.map(UserEntity::name)
.toArray(String[]::new);
} catch (NoSuchEntityException e) {
LOG.warn("Metalake {} does not exist", metalake, e);
throw new NoSuchMetalakeException(METALAKE_DOES_NOT_EXIST_MSG, metalake);
} catch (IOException ioe) {
LOG.error("Listing user under metalake {} failed due to storage issues", metalake, ioe);
throw new RuntimeException(ioe);
}
}

User[] listUsers(String metalake) {
try {
Namespace namespace = AuthorizationUtils.ofUserNamespace(metalake);
return store.list(namespace, UserEntity.class, Entity.EntityType.USER).stream()
.map(entity -> (User) entity)
.toArray(User[]::new);
} catch (NoSuchEntityException e) {
LOG.warn("Metalake {} does not exist", metalake, e);
throw new NoSuchMetalakeException(METALAKE_DOES_NOT_EXIST_MSG, metalake);
} catch (IOException ioe) {
LOG.error("Listing user under metalake {} failed due to storage issues", metalake, ioe);
throw new RuntimeException(ioe);
}
}

Group addGroup(String metalake, String group) throws GroupAlreadyExistsException {
try {
AuthorizationUtils.checkMetalakeExists(metalake);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,8 @@ public <E extends Entity & HasIdentifier> List<E> list(
return (List<E>) TopicMetaService.getInstance().listTopicsByNamespace(namespace);
case TAG:
return (List<E>) TagMetaService.getInstance().listTagsByNamespace(namespace);
case USER:
return (List<E>) UserMetaService.getInstance().listUsersByNamespace(namespace);
default:
throw new UnsupportedEntityTypeException(
"Unsupported entity type: %s for list operation", entityType);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,18 @@ Long selectUserIdByMetalakeIdAndName(
UserPO selectUserMetaByMetalakeIdAndName(
@Param("metalakeId") Long metalakeId, @Param("userName") String name);

@Select(
"SELECT user_id as userId, user_name as userName,"
+ " metalake_id as metalakeId,"
+ " audit_info as auditInfo,"
+ " current_version as currentVersion, last_version as lastVersion,"
+ " deleted_at as deletedAt"
+ " FROM "
+ USER_TABLE_NAME
+ " WHERE metalake_id = #{metalakeId}"
+ " AND deleted_at = 0")
List<UserPO> listUserPOsByMetalakeId(@Param("metalakeId") Long metalakeId);

@Insert(
"INSERT INTO "
+ USER_TABLE_NAME
Expand Down
Loading

0 comments on commit a57e4e3

Please sign in to comment.