use of io.opentracing.Tracer in project hono by eclipse.
the class CommandTargetMapperImpl method getTargetGatewayAndAdapterInstance.
@Override
public final Future<JsonObject> getTargetGatewayAndAdapterInstance(final String tenantId, final String deviceId, final SpanContext context) {
Objects.requireNonNull(tenantId);
Objects.requireNonNull(deviceId);
final Span span = TracingHelper.buildChildSpan(tracer, context, "get target gateway and adapter instance", CommandTargetMapper.class.getSimpleName()).withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_CONSUMER).withTag(TracingHelper.TAG_TENANT_ID, tenantId).withTag(TracingHelper.TAG_DEVICE_ID, deviceId).start();
return registrationClient.assertRegistration(tenantId, deviceId, null, span.context()).map(RegistrationAssertion::getAuthorizedGateways).recover(t -> {
LOG.debug("Error retrieving gateways authorized to act on behalf of device [tenant-id: {}, device-id: {}]", tenantId, deviceId, t);
return Future.failedFuture(ServiceInvocationException.extractStatusCode(t) == HttpURLConnection.HTTP_NOT_FOUND ? new DeviceDisabledOrNotRegisteredException(tenantId, HttpURLConnection.HTTP_NOT_FOUND) : t);
}).compose(viaGateways -> {
return deviceConnectionInfo.getCommandHandlingAdapterInstances(tenantId, deviceId, new HashSet<>(viaGateways), span).compose(resultJson -> determineTargetInstanceJson(resultJson, deviceId, viaGateways, span));
}).onFailure(t -> {
LOG.debug("Error getting target gateway and adapter instance", t);
TracingHelper.logError(span, t);
Tags.HTTP_STATUS.set(span, ServiceInvocationException.extractStatusCode(t));
}).onComplete(ar -> span.finish());
}
use of io.opentracing.Tracer in project hono by eclipse.
the class EdgeDeviceAutoProvisioner method performAutoProvisioning.
/**
* Auto-provisions the edge device using the given device id and the given registration data.
*
* @param tenantId The id of the tenant for which the edge device should be provisioned.
* @param tenant The tenant information.
* @param deviceId The id of the edge device which should be provisioned, may be {@code null}.
* @param gatewayId The id of the edge device's gateway.
* @param device The registration data for the device to be auto-provisioned.
* @param spanContext The tracing context to be used by this operation.
*
* @return A future indicating the outcome of the operation.
*
* @throws NullPointerException if any argument except deviceId is {@code null}.
*/
public Future<Device> performAutoProvisioning(final String tenantId, final Tenant tenant, final String deviceId, final String gatewayId, final Device device, final SpanContext spanContext) {
Objects.requireNonNull(tenantId);
Objects.requireNonNull(tenant);
Objects.requireNonNull(gatewayId);
Objects.requireNonNull(device);
Objects.requireNonNull(spanContext);
final Span span = TracingHelper.buildChildSpan(tracer, spanContext, "auto-provision edge device connected via gateway", Constants.PROTOCOL_ADAPTER_TYPE_DEVICE_REGISTRY).withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_CLIENT).withTag(TracingHelper.TAG_GATEWAY_ID, gatewayId).start();
TracingHelper.setDeviceTags(span, tenantId, deviceId);
return deviceManagementService.createDevice(tenantId, Optional.of(deviceId), device, span).recover(thr -> ServiceInvocationException.extractStatusCode(thr) == HttpURLConnection.HTTP_CONFLICT ? Future.succeededFuture(OperationResult.empty(HttpURLConnection.HTTP_CONFLICT)) : Future.failedFuture(thr)).compose(addEdgeDeviceResult -> {
if (addEdgeDeviceResult.isError()) {
if (addEdgeDeviceResult.getStatus() != HttpURLConnection.HTTP_CONFLICT) {
return Future.failedFuture(StatusCodeMapper.from(addEdgeDeviceResult.getStatus(), String.format("failed to add edge device (status %d)", addEdgeDeviceResult.getStatus())));
}
// handle HTTP_CONFLICT, meaning the device already exists
span.log("device already exists");
LOG.debug("device [{}] for gateway [{}] already created by concurrent auto-provisioning [tenant-id: {}]", deviceId, gatewayId, tenantId);
return deviceManagementService.readDevice(tenantId, deviceId, span).compose(readDeviceResult -> {
if (!readDeviceResult.isOk()) {
span.log("reading device after conflict failed");
LOG.warn("reading device after conflict failed for device [{}] of gateway [{}] of tenant [{}]: status: {}", deviceId, gatewayId, tenantId, readDeviceResult.getStatus());
return Future.failedFuture(StatusCodeMapper.from(readDeviceResult.getStatus(), String.format("reading device after conflict failed (status %d)", readDeviceResult.getStatus())));
}
if (!readDeviceResult.getPayload().getVia().contains(gatewayId)) {
span.log("attempted to auto-provision same device via two different gateways at the same time");
LOG.info("attempted to auto-provision device [{}] via gateway [{}] of tenant [{}] but the registration data's via contains only {}", deviceId, gatewayId, tenantId, readDeviceResult.getPayload().getVia());
return Future.failedFuture(StatusCodeMapper.from(HttpURLConnection.HTTP_FORBIDDEN, "device already auto-provisioned for another gateway"));
}
final Device readDevice = readDeviceResult.getPayload();
// ensure that a notification event gets sent (even if we might send duplicate events)
return sendDelayedAutoProvisioningNotificationIfNeeded(tenantId, tenant, deviceId, gatewayId, readDevice, span).map(readDevice);
});
}
span.log("device created");
LOG.trace("device [{}] for gateway [{}] successfully created by auto-provisioning [tenant-id: {}]", deviceId, gatewayId, tenantId);
return sendAutoProvisioningEvent(tenantId, tenant, deviceId, gatewayId, span).compose(sendEmptyEventOk -> deviceManagementService.readDevice(tenantId, deviceId, span).compose(readDeviceResult -> {
if (!readDeviceResult.isOk()) {
LOG.warn("notification flag of device [{}] for gateway [{}] of tenant [tenant-id: {}] could not be updated", deviceId, gatewayId, tenantId);
return Future.failedFuture(StatusCodeMapper.from(readDeviceResult.getStatus(), String.format("update of notification flag failed (status %d)", readDeviceResult.getStatus())));
}
final Device deviceData = readDeviceResult.getPayload();
return updateAutoProvisioningNotificationSent(tenantId, deviceId, deviceData, readDeviceResult.getResourceVersion(), span).recover(error -> Future.succeededFuture()).map(deviceData);
}));
}).onFailure(thr -> TracingHelper.logError(span, thr)).onComplete(ar -> span.finish());
}
use of io.opentracing.Tracer in project hono by eclipse.
the class ProtonBasedMappingAndDelegatingCommandHandlerTest method mockHonoConnection.
private static <T> HonoConnection mockHonoConnection(final Vertx vertx, final ClientConfigProperties props) {
final Tracer tracer = NoopTracerFactory.create();
final HonoConnection connection = mock(HonoConnection.class);
when(connection.getVertx()).thenReturn(vertx);
when(connection.getConfig()).thenReturn(props);
when(connection.getTracer()).thenReturn(tracer);
when(connection.executeOnContext(VertxMockSupport.anyHandler())).then(invocation -> {
final Promise<T> result = Promise.promise();
final Handler<Future<T>> handler = invocation.getArgument(0);
handler.handle(result.future());
return result.future();
});
return connection;
}
use of io.opentracing.Tracer in project hono by eclipse.
the class CacheBasedDeviceConnectionInfoTest method testGetCommandHandlingAdapterInstancesWithTerminatedAdapterInstanceContainer.
/**
* Verifies that the <em>getCommandHandlingAdapterInstances</em> operation succeeds with a result containing
* the mapping of a gateway device if the also existing mapping belonging to the *the given device* is associated
* with an adapter instance identified as already terminated.
*
* @param extraUnusedViaGateways Test values.
* @param ctx The vert.x context.
*/
@ParameterizedTest(name = PARAMETERIZED_TEST_NAME_PATTERN)
@MethodSource("extraUnusedViaGateways")
public void testGetCommandHandlingAdapterInstancesWithTerminatedAdapterInstanceContainer(final Set<String> extraUnusedViaGateways, final VertxTestContext ctx) {
final AdapterInstanceStatusProvider statusProvider = mock(AdapterInstanceStatusProvider.class);
info = new CacheBasedDeviceConnectionInfo(cache, tracer, statusProvider);
final String deviceId = "testDevice";
final String adapterInstance = "adapterInstance";
final String otherAdapterInstance = "otherAdapterInstance";
final String gatewayId = "gw-1";
final Set<String> viaGateways = new HashSet<>(Set.of(gatewayId));
viaGateways.addAll(extraUnusedViaGateways);
// GIVEN testDevice has no last known gateway registered
when(cache.get(CacheBasedDeviceConnectionInfo.getGatewayEntryKey(Constants.DEFAULT_TENANT, deviceId))).thenReturn(Future.succeededFuture());
// and testDevice's and gw-1's command handling adapter instances are set to
// adapterInstance and otherAdapterInstance respectively
when(cache.getAll(CacheBasedDeviceConnectionInfo.getAdapterInstanceEntryKeys(Constants.DEFAULT_TENANT, deviceId, viaGateways))).thenReturn(Future.succeededFuture(Map.of(CacheBasedDeviceConnectionInfo.getAdapterInstanceEntryKey(Constants.DEFAULT_TENANT, deviceId), adapterInstance, CacheBasedDeviceConnectionInfo.getAdapterInstanceEntryKey(Constants.DEFAULT_TENANT, gatewayId), otherAdapterInstance)));
when(cache.remove(anyString(), anyString())).thenReturn(Future.succeededFuture(Boolean.TRUE));
when(statusProvider.getStatus(adapterInstance)).thenReturn(AdapterInstanceStatus.DEAD);
when(statusProvider.getStatus(otherAdapterInstance)).thenReturn(AdapterInstanceStatus.ALIVE);
info.getCommandHandlingAdapterInstances(Constants.DEFAULT_TENANT, deviceId, viaGateways, span).onComplete(ctx.succeeding(result -> {
ctx.verify(() -> {
assertNotNull(result);
assertGetInstancesResultMapping(result, gatewayId, otherAdapterInstance);
assertGetInstancesResultSize(result, 1);
// verify mapping entry for terminated adapter instance has been removed
verify(cache).remove(CacheBasedDeviceConnectionInfo.getAdapterInstanceEntryKey(Constants.DEFAULT_TENANT, deviceId), adapterInstance);
});
ctx.completeNow();
}));
}
use of io.opentracing.Tracer in project hono by eclipse.
the class CacheBasedDeviceConnectionInfoTest method testGetCommandHandlingAdapterInstancesWithSuspectedAdapterInstance.
/**
* Verifies that the <em>getCommandHandlingAdapterInstances</em> operation fails
* if the adapter instance mapping entry is associated with a adapter having the state 'SUSPECTED_DEAD'.
*
* @param ctx The vert.x context.
*/
@Test
public void testGetCommandHandlingAdapterInstancesWithSuspectedAdapterInstance(final VertxTestContext ctx) {
final AdapterInstanceStatusProvider statusProvider = mock(AdapterInstanceStatusProvider.class);
info = new CacheBasedDeviceConnectionInfo(cache, tracer, statusProvider);
final String deviceId = "testDevice";
final String adapterInstance = "adapterInstance";
when(cache.get(anyString())).thenReturn(Future.succeededFuture(adapterInstance));
when(statusProvider.getStatus(adapterInstance)).thenReturn(AdapterInstanceStatus.SUSPECTED_DEAD);
when(cache.remove(anyString(), anyString())).thenReturn(Future.succeededFuture(Boolean.TRUE));
info.getCommandHandlingAdapterInstances(Constants.DEFAULT_TENANT, deviceId, Set.of(), span).onComplete(ctx.failing(t -> {
ctx.verify(() -> {
verify(cache).get(CacheBasedDeviceConnectionInfo.getAdapterInstanceEntryKey(Constants.DEFAULT_TENANT, deviceId));
assertThat(t).isInstanceOf(ClientErrorException.class);
assertThat(((ClientErrorException) t).getErrorCode()).isEqualTo(HttpURLConnection.HTTP_NOT_FOUND);
// verify mapping entry for terminated adapter instance has not been removed
verify(cache, never()).remove(CacheBasedDeviceConnectionInfo.getAdapterInstanceEntryKey(Constants.DEFAULT_TENANT, deviceId), adapterInstance);
});
ctx.completeNow();
}));
}
Aggregations