aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMorten Tokle <mortent@vespa.ai>2024-04-08 11:09:25 +0200
committerGitHub <noreply@github.com>2024-04-08 11:09:25 +0200
commit88b23778c4a4bc6b3210e82f0aab015deb6a7495 (patch)
treede435ffddc80077d7c1fef7278d5eafe5fef645e
parent39fcf4849c673bed1e9650dc27b30564474c1623 (diff)
parentfbdcc1a57406d869bac44ff80f666b0ced77e162 (diff)
Merge pull request #30847 from vespa-engine/mortent/flag-roles
Flag to support role definitions
-rw-r--r--flags/src/main/java/com/yahoo/vespa/flags/Flags.java9
-rw-r--r--flags/src/main/java/com/yahoo/vespa/flags/custom/Role.java55
-rw-r--r--flags/src/main/java/com/yahoo/vespa/flags/custom/RoleList.java45
-rw-r--r--flags/src/test/java/com/yahoo/vespa/flags/custom/RoleTest.java56
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