Search in sources :

Example 46 with SpanContext

use of io.opentracing.SpanContext in project hono by eclipse.

the class CommandRouterServiceImpl method activateCommandRouting.

private void activateCommandRouting(final Pair<String, Integer> attempt, final SpanContext tracingContext) {
    if (!running.get()) {
        // component has been stopped, no need to create command consumer in this case
        tenantsInProcess.remove(attempt.one());
        return;
    }
    final Span span = tracer.buildSpan("re-enable command routing for tenant").addReference(References.FOLLOWS_FROM, tracingContext).withTag(TracingHelper.TAG_TENANT_ID, attempt.one()).start();
    final var logEntries = new HashMap<String, Object>(2);
    logEntries.put("attempt#", attempt.two());
    tenantClient.get(attempt.one(), span.context()).map(tenantObject -> commandConsumerFactoryProvider.getClient(tenantObject)).map(factory -> factory.createCommandConsumer(attempt.one(), span.context())).onSuccess(ok -> {
        logEntries.put(Fields.MESSAGE, "successfully created command consumer");
        span.log(logEntries);
        reenabledTenants.add(attempt.one());
    }).onFailure(t -> {
        logEntries.put(Fields.MESSAGE, "failed to create command consumer");
        logEntries.put(Fields.ERROR_OBJECT, t);
        TracingHelper.logError(span, logEntries);
        if (t instanceof ServerErrorException) {
            // add to end of queue in order to retry at a later time
            LOG.info("failed to create command consumer [attempt#: {}]", attempt.two(), t);
            span.log("marking tenant for later re-try to create command consumer");
            tenantsToEnable.addLast(Pair.of(attempt.one(), attempt.two() + 1));
        }
    }).onComplete(r -> {
        span.finish();
        tenantsInProcess.remove(attempt.one());
        processTenantQueue(tracingContext);
    });
}
Also used : HttpURLConnection(java.net.HttpURLConnection) CommandRouterService(org.eclipse.hono.service.commandrouter.CommandRouterService) Lifecycle(org.eclipse.hono.util.Lifecycle) LoggerFactory(org.slf4j.LoggerFactory) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) HashMap(java.util.HashMap) Deque(java.util.Deque) ServiceInvocationException(org.eclipse.hono.client.ServiceInvocationException) ServiceConfigProperties(org.eclipse.hono.config.ServiceConfigProperties) Context(io.vertx.core.Context) ArrayList(java.util.ArrayList) HashSet(java.util.HashSet) CompositeFuture(io.vertx.core.CompositeFuture) Status(io.vertx.ext.healthchecks.Status) MessagingType(org.eclipse.hono.util.MessagingType) HealthCheckHandler(io.vertx.ext.healthchecks.HealthCheckHandler) DeviceRegistrationClient(org.eclipse.hono.client.registry.DeviceRegistrationClient) HealthCheckProvider(org.eclipse.hono.service.HealthCheckProvider) References(io.opentracing.References) Duration(java.time.Duration) Map(java.util.Map) Pair(org.eclipse.hono.util.Pair) Fields(io.opentracing.log.Fields) TracingHelper(org.eclipse.hono.tracing.TracingHelper) LinkedList(java.util.LinkedList) CommandRouterResult(org.eclipse.hono.service.commandrouter.CommandRouterResult) Logger(org.slf4j.Logger) Tracer(io.opentracing.Tracer) MessagingClientProvider(org.eclipse.hono.client.util.MessagingClientProvider) Vertx(io.vertx.core.Vertx) Set(java.util.Set) ServerErrorException(org.eclipse.hono.client.ServerErrorException) TenantClient(org.eclipse.hono.client.registry.TenantClient) Future(io.vertx.core.Future) DeviceConnectionInfo(org.eclipse.hono.deviceconnection.infinispan.client.DeviceConnectionInfo) SpanContext(io.opentracing.SpanContext) Objects(java.util.Objects) List(java.util.List) ServiceClient(org.eclipse.hono.client.util.ServiceClient) CommandConsumerFactory(org.eclipse.hono.commandrouter.CommandConsumerFactory) Span(io.opentracing.Span) AdapterInstanceStatusService(org.eclipse.hono.commandrouter.AdapterInstanceStatusService) HashMap(java.util.HashMap) ServerErrorException(org.eclipse.hono.client.ServerErrorException) Span(io.opentracing.Span)

Example 47 with SpanContext

use of io.opentracing.SpanContext in project hono by eclipse.

the class ProtonBasedMappingAndDelegatingCommandHandler method mapAndDelegateIncomingCommandMessage.

/**
 * Delegates an incoming command to the protocol adapter instance that the target
 * device is connected to.
 * <p>
 * Determines the target gateway (if applicable) and protocol adapter instance for an incoming command
 * and delegates the command to the resulting protocol adapter instance.
 *
 * @param tenantId The tenant that the command target must belong to.
 * @param messageDelivery The delivery of the command message.
 * @param message The command message.
 * @throws NullPointerException if any of the parameters is {@code null}.
 */
public void mapAndDelegateIncomingCommandMessage(final String tenantId, final ProtonDelivery messageDelivery, final Message message) {
    Objects.requireNonNull(tenantId);
    Objects.requireNonNull(messageDelivery);
    Objects.requireNonNull(message);
    final Timer.Sample timer = getMetrics().startTimer();
    // this is the place where a command message on the "command/${tenant}" address arrives *first*
    if (!ResourceIdentifier.isValid(message.getAddress())) {
        log.debug("command message has no valid address");
        final Rejected rejected = new Rejected();
        rejected.setError(new ErrorCondition(Constants.AMQP_BAD_REQUEST, "missing or invalid command target address"));
        messageDelivery.disposition(rejected, true);
        return;
    }
    final ResourceIdentifier targetAddress = ResourceIdentifier.fromString(message.getAddress());
    final String deviceId = targetAddress.getResourceId();
    if (!tenantId.equals(targetAddress.getTenantId())) {
        log.debug("command message address contains invalid tenant [expected: {}, found: {}]", tenantId, targetAddress.getTenantId());
        final Rejected rejected = new Rejected();
        rejected.setError(new ErrorCondition(AmqpError.UNAUTHORIZED_ACCESS, "unauthorized to send command to tenant"));
        messageDelivery.disposition(rejected, true);
        return;
    } else if (Strings.isNullOrEmpty(deviceId)) {
        log.debug("invalid command message address: {}", message.getAddress());
        final Rejected rejected = new Rejected();
        rejected.setError(new ErrorCondition(Constants.AMQP_BAD_REQUEST, "invalid command target address"));
        messageDelivery.disposition(rejected, true);
        return;
    }
    final ProtonBasedCommand command = ProtonBasedCommand.from(message);
    if (command.isValid()) {
        log.trace("received valid command message: {}", command);
    } else {
        log.debug("received invalid command message: {}", command);
    }
    final SpanContext spanContext = TracingHelper.extractSpanContext(tracer, message);
    final Span currentSpan = createSpan(tenantId, deviceId, spanContext);
    command.logToSpan(currentSpan);
    final ProtonBasedCommandContext commandContext = new ProtonBasedCommandContext(command, messageDelivery, currentSpan);
    if (command.isValid()) {
        mapAndDelegateIncomingCommand(commandContext, timer);
    } else {
        // command message is invalid
        commandContext.reject("malformed command message");
        reportInvalidCommand(commandContext, timer);
    }
}
Also used : ResourceIdentifier(org.eclipse.hono.util.ResourceIdentifier) SpanContext(io.opentracing.SpanContext) Timer(io.micrometer.core.instrument.Timer) ProtonBasedCommandContext(org.eclipse.hono.client.command.amqp.ProtonBasedCommandContext) ErrorCondition(org.apache.qpid.proton.amqp.transport.ErrorCondition) ProtonBasedCommand(org.eclipse.hono.client.command.amqp.ProtonBasedCommand) Rejected(org.apache.qpid.proton.amqp.messaging.Rejected) Span(io.opentracing.Span)

Example 48 with SpanContext

use of io.opentracing.SpanContext 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());
}
Also used : HttpURLConnection(java.net.HttpURLConnection) Logger(org.slf4j.Logger) Tracer(io.opentracing.Tracer) DeviceConnectionConstants(org.eclipse.hono.util.DeviceConnectionConstants) LoggerFactory(org.slf4j.LoggerFactory) ServerErrorException(org.eclipse.hono.client.ServerErrorException) CommandTargetMapper(org.eclipse.hono.commandrouter.CommandTargetMapper) RegistrationAssertion(org.eclipse.hono.util.RegistrationAssertion) ServiceInvocationException(org.eclipse.hono.client.ServiceInvocationException) MessageHelper(org.eclipse.hono.util.MessageHelper) Tags(io.opentracing.tag.Tags) Future(io.vertx.core.Future) DeviceConnectionInfo(org.eclipse.hono.deviceconnection.infinispan.client.DeviceConnectionInfo) SpanContext(io.opentracing.SpanContext) HashSet(java.util.HashSet) Objects(java.util.Objects) DeviceDisabledOrNotRegisteredException(org.eclipse.hono.client.registry.DeviceDisabledOrNotRegisteredException) JsonArray(io.vertx.core.json.JsonArray) List(java.util.List) DeviceRegistrationClient(org.eclipse.hono.client.registry.DeviceRegistrationClient) Span(io.opentracing.Span) JsonObject(io.vertx.core.json.JsonObject) TracingHelper(org.eclipse.hono.tracing.TracingHelper) CommandTargetMapper(org.eclipse.hono.commandrouter.CommandTargetMapper) DeviceDisabledOrNotRegisteredException(org.eclipse.hono.client.registry.DeviceDisabledOrNotRegisteredException) RegistrationAssertion(org.eclipse.hono.util.RegistrationAssertion) Span(io.opentracing.Span) HashSet(java.util.HashSet)

Example 49 with SpanContext

use of io.opentracing.SpanContext 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());
}
Also used : HttpURLConnection(java.net.HttpURLConnection) Device(org.eclipse.hono.service.management.device.Device) Tracer(io.opentracing.Tracer) EventSender(org.eclipse.hono.client.telemetry.EventSender) MessagingClientProvider(org.eclipse.hono.client.util.MessagingClientProvider) Promise(io.vertx.core.Promise) Vertx(io.vertx.core.Vertx) ServiceInvocationException(org.eclipse.hono.client.ServiceInvocationException) Constants(org.eclipse.hono.util.Constants) Tags(io.opentracing.tag.Tags) Future(io.vertx.core.Future) Tenant(org.eclipse.hono.service.management.tenant.Tenant) SpanContext(io.opentracing.SpanContext) Objects(java.util.Objects) DeviceManagementService(org.eclipse.hono.service.management.device.DeviceManagementService) StatusCodeMapper(org.eclipse.hono.client.StatusCodeMapper) Optional(java.util.Optional) OperationResult(org.eclipse.hono.service.management.OperationResult) Span(io.opentracing.Span) TracingHelper(org.eclipse.hono.tracing.TracingHelper) Device(org.eclipse.hono.service.management.device.Device) Span(io.opentracing.Span)

Example 50 with SpanContext

use of io.opentracing.SpanContext in project hono by eclipse.

the class AbstractTenantStore method readTenant.

/**
 * Read the content of a tenant.
 * <p>
 * This will execute the {@code read} statement and return the unprocessed information.
 * <p>
 * If there are no entries, an empty result will be returned.
 * <p>
 * If more than one entry is being found, the result will be failed with an
 * {@link IllegalStateException} exception.
 *
 * @param id The key to the tenant entry.
 * @param spanContext The span to contribute to.
 * @return The future, tracking the outcome of the operation.
 */
public Future<Optional<TenantReadResult>> readTenant(final String id, final SpanContext spanContext) {
    final Span span = TracingHelper.buildChildSpan(this.tracer, spanContext, "read tenant", getClass().getSimpleName()).withTag(TracingHelper.TAG_TENANT_ID, id).start();
    final var expanded = this.readStatement.expand(map -> {
        map.put("tenant_id", id);
    });
    return SQL.runTransactionally(this.client, this.tracer, span.context(), (connection, context) -> readTenantBy(connection, expanded, context)).onComplete(x -> span.finish());
}
Also used : SQL(org.eclipse.hono.service.base.jdbc.store.SQL) Json(io.vertx.core.json.Json) Logger(org.slf4j.Logger) Tracer(io.opentracing.Tracer) LoggerFactory(org.slf4j.LoggerFactory) AbstractStore(org.eclipse.hono.service.base.jdbc.store.AbstractStore) Collectors(java.util.stream.Collectors) Future(io.vertx.core.Future) Tenant(org.eclipse.hono.service.management.tenant.Tenant) Statement(org.eclipse.hono.service.base.jdbc.store.Statement) ExpandedStatement(org.eclipse.hono.service.base.jdbc.store.Statement.ExpandedStatement) SpanContext(io.opentracing.SpanContext) List(java.util.List) JDBCClient(io.vertx.ext.jdbc.JDBCClient) TrustedCertificateAuthority(org.eclipse.hono.service.management.tenant.TrustedCertificateAuthority) Map(java.util.Map) ResultSet(io.vertx.ext.sql.ResultSet) Optional(java.util.Optional) Span(io.opentracing.Span) JsonObject(io.vertx.core.json.JsonObject) TracingHelper(org.eclipse.hono.tracing.TracingHelper) SQLOperations(io.vertx.ext.sql.SQLOperations) StatementConfiguration(org.eclipse.hono.service.base.jdbc.store.StatementConfiguration) Span(io.opentracing.Span)

Aggregations

SpanContext (io.opentracing.SpanContext)118 Span (io.opentracing.Span)81 Future (io.vertx.core.Future)70 Tracer (io.opentracing.Tracer)60 Objects (java.util.Objects)57 HttpURLConnection (java.net.HttpURLConnection)56 JsonObject (io.vertx.core.json.JsonObject)55 TracingHelper (org.eclipse.hono.tracing.TracingHelper)55 Logger (org.slf4j.Logger)54 LoggerFactory (org.slf4j.LoggerFactory)54 List (java.util.List)51 Promise (io.vertx.core.Promise)45 Optional (java.util.Optional)45 Map (java.util.Map)40 ClientErrorException (org.eclipse.hono.client.ClientErrorException)39 MessageHelper (org.eclipse.hono.util.MessageHelper)33 UUID (java.util.UUID)31 Collectors (java.util.stream.Collectors)31 HashMap (java.util.HashMap)25 Vertx (io.vertx.core.Vertx)24