diff options
author | Morten Tokle <mortent@vespa.ai> | 2024-04-08 11:09:25 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-04-08 11:09:25 +0200 |
commit | 88b23778c4a4bc6b3210e82f0aab015deb6a7495 (patch) | |
tree | de435ffddc80077d7c1fef7278d5eafe5fef645e | |
parent | 39fcf4849c673bed1e9650dc27b30564474c1623 (diff) | |
parent | fbdcc1a57406d869bac44ff80f666b0ced77e162 (diff) |
Merge pull request #30847 from vespa-engine/mortent/flag-roles
Flag to support role definitions
4 files changed, 163 insertions, 2 deletions
diff --git a/flags/src/main/java/com/yahoo/vespa/flags/Flags.java b/flags/src/main/java/com/yahoo/vespa/flags/Flags.java index e038c96bf99..03a713f37f5 100644 --- a/flags/src/main/java/com/yahoo/vespa/flags/Flags.java +++ b/flags/src/main/java/com/yahoo/vespa/flags/Flags.java @@ -3,6 +3,7 @@ package com.yahoo.vespa.flags; import com.yahoo.component.Vtag; import com.yahoo.vespa.defaults.Defaults; +import com.yahoo.vespa.flags.custom.RoleList; import java.time.Instant; import java.time.LocalDate; @@ -14,8 +15,6 @@ import java.util.TreeMap; import java.util.function.Predicate; import static com.yahoo.vespa.flags.Dimension.APPLICATION; -import static com.yahoo.vespa.flags.Dimension.ARCHITECTURE; -import static com.yahoo.vespa.flags.Dimension.CLAVE; import static com.yahoo.vespa.flags.Dimension.CLOUD_ACCOUNT; import static com.yahoo.vespa.flags.Dimension.CONSOLE_USER_EMAIL; import static com.yahoo.vespa.flags.Dimension.HOSTNAME; @@ -417,6 +416,12 @@ public class Flags { "Whether to use athenz as node identity provider", "Takes effect on next identity refresh", HOSTNAME); + public static UnboundJacksonFlag<RoleList> ROLE_DEFINITIONS = defineJacksonFlag( + "role-definitions", RoleList.empty(), RoleList.class, + List.of("mortent"), "2024-04-05", "2024-10-01", + "Role definitions for the system", + "Takes effect immediately"); + /** WARNING: public for testing: All flags should be defined in {@link Flags}. */ public static UnboundBooleanFlag defineFeatureFlag(String flagId, boolean defaultValue, List<String> owners, String createdAt, String expiresAt, String description, diff --git a/flags/src/main/java/com/yahoo/vespa/flags/custom/Role.java b/flags/src/main/java/com/yahoo/vespa/flags/custom/Role.java new file mode 100644 index 00000000000..93845b6f59d --- /dev/null +++ b/flags/src/main/java/com/yahoo/vespa/flags/custom/Role.java @@ -0,0 +1,55 @@ +// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + +package com.yahoo.vespa.flags.custom; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.List; +import java.util.Objects; + +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(value = JsonInclude.Include.NON_NULL) +public class Role { + @JsonProperty("name") + private final String name; + @JsonProperty("members") + private final List<String> members; + + @JsonCreator + public Role(@JsonProperty("name") String name, @JsonProperty("members") List<String> members) { + this.name = name; + this.members = members; + } + + public String getName() { + return name; + } + + public List<String> getMembers() { + return members; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Role that = (Role) o; + return Objects.equals(name, that.name) && Objects.equals(members, that.members); + } + + @Override + public int hashCode() { + return Objects.hash(name, members); + } + + @Override + public String toString() { + return "RoleDefinition{" + + "name='" + name + '\'' + + ", members=" + members + + '}'; + } +} diff --git a/flags/src/main/java/com/yahoo/vespa/flags/custom/RoleList.java b/flags/src/main/java/com/yahoo/vespa/flags/custom/RoleList.java new file mode 100644 index 00000000000..4e3d14bf076 --- /dev/null +++ b/flags/src/main/java/com/yahoo/vespa/flags/custom/RoleList.java @@ -0,0 +1,45 @@ +// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + +package com.yahoo.vespa.flags.custom; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.List; +import java.util.Objects; + +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(value = JsonInclude.Include.NON_NULL) +public class RoleList { + + @JsonProperty("roles") + List<Role> roles; + + @JsonCreator + public RoleList(@JsonProperty("roles") List<Role> roles) { + this.roles = roles; + } + + public List<Role> roles() { + return roles; + } + + public static RoleList empty() { + return new RoleList(List.of()); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + RoleList roleList = (RoleList) o; + return Objects.equals(roles, roleList.roles); + } + + @Override + public int hashCode() { + return Objects.hash(roles); + } +} diff --git a/flags/src/test/java/com/yahoo/vespa/flags/custom/RoleTest.java b/flags/src/test/java/com/yahoo/vespa/flags/custom/RoleTest.java new file mode 100644 index 00000000000..2b1290f5222 --- /dev/null +++ b/flags/src/test/java/com/yahoo/vespa/flags/custom/RoleTest.java @@ -0,0 +1,56 @@ +// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + +package com.yahoo.vespa.flags.custom; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.yahoo.test.json.Jackson; +import org.junit.jupiter.api.Test; + +import java.util.List; +import java.util.Optional; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class RoleTest { + + @Test + void deSerializesCorrectly() throws JsonProcessingException { + String json = """ + { + "roles": [ + { + "name": "role1", + "members": ["u1@example.com", "u2@example.com"] + }, + { + "name": "role2", + "members": [ "u1@example.com" ] + } + ] + } + """; + var mapper = Jackson.mapper(); + RoleList roleList = mapper.readValue(json, RoleList.class); + assertEquals(2, roleList.roles().size()); + Optional<Role> role1 = roleList.roles().stream() + .filter(r -> r.getName().equals("role1")) + .findFirst(); + assertEquals(2, role1.get().getMembers().size()); + + Optional<Role> role2 = roleList.roles().stream() + .filter(r -> r.getName().equals("role2")) + .findFirst(); + assertEquals(1, role2.get().getMembers().size()); + } + + @Test + void serializeCorrectly() throws JsonProcessingException { + Role role1 = new Role("role1", List.of("u1", "u2")); + Role role2 = new Role("role2", List.of("u1")); + RoleList roleList = new RoleList(List.of(role1, role2)); + var mapper = Jackson.mapper(); + String serialized = mapper.writeValueAsString(roleList); + RoleList deserialized = mapper.readValue(serialized, RoleList.class); + assertEquals(roleList, deserialized); + } +}
\ No newline at end of file |