[#41] Add APE rule serializer
All checks were successful
DCO / DCO (pull_request) Successful in 26s
Verify code phase / Verify code (pull_request) Successful in 1m38s

Signed-off-by: Ori Bruk <o.bruk@yadro.com>
This commit is contained in:
Ori Bruk 2025-02-13 20:25:29 +03:00
parent 532db56f1b
commit 3861eb0dc2
28 changed files with 542 additions and 143 deletions

View file

@ -0,0 +1,15 @@
package info.frostfs.sdk.dto.ape;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class Actions {
private boolean inverted;
private String[] names;
}

View file

@ -0,0 +1,17 @@
package info.frostfs.sdk.dto.ape;
import info.frostfs.sdk.enums.RuleMatchType;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class Chain {
private Byte[] id;
private Rule[] rules;
private RuleMatchType matchType;
}

View file

@ -0,0 +1,19 @@
package info.frostfs.sdk.dto.ape;
import info.frostfs.sdk.enums.ConditionKindType;
import info.frostfs.sdk.enums.ConditionType;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class Condition {
private ConditionType op;
private ConditionKindType kind;
private String key;
private String value;
}

View file

@ -0,0 +1,15 @@
package info.frostfs.sdk.dto.ape;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class Resources {
private boolean inverted;
private String[] names;
}

View file

@ -0,0 +1,27 @@
package info.frostfs.sdk.dto.ape;
import info.frostfs.sdk.enums.RuleStatus;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class Rule {
private RuleStatus status;
// Actions the operation is applied to.
private Actions actions;
// List of the resources the operation is applied to.
private Resources resources;
// True if individual conditions must be combined with the logical OR.
// By default, AND is used, so _each_ condition must pass.
private boolean any;
private Condition[] conditions;
}

View file

@ -1,10 +0,0 @@
package info.frostfs.sdk.dto.chain;
import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter
@AllArgsConstructor
public class Chain {
private final byte[] raw;
}

View file

@ -3,19 +3,21 @@ package info.frostfs.sdk.dto.response;
import info.frostfs.sdk.enums.StatusCode;
import lombok.Getter;
import lombok.Setter;
import org.apache.commons.lang3.StringUtils;
import static info.frostfs.sdk.constants.FieldConst.EMPTY_STRING;
import static java.util.Objects.isNull;
@Getter
@Setter
public class ResponseStatus {
private StatusCode code;
private String message;
private String details;
public ResponseStatus(StatusCode code, String message) {
public ResponseStatus(StatusCode code, String message, String details) {
this.code = code;
this.message = isNull(message) ? EMPTY_STRING : message;
this.message = StringUtils.isBlank(message) ? EMPTY_STRING : message;
this.details = StringUtils.isBlank(details) ? EMPTY_STRING : details;
}
public ResponseStatus(StatusCode code) {
@ -25,7 +27,7 @@ public class ResponseStatus {
@Override
public String toString() {
return String.format("Response status: %s. Message: %s.", code, message);
return String.format("Response status: %s. Message: %s. Details: %s", code, message, details);
}
public boolean isSuccess() {

View file

@ -0,0 +1,13 @@
package info.frostfs.sdk.enums;
public enum ConditionKindType {
RESOURCE(0),
REQUEST(1),
;
public final int value;
ConditionKindType(int value) {
this.value = value;
}
}

View file

@ -0,0 +1,36 @@
package info.frostfs.sdk.enums;
public enum ConditionType {
COND_STRING_EQUALS(0),
COND_STRING_NOT_EQUALS(1),
COND_STRING_EQUALS_IGNORE_CASE(2),
COND_STRING_NOT_EQUALS_IGNORE_CASE(3),
COND_STRING_LIKE(4),
COND_STRING_NOT_LIKE(5),
COND_STRING_LESS_THAN(6),
COND_STRING_LESS_THAN_EQUALS(7),
COND_STRING_GREATER_THAN(8),
COND_STRING_GREATER_THAN_EQUALS(9),
COND_NUMERIC_EQUALS(10),
COND_NUMERIC_NOT_EQUALS(11),
COND_NUMERIC_LESS_THAN(12),
COND_NUMERIC_LESS_THAN_EQUALS(13),
COND_NUMERIC_GREATER_THAN(14),
COND_NUMERIC_GREATER_THAN_EQUALS(15),
COND_SLICE_CONTAINS(16),
COND_IP_ADDRESS(17),
COND_NOT_IP_ADDRESS(18),
;
public final int value;
ConditionType(int value) {
this.value = value;
}
}

View file

@ -0,0 +1,16 @@
package info.frostfs.sdk.enums;
public enum RuleMatchType {
// DENY_PRIORITY rejects the request if any `Deny` is specified.
DENY_PRIORITY(0),
// FIRST_MATCH returns the first rule action matched to the request.
FIRST_MATCH(1),
;
public final int value;
RuleMatchType(int value) {
this.value = value;
}
}

View file

@ -0,0 +1,15 @@
package info.frostfs.sdk.enums;
public enum RuleStatus {
ALLOW(0),
NO_RULE_FOUND(1),
ACCESS_DENIED(2),
QUOTA_LIMIT_REACHED(3),
;
public final int value;
RuleStatus(int value) {
this.value = value;
}
}

View file

@ -1,31 +0,0 @@
package info.frostfs.sdk.mappers.chain;
import frostfs.ape.Types;
import info.frostfs.sdk.dto.chain.Chain;
import org.apache.commons.collections4.CollectionUtils;
import java.util.List;
import java.util.stream.Collectors;
import static java.util.Objects.isNull;
public class ChainMapper {
private ChainMapper() {
}
public static List<Chain> toModels(List<Types.Chain> chains) {
if (CollectionUtils.isEmpty(chains)) {
return null;
}
return chains.stream().map(ChainMapper::toModel).collect(Collectors.toList());
}
public static Chain toModel(Types.Chain chain) {
if (isNull(chain) || chain.getSerializedSize() == 0) {
return null;
}
return new Chain(chain.getRaw().toByteArray());
}
}

View file

@ -5,6 +5,9 @@ import info.frostfs.sdk.dto.response.ResponseStatus;
import info.frostfs.sdk.enums.StatusCode;
import info.frostfs.sdk.exceptions.ProcessFrostFSException;
import java.util.stream.Collectors;
import static info.frostfs.sdk.constants.ErrorConst.FIELDS_DELIMITER_COMMA;
import static info.frostfs.sdk.constants.ErrorConst.UNKNOWN_ENUM_VALUE_TEMPLATE;
import static java.util.Objects.isNull;
@ -24,6 +27,10 @@ public class ResponseStatusMapper {
);
}
return new ResponseStatus(statusCode, status.getMessage());
var stringDetails = status.getDetailsList().stream()
.map(t -> t.getValue().toStringUtf8())
.collect(Collectors.toList());
return new ResponseStatus(statusCode, status.getMessage(), String.join(FIELDS_DELIMITER_COMMA, stringDetails));
}
}

View file

@ -1,64 +0,0 @@
package info.frostfs.sdk.mappers.chain;
import com.google.protobuf.ByteString;
import frostfs.ape.Types;
import org.junit.jupiter.api.Test;
import java.util.Collections;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
public class ChainMapperTest {
@Test
void toModels_success() {
//Given
var chain1 = Types.Chain.newBuilder()
.setRaw(ByteString.copyFrom(new byte[]{1, 2, 3, 4, 5}))
.build();
var chain2 = Types.Chain.newBuilder()
.setRaw(ByteString.copyFrom(new byte[]{6, 7, 8, 9, 10}))
.build();
//When
var result = ChainMapper.toModels(List.of(chain1, chain2));
//Then
assertNotNull(result);
assertThat(result).hasSize(2);
assertThat(result.get(0).getRaw()).containsOnly(chain1.getRaw().toByteArray());
assertThat(result.get(1).getRaw()).containsOnly(chain2.getRaw().toByteArray());
}
@Test
void toModels_null() {
//When + Then
assertNull(ChainMapper.toModels(null));
assertNull(ChainMapper.toModels(Collections.emptyList()));
}
@Test
void toModel_success() {
//Given
var chain = Types.Chain.newBuilder()
.setRaw(ByteString.copyFrom(new byte[]{1, 2, 3, 4, 5}))
.build();
//When
var result = ChainMapper.toModel(chain);
//Then
assertNotNull(result);
assertThat(result.getRaw()).containsOnly(chain.getRaw().toByteArray());
}
@Test
void toModel_null() {
//When + Then
assertNull(ChainMapper.toModel(null));
assertNull(ChainMapper.toModel(Types.Chain.getDefaultInstance()));
}
}