Adding metadata endpoint (#1049)

* adding metadata endpoint

Signed-off-by: salaboy <Salaboy@gmail.com>

* apply formatting

Signed-off-by: salaboy <Salaboy@gmail.com>

* updating formatting

Signed-off-by: salaboy <Salaboy@gmail.com>

* updating formatting

Signed-off-by: salaboy <Salaboy@gmail.com>

* reverting formatting

Signed-off-by: salaboy <Salaboy@gmail.com>

* making domain classes final

Signed-off-by: salaboy <Salaboy@gmail.com>

* making domain model immutable

Signed-off-by: salaboy <Salaboy@gmail.com>

* equals/hashcode

Signed-off-by: salaboy <Salaboy@gmail.com>

* updating tests and clients

Signed-off-by: salaboy <Salaboy@gmail.com>

* rebasing after http client removed

Signed-off-by: salaboy <Salaboy@gmail.com>

* reverting delete

Signed-off-by: salaboy <Salaboy@gmail.com>

* adding space

Signed-off-by: salaboy <Salaboy@gmail.com>

* update copy and spaces

Signed-off-by: salaboy <Salaboy@gmail.com>

* eof line

Signed-off-by: salaboy <Salaboy@gmail.com>

* another new line

Signed-off-by: salaboy <Salaboy@gmail.com>

* adding coverage tests

Signed-off-by: salaboy <Salaboy@gmail.com>

* removing equals and hashcode

Signed-off-by: salaboy <Salaboy@gmail.com>

---------

Signed-off-by: salaboy <Salaboy@gmail.com>
This commit is contained in:
salaboy 2024-06-25 06:20:41 +01:00 committed by GitHub
parent 502f7c0638
commit 7e09841b4a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 332 additions and 5 deletions

View File

@ -14,6 +14,7 @@ limitations under the License.
package io.dapr.client;
import io.dapr.client.domain.ConfigurationItem;
import io.dapr.client.domain.DaprMetadata;
import io.dapr.client.domain.DeleteStateRequest;
import io.dapr.client.domain.ExecuteStateTransactionRequest;
import io.dapr.client.domain.GetBulkSecretRequest;
@ -671,6 +672,13 @@ public interface DaprClient extends AutoCloseable {
*/
<T extends AbstractStub<T>> T newGrpcStub(String appId, Function<Channel, T> stubBuilder);
/**
* Fetches Dapr Metadata from the metadata endpoint.
*
* @return DaprMetadata containing Dapr Metadata from the metadata endpoint.
*/
Mono<DaprMetadata> getMetadata();
/**
* Gracefully shutdown the dapr runtime.
*

View File

@ -20,7 +20,9 @@ import io.dapr.client.domain.BulkPublishEntry;
import io.dapr.client.domain.BulkPublishRequest;
import io.dapr.client.domain.BulkPublishResponse;
import io.dapr.client.domain.BulkPublishResponseFailedEntry;
import io.dapr.client.domain.ComponentMetadata;
import io.dapr.client.domain.ConfigurationItem;
import io.dapr.client.domain.DaprMetadata;
import io.dapr.client.domain.DeleteStateRequest;
import io.dapr.client.domain.ExecuteStateTransactionRequest;
import io.dapr.client.domain.GetBulkSecretRequest;
@ -36,11 +38,13 @@ import io.dapr.client.domain.PublishEventRequest;
import io.dapr.client.domain.QueryStateItem;
import io.dapr.client.domain.QueryStateRequest;
import io.dapr.client.domain.QueryStateResponse;
import io.dapr.client.domain.RuleMetadata;
import io.dapr.client.domain.SaveStateRequest;
import io.dapr.client.domain.State;
import io.dapr.client.domain.StateOptions;
import io.dapr.client.domain.SubscribeConfigurationRequest;
import io.dapr.client.domain.SubscribeConfigurationResponse;
import io.dapr.client.domain.SubscriptionMetadata;
import io.dapr.client.domain.TransactionalStateOperation;
import io.dapr.client.domain.UnlockRequest;
import io.dapr.client.domain.UnlockResponseStatus;
@ -58,6 +62,10 @@ import io.dapr.utils.TypeRef;
import io.dapr.v1.CommonProtos;
import io.dapr.v1.DaprGrpc;
import io.dapr.v1.DaprProtos;
import io.dapr.v1.DaprProtos.PubsubSubscription;
import io.dapr.v1.DaprProtos.PubsubSubscriptionRule;
import io.dapr.v1.DaprProtos.RegisteredComponents;
import io.grpc.CallOptions;
import io.grpc.Channel;
import io.grpc.stub.AbstractStub;
import io.grpc.stub.StreamObserver;
@ -118,7 +126,8 @@ public class DaprClientImpl extends AbstractDaprClient {
private final DaprHttp httpClient;
/**
* Default access level constructor, in order to create an instance of this class use io.dapr.client.DaprClientBuilder
* Default access level constructor, in order to create an instance of this
* class use io.dapr.client.DaprClientBuilder
*
* @param channel Facade for the managed GRPC channel
* @param asyncStub async gRPC stub
@ -1169,8 +1178,7 @@ public class DaprClientImpl extends AbstractDaprClient {
key,
configurationItem.getValue(),
configurationItem.getVersion(),
configurationItem.getMetadataMap()
);
configurationItem.getMetadataMap());
}
/**
@ -1231,4 +1239,43 @@ public class DaprClientImpl extends AbstractDaprClient {
}
};
}
}
@Override
public Mono<DaprMetadata> getMetadata() {
DaprProtos.GetMetadataRequest metadataRequest = DaprProtos.GetMetadataRequest.newBuilder().build();
return Mono.deferContextual(
context -> this.<DaprProtos.GetMetadataResponse>createMono(
it -> intercept(context, asyncStub).getMetadata(metadataRequest, it)))
.map(
it -> {
try {
return buildDaprMetadata(it);
} catch (IOException ex) {
throw DaprException.propagate(ex);
}
});
}
private DaprMetadata buildDaprMetadata(
DaprProtos.GetMetadataResponse response) throws IOException {
List<RegisteredComponents> registeredComponentsList = response.getRegisteredComponentsList();
List<ComponentMetadata> components = new ArrayList<>();
for (RegisteredComponents rc : registeredComponentsList) {
components.add(new ComponentMetadata(rc.getName(), rc.getType(), rc.getVersion()));
}
List<PubsubSubscription> subscriptionsList = response.getSubscriptionsList();
List<SubscriptionMetadata> subscriptions = new ArrayList<>();
for (PubsubSubscription s : subscriptionsList) {
List<PubsubSubscriptionRule> rulesList = s.getRules().getRulesList();
List<RuleMetadata> rules = new ArrayList<>();
for (PubsubSubscriptionRule r : rulesList) {
rules.add(new RuleMetadata(r.getPath()));
}
subscriptions.add(new SubscriptionMetadata(s.getTopic(), s.getPubsubName(), s.getDeadLetterTopic(), rules));
}
return new DaprMetadata(response.getId(), response.getRuntimeVersion(), components, subscriptions);
}
}

View File

@ -0,0 +1,52 @@
/*
* Copyright 2024 The Dapr Authors
* Licensed 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 io.dapr.client.domain;
import java.util.Objects;
/**
* ComponentMetadata describes a Dapr Component.
*/
public final class ComponentMetadata {
private String name;
private String type;
private String version;
/**
* Constructor for a ComponentMetadata.
*
* @param name of the component
* @param type component type
* @param version version of the component
*/
public ComponentMetadata(String name, String type, String version) {
this.name = name;
this.type = type;
this.version = version;
}
public String getName() {
return name;
}
public String getType() {
return type;
}
public String getVersion() {
return version;
}
}

View File

@ -0,0 +1,62 @@
/*
* Copyright 2024 The Dapr Authors
* Licensed 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 io.dapr.client.domain;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
/**
* DaprMetadata describes the Dapr Metadata.
*/
public final class DaprMetadata {
private String id;
private String runtimeVersion;
private List<ComponentMetadata> components;
private List<SubscriptionMetadata> subscriptions;
/**
* Constructor for a DaprMetadata.
*
* @param id of the application
* @param runtimeVersion Dapr version
* @param components list of registered componnets
* @param subscriptions list of registered subscription
*/
public DaprMetadata(String id, String runtimeVersion, List<ComponentMetadata> components,
List<SubscriptionMetadata> subscriptions) {
this.id = id;
this.runtimeVersion = runtimeVersion;
this.components = components == null ? Collections.emptyList() : Collections.unmodifiableList(components);
this.subscriptions = subscriptions == null ? Collections.emptyList() : Collections.unmodifiableList(subscriptions);
}
public String getId() {
return id;
}
public String getRuntimeVersion() {
return runtimeVersion;
}
public List<ComponentMetadata> getComponents() {
return components;
}
public List<SubscriptionMetadata> getSubscriptions() {
return subscriptions;
}
}

View File

@ -0,0 +1,30 @@
/*
* Copyright 2024 The Dapr Authors
* Licensed 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 io.dapr.client.domain;
/**
* RuleMetadata describes the Subscription Rule's Metadata.
*/
public final class RuleMetadata {
private String path;
public RuleMetadata(String path) {
this.path = path;
}
public String getPath() {
return path;
}
}

View File

@ -0,0 +1,62 @@
/*
* Copyright 2024 The Dapr Authors
* Licensed 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 io.dapr.client.domain;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
/**
* SubscriptionMetadata describes the Subscription Metadata.
*/
public final class SubscriptionMetadata {
private String topic;
private String pubsubname;
private String deadLetterTopic;
private List<RuleMetadata> rules;
/**
* Constructor for a SubscriptionMetadata.
*
* @param topic of the pubsub component
* @param pubsubname component name
* @param deadLetterTopic dead letter topic
* @param rules subscription path rules
*/
public SubscriptionMetadata(String topic, String pubsubname, String deadLetterTopic, List<RuleMetadata> rules) {
this.topic = topic;
this.pubsubname = pubsubname;
this.deadLetterTopic = deadLetterTopic;
this.rules = rules == null ? Collections.emptyList() : Collections.unmodifiableList(rules);
}
public String getTopic() {
return topic;
}
public String getPubsubname() {
return pubsubname;
}
public String getDeadLetterTopic() {
return deadLetterTopic;
}
public List<RuleMetadata> getRules() {
return rules;
}
}

View File

@ -17,6 +17,7 @@ import com.google.protobuf.Any;
import com.google.protobuf.ByteString;
import com.google.protobuf.Empty;
import io.dapr.client.domain.ConfigurationItem;
import io.dapr.client.domain.DaprMetadata;
import io.dapr.client.domain.DeleteStateRequest;
import io.dapr.client.domain.ExecuteStateTransactionRequest;
import io.dapr.client.domain.GetBulkStateRequest;
@ -28,12 +29,16 @@ import io.dapr.client.domain.SubscribeConfigurationResponse;
import io.dapr.client.domain.TransactionalStateOperation;
import io.dapr.client.domain.UnsubscribeConfigurationRequest;
import io.dapr.client.domain.UnsubscribeConfigurationResponse;
import io.dapr.exceptions.DaprError;
import io.dapr.exceptions.DaprException;
import io.dapr.serializer.DaprObjectSerializer;
import io.dapr.serializer.DefaultObjectSerializer;
import io.dapr.utils.TypeRef;
import io.dapr.v1.CommonProtos;
import io.dapr.v1.DaprGrpc;
import io.dapr.v1.DaprProtos;
import io.dapr.v1.DaprProtos.PubsubSubscription;
import io.dapr.v1.DaprProtos.RegisteredComponents;
import io.grpc.Status;
import io.grpc.StatusRuntimeException;
import io.grpc.protobuf.StatusProto;
@ -2078,4 +2083,65 @@ public class DaprClientGrpcTest {
return StatusProto.toStatusRuntimeException(status);
}
}
@Test
public void getMetadataTest() {
RegisteredComponents registeredComponents = DaprProtos.RegisteredComponents.newBuilder()
.setName("statestore")
.setType("state.redis")
.setVersion("v1")
.build();
PubsubSubscription pubsubSubscription = DaprProtos.PubsubSubscription.newBuilder()
.setDeadLetterTopic("")
.setPubsubName("pubsub")
.setTopic("topic")
.setRules(DaprProtos.PubsubSubscriptionRules.newBuilder()
.addRules(DaprProtos.PubsubSubscriptionRule.newBuilder().setPath("/events").build()).build())
.build();
DaprProtos.GetMetadataResponse responseEnvelope = DaprProtos.GetMetadataResponse.newBuilder()
.setId("app")
.setRuntimeVersion("1.1x.x")
.addAllRegisteredComponents(Collections.singletonList(registeredComponents))
.addAllSubscriptions(Collections.singletonList(pubsubSubscription))
.build();
doAnswer((Answer<Void>) invocation -> {
StreamObserver<DaprProtos.GetMetadataResponse> observer = (StreamObserver<DaprProtos.GetMetadataResponse>) invocation
.getArguments()[1];
observer.onNext(responseEnvelope);
observer.onCompleted();
return null;
}).when(daprStub).getMetadata(any(DaprProtos.GetMetadataRequest.class), any());
Mono<DaprMetadata> result = client.getMetadata();
DaprMetadata metadata = result.block();
assertNotNull(metadata);
assertEquals("app", metadata.getId());
assertEquals("1.1x.x", metadata.getRuntimeVersion());
assertEquals(1, metadata.getComponents().size());
assertEquals(registeredComponents.getName(), metadata.getComponents().get(0).getName());
assertEquals(registeredComponents.getVersion(), metadata.getComponents().get(0).getVersion());
assertEquals(registeredComponents.getType(), metadata.getComponents().get(0).getType());
assertEquals(1, metadata.getSubscriptions().size());
assertEquals(pubsubSubscription.getPubsubName(), metadata.getSubscriptions().get(0).getPubsubname());
assertEquals(pubsubSubscription.getTopic(), metadata.getSubscriptions().get(0).getTopic());
assertEquals(1, metadata.getSubscriptions().get(0).getRules().size());
assertEquals(pubsubSubscription.getRules().getRules(0).getPath(), metadata.getSubscriptions().get(0).getRules().get(0).getPath());
}
@Test
public void getMetadataExceptionTest() {
doAnswer((Answer<Void>) invocation -> {
throw new RuntimeException();
}).when(daprStub).getMetadata(any(DaprProtos.GetMetadataRequest.class), any());
Mono<DaprMetadata> result = client.getMetadata();
assertThrowsDaprException(
RuntimeException.class,
"UNKNOWN",
"UNKNOWN: ",
() -> result.block());
}
}