imbajin commented on code in PR #3096:
URL: https://github.com/apache/hugegraph/pull/3096#discussion_r3610057865
##########
hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/auth/AuthManager.java:
##########
@@ -53,6 +53,11 @@ public interface AuthManager {
HugeGroup deleteGroup(Id id);
+ default HugeGroup deleteGroup(String graphSpace, Id id) {
Review Comment:
‼️ These scoped overloads are not overridden by
`HugeGraphAuthProxy.AuthManagerProxy`, which is the manager returned to REST
calls when authentication is enabled. Scoped group deletion therefore always
reaches this default exception, while target/belong/access calls fall back to
unscoped proxy methods and lose the requested graph space. Please override and
delegate every scoped overload in the proxy while preserving its permission,
creator, and cache behavior, and cover non-default graph-space CRUD through the
authenticated proxy.
##########
hugegraph-server/hugegraph-api/src/main/java/org/apache/hugegraph/api/auth/GraphSpaceGroupAPI.java:
##########
@@ -0,0 +1,299 @@
+/*
+ * 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.hugegraph.api.auth;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+
+import org.apache.hugegraph.api.API;
+import org.apache.hugegraph.api.filter.StatusFilter.Status;
+import org.apache.hugegraph.auth.AuthManager;
+import org.apache.hugegraph.auth.HugeBelong;
+import org.apache.hugegraph.auth.HugeGraphAuthProxy;
+import org.apache.hugegraph.auth.HugeGroup;
+import org.apache.hugegraph.auth.HugeUser;
+import org.apache.hugegraph.auth.StandardAuthManagerV2;
+import org.apache.hugegraph.backend.id.Id;
+import org.apache.hugegraph.core.GraphManager;
+import org.apache.hugegraph.define.Checkable;
+import org.apache.hugegraph.exception.NotFoundException;
+import org.apache.hugegraph.util.E;
+import org.apache.hugegraph.util.Log;
+import org.slf4j.Logger;
+
+import com.codahale.metrics.annotation.Timed;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.inject.Singleton;
+import jakarta.ws.rs.Consumes;
+import jakarta.ws.rs.DELETE;
+import jakarta.ws.rs.DefaultValue;
+import jakarta.ws.rs.ForbiddenException;
+import jakarta.ws.rs.GET;
+import jakarta.ws.rs.POST;
+import jakarta.ws.rs.PUT;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.PathParam;
+import jakarta.ws.rs.Produces;
+import jakarta.ws.rs.QueryParam;
+import jakarta.ws.rs.core.Context;
+
+@Path("graphspaces/{graphspace}/auth/groups")
+@Singleton
+@Tag(name = "GraphSpaceGroupAPI")
+public class GraphSpaceGroupAPI extends API {
+
+ private static final Logger LOG = Log.logger(GraphSpaceGroupAPI.class);
+
+ @POST
+ @Timed
+ @Status(Status.CREATED)
+ @Consumes(APPLICATION_JSON)
+ @Produces(APPLICATION_JSON_WITH_CHARSET)
+ public String create(@Context GraphManager manager,
+ @PathParam("graphspace") String graphSpace,
+ JsonGroup jsonGroup) {
+ LOG.debug("GraphSpace [{}] create scoped group", graphSpace);
+ ensureManager(manager, graphSpace);
+ checkCreatingBody(jsonGroup);
+ HugeGroup group = jsonGroup.build(graphSpace);
+ checkScopedGroup(graphSpace, group);
+ group.id(manager.authManager().createGroup(group));
+ return manager.serializer().writeAuthElement(group);
+ }
+
+ @PUT
+ @Timed
+ @Path("{id}")
+ @Consumes(APPLICATION_JSON)
+ @Produces(APPLICATION_JSON_WITH_CHARSET)
+ public String update(@Context GraphManager manager,
+ @PathParam("graphspace") String graphSpace,
+ @PathParam("id") String id,
+ JsonGroup jsonGroup) {
+ LOG.debug("GraphSpace [{}] update scoped group", graphSpace);
+ ensureManager(manager, graphSpace);
+ checkUpdatingBody(jsonGroup);
+ HugeGroup group = getGroup(manager.authManager(), id);
+ checkScopedGroup(graphSpace, group);
+ group = jsonGroup.build(group);
+ manager.authManager().updateGroup(group);
+ return manager.serializer().writeAuthElement(group);
+ }
+
+ @GET
+ @Timed
+ @Produces(APPLICATION_JSON_WITH_CHARSET)
+ public String list(@Context GraphManager manager,
+ @PathParam("graphspace") String graphSpace,
+ @QueryParam("limit") @DefaultValue("100") long limit) {
+ LOG.debug("GraphSpace [{}] list scoped groups", graphSpace);
+ ensureManager(manager, graphSpace);
+ List<HugeGroup> groups = listScopedGroups(manager.authManager(),
+ graphSpace, limit);
+ return manager.serializer().writeAuthElements("groups", groups);
+ }
+
+ static List<HugeGroup> listScopedGroups(AuthManager authManager,
+ String graphSpace, long limit) {
+ List<HugeGroup> groups = authManager.listAllGroups(-1);
+ groups = filterScopedGroups(graphSpace, groups);
+ return applyLimit(groups, limit);
+ }
+
+ static <T> List<T> applyLimit(List<T> values, long limit) {
+ E.checkArgument(limit >= -1L,
+ "The limit must be -1 or a non-negative number");
+ if (limit >= 0L && values.size() > limit) {
+ return new ArrayList<>(values.subList(0, (int) limit));
+ }
+ return values;
+ }
+
+ @GET
+ @Timed
+ @Path("{id}")
+ @Produces(APPLICATION_JSON_WITH_CHARSET)
+ public String get(@Context GraphManager manager,
+ @PathParam("graphspace") String graphSpace,
+ @Parameter(description = "The scoped group id")
+ @PathParam("id") String id) {
+ LOG.debug("GraphSpace [{}] get scoped group", graphSpace);
+ ensureManager(manager, graphSpace);
+ HugeGroup group = getGroup(manager.authManager(), id);
+ checkScopedGroup(graphSpace, group);
+ return manager.serializer().writeAuthElement(group);
+ }
+
+ @DELETE
+ @Timed
+ @Path("{id}")
+ @Consumes(APPLICATION_JSON)
+ public void delete(@Context GraphManager manager,
+ @PathParam("graphspace") String graphSpace,
+ @Parameter(description = "The scoped group id")
+ @PathParam("id") String id) {
+ LOG.debug("GraphSpace [{}] delete scoped group", graphSpace);
+ ensureManager(manager, graphSpace);
+ HugeGroup group = getGroup(manager.authManager(), id);
+ checkScopedGroup(graphSpace, group);
+ manager.authManager().deleteGroup(graphSpace, group.id());
+ }
+
+ static void checkManagerPermission(AuthManager authManager,
+ String graphSpace, String username) {
+ validPermission(authManager.isAdminManager(username) ||
+ authManager.isSpaceManager(graphSpace, username),
+ username, "graphspace-group.manage");
+ }
+
+ static List<HugeGroup> filterScopedGroups(String graphSpace,
+ List<HugeGroup> groups) {
+ List<HugeGroup> scoped = new ArrayList<>();
+ for (HugeGroup group : groups) {
+ if (isScopedGroup(graphSpace, group)) {
+ scoped.add(group);
+ }
+ }
+ return scoped;
+ }
+
+ static void checkScopedGroup(String graphSpace, HugeGroup group) {
+ if (!isScopedGroup(graphSpace, group)) {
+ throw new ForbiddenException(
+ "Permission denied: group belongs to another graphspace");
+ }
+ }
+
+ static String scopedPrefix(String graphSpace) {
+ return StandardAuthManagerV2.scopedGroupPrefix(graphSpace);
+ }
+
+ static void ensureManager(GraphManager manager, String graphSpace) {
+ ensurePdModeEnabled(manager);
+ ensureAuthManager(manager, graphSpace);
+ }
+
+ static void ensureAuthManager(GraphManager manager, String graphSpace) {
+ E.checkArgument(manager.graphSpace(graphSpace) != null,
+ "The graph space '%s' does not exist", graphSpace);
+ checkManagerPermission(manager.authManager(), graphSpace,
Review Comment:
‼️ This gate is also used by the existing target, belong, and access routes,
but standalone `StandardAuthManager` returns `false` for both
`isAdminManager()` and `isSpaceManager()`. As a result, even the built-in admin
is denied for `/graphspaces/DEFAULT/auth/{targets,belongs,accesses}` after
upgrade. Please apply this manager-role gate only to the V2/PD mode or provide
equivalent standalone admin semantics, with REST regressions for standalone
DEFAULT auth enabled and disabled.
##########
hugegraph-server/hugegraph-api/src/main/java/org/apache/hugegraph/api/auth/GraphSpaceGroupAPI.java:
##########
@@ -0,0 +1,299 @@
+/*
+ * 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.hugegraph.api.auth;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+
+import org.apache.hugegraph.api.API;
+import org.apache.hugegraph.api.filter.StatusFilter.Status;
+import org.apache.hugegraph.auth.AuthManager;
+import org.apache.hugegraph.auth.HugeBelong;
+import org.apache.hugegraph.auth.HugeGraphAuthProxy;
+import org.apache.hugegraph.auth.HugeGroup;
+import org.apache.hugegraph.auth.HugeUser;
+import org.apache.hugegraph.auth.StandardAuthManagerV2;
+import org.apache.hugegraph.backend.id.Id;
+import org.apache.hugegraph.core.GraphManager;
+import org.apache.hugegraph.define.Checkable;
+import org.apache.hugegraph.exception.NotFoundException;
+import org.apache.hugegraph.util.E;
+import org.apache.hugegraph.util.Log;
+import org.slf4j.Logger;
+
+import com.codahale.metrics.annotation.Timed;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.inject.Singleton;
+import jakarta.ws.rs.Consumes;
+import jakarta.ws.rs.DELETE;
+import jakarta.ws.rs.DefaultValue;
+import jakarta.ws.rs.ForbiddenException;
+import jakarta.ws.rs.GET;
+import jakarta.ws.rs.POST;
+import jakarta.ws.rs.PUT;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.PathParam;
+import jakarta.ws.rs.Produces;
+import jakarta.ws.rs.QueryParam;
+import jakarta.ws.rs.core.Context;
+
+@Path("graphspaces/{graphspace}/auth/groups")
+@Singleton
+@Tag(name = "GraphSpaceGroupAPI")
+public class GraphSpaceGroupAPI extends API {
+
+ private static final Logger LOG = Log.logger(GraphSpaceGroupAPI.class);
+
+ @POST
+ @Timed
+ @Status(Status.CREATED)
+ @Consumes(APPLICATION_JSON)
+ @Produces(APPLICATION_JSON_WITH_CHARSET)
+ public String create(@Context GraphManager manager,
+ @PathParam("graphspace") String graphSpace,
+ JsonGroup jsonGroup) {
+ LOG.debug("GraphSpace [{}] create scoped group", graphSpace);
+ ensureManager(manager, graphSpace);
+ checkCreatingBody(jsonGroup);
+ HugeGroup group = jsonGroup.build(graphSpace);
+ checkScopedGroup(graphSpace, group);
+ group.id(manager.authManager().createGroup(group));
+ return manager.serializer().writeAuthElement(group);
+ }
+
+ @PUT
+ @Timed
+ @Path("{id}")
+ @Consumes(APPLICATION_JSON)
+ @Produces(APPLICATION_JSON_WITH_CHARSET)
+ public String update(@Context GraphManager manager,
+ @PathParam("graphspace") String graphSpace,
+ @PathParam("id") String id,
+ JsonGroup jsonGroup) {
+ LOG.debug("GraphSpace [{}] update scoped group", graphSpace);
+ ensureManager(manager, graphSpace);
+ checkUpdatingBody(jsonGroup);
+ HugeGroup group = getGroup(manager.authManager(), id);
+ checkScopedGroup(graphSpace, group);
+ group = jsonGroup.build(group);
+ manager.authManager().updateGroup(group);
+ return manager.serializer().writeAuthElement(group);
+ }
+
+ @GET
+ @Timed
+ @Produces(APPLICATION_JSON_WITH_CHARSET)
+ public String list(@Context GraphManager manager,
+ @PathParam("graphspace") String graphSpace,
+ @QueryParam("limit") @DefaultValue("100") long limit) {
+ LOG.debug("GraphSpace [{}] list scoped groups", graphSpace);
+ ensureManager(manager, graphSpace);
+ List<HugeGroup> groups = listScopedGroups(manager.authManager(),
+ graphSpace, limit);
+ return manager.serializer().writeAuthElements("groups", groups);
+ }
+
+ static List<HugeGroup> listScopedGroups(AuthManager authManager,
+ String graphSpace, long limit) {
+ List<HugeGroup> groups = authManager.listAllGroups(-1);
+ groups = filterScopedGroups(graphSpace, groups);
+ return applyLimit(groups, limit);
+ }
+
+ static <T> List<T> applyLimit(List<T> values, long limit) {
+ E.checkArgument(limit >= -1L,
+ "The limit must be -1 or a non-negative number");
+ if (limit >= 0L && values.size() > limit) {
+ return new ArrayList<>(values.subList(0, (int) limit));
+ }
+ return values;
+ }
+
+ @GET
+ @Timed
+ @Path("{id}")
+ @Produces(APPLICATION_JSON_WITH_CHARSET)
+ public String get(@Context GraphManager manager,
+ @PathParam("graphspace") String graphSpace,
+ @Parameter(description = "The scoped group id")
+ @PathParam("id") String id) {
+ LOG.debug("GraphSpace [{}] get scoped group", graphSpace);
+ ensureManager(manager, graphSpace);
+ HugeGroup group = getGroup(manager.authManager(), id);
+ checkScopedGroup(graphSpace, group);
+ return manager.serializer().writeAuthElement(group);
+ }
+
+ @DELETE
+ @Timed
+ @Path("{id}")
+ @Consumes(APPLICATION_JSON)
+ public void delete(@Context GraphManager manager,
+ @PathParam("graphspace") String graphSpace,
+ @Parameter(description = "The scoped group id")
+ @PathParam("id") String id) {
+ LOG.debug("GraphSpace [{}] delete scoped group", graphSpace);
+ ensureManager(manager, graphSpace);
+ HugeGroup group = getGroup(manager.authManager(), id);
+ checkScopedGroup(graphSpace, group);
+ manager.authManager().deleteGroup(graphSpace, group.id());
+ }
+
+ static void checkManagerPermission(AuthManager authManager,
+ String graphSpace, String username) {
+ validPermission(authManager.isAdminManager(username) ||
+ authManager.isSpaceManager(graphSpace, username),
+ username, "graphspace-group.manage");
+ }
+
+ static List<HugeGroup> filterScopedGroups(String graphSpace,
+ List<HugeGroup> groups) {
+ List<HugeGroup> scoped = new ArrayList<>();
+ for (HugeGroup group : groups) {
+ if (isScopedGroup(graphSpace, group)) {
+ scoped.add(group);
+ }
+ }
+ return scoped;
+ }
+
+ static void checkScopedGroup(String graphSpace, HugeGroup group) {
+ if (!isScopedGroup(graphSpace, group)) {
+ throw new ForbiddenException(
+ "Permission denied: group belongs to another graphspace");
+ }
+ }
+
+ static String scopedPrefix(String graphSpace) {
+ return StandardAuthManagerV2.scopedGroupPrefix(graphSpace);
+ }
+
+ static void ensureManager(GraphManager manager, String graphSpace) {
+ ensurePdModeEnabled(manager);
+ ensureAuthManager(manager, graphSpace);
+ }
+
+ static void ensureAuthManager(GraphManager manager, String graphSpace) {
+ E.checkArgument(manager.graphSpace(graphSpace) != null,
+ "The graph space '%s' does not exist", graphSpace);
+ checkManagerPermission(manager.authManager(), graphSpace,
+ HugeGraphAuthProxy.username());
+ }
+
+ static void checkBelongReferences(AuthManager authManager,
+ String graphSpace,
+ HugeBelong belong) {
+ if (!(authManager instanceof StandardAuthManagerV2)) {
Review Comment:
‼️ In authenticated requests the supplied manager is `AuthManagerProxy`, so
this concrete-type check returns before validating membership or group scope. A
space manager can consequently reference a user who is not a member of this
space, or a group from another space, when creating belongs/accesses;
lower-level metadata checks only verify global existence. Please expose
scope-aware validation through `AuthManager` and delegate it through the proxy
instead of gating on the concrete class, then add cross-space REST tests.
##########
hugegraph-server/hugegraph-api/src/main/java/org/apache/hugegraph/api/auth/AccessAPI.java:
##########
@@ -114,20 +141,35 @@ public String list(@Context GraphManager manager,
@QueryParam("limit") @DefaultValue("100") long limit) {
LOG.debug("GraphSpace [{}] list accesses by group {} or target {}",
graphSpace, group, target);
+ GraphSpaceGroupAPI.ensureAuthManager(manager, graphSpace);
E.checkArgument(group == null || target == null,
"Can't pass both group and target at the same time");
- List<HugeAccess> belongs;
+ Id groupId = group == null ? null : UserAPI.parseId(group);
+ Id targetId = target == null ? null : UserAPI.parseId(target);
+ List<HugeAccess> accesses = listScopedAccesses(manager.authManager(),
+ graphSpace, groupId,
+ targetId, limit);
+ return manager.serializer().writeAuthElements("accesses", accesses);
+ }
+
+ static List<HugeAccess> listScopedAccesses(AuthManager authManager,
+ String graphSpace, Id group,
+ Id target, long limit) {
+ List<HugeAccess> accesses;
if (group != null) {
- Id id = UserAPI.parseId(group);
- belongs = manager.authManager().listAccessByGroup(id, limit);
+ accesses = authManager.listAccessByGroup(graphSpace, group, -1L);
} else if (target != null) {
- Id id = UserAPI.parseId(target);
- belongs = manager.authManager().listAccessByTarget(id, limit);
+ accesses = authManager.listAccessByTarget(graphSpace, target,
+ -1L);
} else {
- belongs = manager.authManager().listAllAccess(limit);
+ accesses = authManager.listAllAccess(graphSpace, -1L);
}
- return manager.serializer().writeAuthElements("accesses", belongs);
+ accesses = accesses.stream()
Review Comment:
‼️ Filtering only on `access.graphSpace()` includes the built-in role
accesses stored in the same space. Those records do not resolve to a scoped
business group, yet `checkScopedGroupReference()` treats a missing group as
valid and GET/DELETE do not call it, so a space manager can enumerate or delete
default SPACE/SPACE_MEMBER/analyst/observer authorization links. Please require
a verified scoped-group source for this business API and keep built-in role
metadata hidden and immutable; cover list/get/update/delete with a
built-in-role access.
##########
hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/auth/HugeTarget.java:
##########
@@ -226,10 +246,15 @@ public Map<String, Object> asMap() {
Map<String, Object> map = new HashMap<>();
+ map.put(Hidden.unHide(P.GRAPHSPACE), this.graphSpace);
Review Comment:
⚠️ New nodes now persist `graphspace` (and optionally `target_description`)
in shared target metadata, but the previous `HugeTarget.property()` throws
`AssertionError` for both unknown keys. During a rolling upgrade, an older
server reading a target written by a new server can therefore fail target
loading and dependent authorization. Please version or feature-gate the new
persisted format, avoid writing fields that old readers cannot accept where the
scope can be derived from the metadata namespace, or explicitly block
mixed-version operation; add an old-reader/new-writer compatibility test.
##########
hugegraph-server/hugegraph-api/src/main/java/org/apache/hugegraph/auth/WsAndHttpBasicAuthHandler.java:
##########
@@ -103,28 +107,21 @@ public void channelRead(ChannelHandlerContext ctx, Object
msg) {
return;
}
- // strip off "Basic " from the Authorization header (RFC 2617)
- final String basic = "Basic ";
final String header = request.headers().get("Authorization");
- if (!header.startsWith(basic)) {
- sendError(ctx, msg);
- return;
- }
- byte[] userPass = null;
- try {
- final String encoded = header.substring(basic.length());
- userPass = this.decoder.decode(encoded);
- } catch (IndexOutOfBoundsException iae) {
- sendError(ctx, msg);
- return;
- } catch (IllegalArgumentException iae) {
- sendError(ctx, msg);
- return;
- }
- String authorization = new String(userPass,
- StandardCharsets.UTF_8);
- String[] split = authorization.split(":");
- if (split.length != 2) {
+ final Map<String, String> credentials = new HashMap<>();
+ if (header.startsWith(BASIC_AUTH_PREFIX)) {
Review Comment:
⚠️ HTTP authentication scheme names are case-insensitive, but these
`startsWith("Basic ")` / `startsWith("Bearer ")` checks reject valid `basic` or
`bearer` variants with 401. Please split the scheme from credentials, compare
the scheme with `equalsIgnoreCase`, preserve the credential payload unchanged,
and add case-variant tests.
##########
hugegraph-pd/hg-pd-service/src/main/java/org/apache/hugegraph/pd/service/SDConfigService.java:
##########
@@ -215,34 +215,14 @@ private Set<String> getStoreAddresses() {
return res;
}
- // TODO: optimized store registry data, to add host:port of REST server.
+ // Keep the legacy gRPC fallback when no valid REST port is registered.
private String getRestAddress(Metapb.Store store) {
String address = store.getAddress();
if (address == null || address.isEmpty()) {
return null;
}
- try {
- Optional<String> port = store.getLabelsList().stream().map(
- e -> {
- if ("rest.port".equals(e.getKey())) {
- return e.getValue();
- }
- return null;
- }).filter(e -> e != null).findFirst();
-
- if (port.isPresent()) {
- java.net.URI uri = address.contains("://")
- ? java.net.URI.create(address)
- : java.net.URI.create("http://" + address);
- String host = uri.getHost() != null ? uri.getHost() : address;
- String hostPart =
- host.contains(":") && !host.startsWith("[") ? "[" +
host + "]" : host;
- address = hostPart + ":" + port.get().trim();
- }
- } catch (Throwable t) {
- log.error("Failed to extract the REST address of store, cause
by:", t);
- }
- return address;
+ String restAddress = StoreRestAddressUtil.getRestAddress(store);
+ return restAddress != null ? restAddress : address;
Review Comment:
⚠️ `StoreRestAddressUtil` returns null when `rest.port` is absent or
invalid, but this fallback publishes the Store gRPC address as a monitoring
target while the discovery scheme remains HTTP. Prometheus will then request
`/actuator/prometheus` from a gRPC port, and this also disagrees with
`StoreAPI`, which exposes a null REST address. Please omit stores without a
validated REST endpoint (or only fall back when the address is known to be
HTTP) and add missing/invalid-port service-discovery tests.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]