Search in sources :

Example 1 with TenantDisabledOrNotRegisteredException

use of org.eclipse.hono.client.registry.TenantDisabledOrNotRegisteredException in project hono by eclipse.

the class LoraProtocolAdapter method handleTenantTimeout.

private void handleTenantTimeout(final Message<String> msg) {
    final String tenantId = msg.body();
    log.debug("check command subscriptions on timeout of tenant [{}]", tenantId);
    final Span span = TracingHelper.buildSpan(tracer, null, "check command subscriptions on tenant timeout", getClass().getSimpleName()).withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_CLIENT).start();
    TracingHelper.setDeviceTags(span, tenantId, null);
    // check if tenant still exists
    getTenantConfiguration(tenantId, span.context()).recover(thr -> {
        if (thr instanceof TenantDisabledOrNotRegisteredException) {
            log.debug("tenant [{}] disabled or removed, removing corresponding command consumers", tenantId);
            span.log("tenant disabled or removed, corresponding command consumers will be closed");
            @SuppressWarnings("rawtypes") final List<Future> consumerCloseFutures = new LinkedList<>();
            for (final var iter = commandSubscriptions.entrySet().iterator(); iter.hasNext(); ) {
                final var entry = iter.next();
                if (entry.getKey().getTenant().equals(tenantId)) {
                    final CommandConsumer commandConsumer = entry.getValue().one();
                    consumerCloseFutures.add(commandConsumer.close(span.context()));
                    iter.remove();
                }
            }
            return CompositeFuture.join(consumerCloseFutures).mapEmpty();
        } else {
            return Future.failedFuture(thr);
        }
    }).onFailure(thr -> TracingHelper.logError(span, thr)).onComplete(ar -> span.finish());
}
Also used : HttpURLConnection(java.net.HttpURLConnection) LoraProviderMalformedPayloadException(org.eclipse.hono.adapter.lora.providers.LoraProviderMalformedPayloadException) LoggerFactory(org.slf4j.LoggerFactory) Router(io.vertx.ext.web.Router) Tag(io.opentracing.tag.Tag) RoutingContext(io.vertx.ext.web.RoutingContext) Tags(io.opentracing.tag.Tags) Map(java.util.Map) Pair(org.eclipse.hono.util.Pair) Fields(io.opentracing.log.Fields) JsonObject(io.vertx.core.json.JsonObject) TracingHelper(org.eclipse.hono.tracing.TracingHelper) TenantServiceBasedX509Authentication(org.eclipse.hono.adapter.auth.device.TenantServiceBasedX509Authentication) ChainAuthHandler(io.vertx.ext.web.handler.ChainAuthHandler) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) CommandContext(org.eclipse.hono.client.command.CommandContext) MetricsTags(org.eclipse.hono.service.metric.MetricsTags) Message(io.vertx.core.eventbus.Message) EventConstants(org.eclipse.hono.util.EventConstants) StringTag(io.opentracing.tag.StringTag) Future(io.vertx.core.Future) HonoBasicAuthHandler(org.eclipse.hono.adapter.http.HonoBasicAuthHandler) Device(org.eclipse.hono.auth.Device) Objects(java.util.Objects) List(java.util.List) Buffer(io.vertx.core.buffer.Buffer) X509AuthHandler(org.eclipse.hono.adapter.http.X509AuthHandler) CommandConsumer(org.eclipse.hono.client.command.CommandConsumer) Optional(java.util.Optional) Span(io.opentracing.Span) UsernamePasswordCredentials(org.eclipse.hono.adapter.auth.device.UsernamePasswordCredentials) CommandEndpoint(org.eclipse.hono.util.CommandEndpoint) HttpContext(org.eclipse.hono.service.http.HttpContext) Json(io.vertx.core.json.Json) LoraProvider(org.eclipse.hono.adapter.lora.providers.LoraProvider) WebClient(io.vertx.ext.web.client.WebClient) Command(org.eclipse.hono.client.command.Command) ClientErrorException(org.eclipse.hono.client.ClientErrorException) TenantDisabledOrNotRegisteredException(org.eclipse.hono.client.registry.TenantDisabledOrNotRegisteredException) Constants(org.eclipse.hono.util.Constants) ArrayList(java.util.ArrayList) TracingHandler(org.eclipse.hono.service.http.TracingHandler) CompositeFuture(io.vertx.core.CompositeFuture) StatusCodeMapper(org.eclipse.hono.client.StatusCodeMapper) HttpUtils(org.eclipse.hono.service.http.HttpUtils) LinkedList(java.util.LinkedList) UsernamePasswordAuthProvider(org.eclipse.hono.adapter.auth.device.UsernamePasswordAuthProvider) Logger(org.slf4j.Logger) Direction(org.eclipse.hono.service.metric.MetricsTags.Direction) AbstractVertxBasedHttpProtocolAdapter(org.eclipse.hono.adapter.http.AbstractVertxBasedHttpProtocolAdapter) Promise(io.vertx.core.Promise) ServerErrorException(org.eclipse.hono.client.ServerErrorException) Sample(io.micrometer.core.instrument.Timer.Sample) TenantObject(org.eclipse.hono.util.TenantObject) SpanContext(io.opentracing.SpanContext) HttpRequest(io.vertx.ext.web.client.HttpRequest) DeviceCredentialsAuthProvider(org.eclipse.hono.adapter.auth.device.DeviceCredentialsAuthProvider) X509AuthProvider(org.eclipse.hono.adapter.auth.device.X509AuthProvider) HttpMethod(io.vertx.core.http.HttpMethod) HttpProtocolAdapterProperties(org.eclipse.hono.adapter.http.HttpProtocolAdapterProperties) SubjectDnCredentials(org.eclipse.hono.adapter.auth.device.SubjectDnCredentials) CommandConsumer(org.eclipse.hono.client.command.CommandConsumer) Future(io.vertx.core.Future) CompositeFuture(io.vertx.core.CompositeFuture) TenantDisabledOrNotRegisteredException(org.eclipse.hono.client.registry.TenantDisabledOrNotRegisteredException) Span(io.opentracing.Span) LinkedList(java.util.LinkedList)

Example 2 with TenantDisabledOrNotRegisteredException

use of org.eclipse.hono.client.registry.TenantDisabledOrNotRegisteredException in project hono by eclipse.

the class AbstractMappingAndDelegatingCommandHandler method mapAndDelegateIncomingCommand.

/**
 * 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 commandContext The context of the command to send.
 * @param timer The timer indicating the amount of time used for processing the command message.
 * @return A future indicating the outcome of the operation.
 * @throws NullPointerException if any of the parameters are {@code null}.
 */
protected final Future<Void> mapAndDelegateIncomingCommand(final CommandContext commandContext, final Timer.Sample timer) {
    Objects.requireNonNull(commandContext);
    Objects.requireNonNull(timer);
    final Command command = commandContext.getCommand();
    // determine last used gateway device id
    if (log.isTraceEnabled()) {
        log.trace("determine command target gateway/adapter for [{}]", command);
    }
    final Future<TenantObject> tenantObjectFuture = tenantClient.get(command.getTenant(), commandContext.getTracingContext());
    return tenantObjectFuture.compose(tenantObject -> {
        TenantTraceSamplingHelper.applyTraceSamplingPriority(tenantObject, null, commandContext.getTracingSpan());
        commandContext.put(CommandContext.KEY_TENANT_CONFIG, tenantObject);
        // check whether the handler messaging type is equal to the messaging type of the tenant (if set)
        final MessagingType tenantMessagingType = Optional.ofNullable(tenantObject.getProperty(TenantConstants.FIELD_EXT, JsonObject.class)).map(ext -> ext.getString(TenantConstants.FIELD_EXT_MESSAGING_TYPE)).map(MessagingType::valueOf).orElse(null);
        if (tenantMessagingType != null && getMessagingType() != tenantMessagingType) {
            log.info("command received via {} but tenant is configured to use {} [{}]", getMessagingType(), tenantMessagingType, commandContext.getCommand());
            commandContext.getTracingSpan().log(String.format("command received via %s but tenant is configured to use %s", getMessagingType(), tenantMessagingType));
        }
        return commandTargetMapper.getTargetGatewayAndAdapterInstance(command.getTenant(), command.getDeviceId(), commandContext.getTracingContext());
    }).recover(cause -> {
        final Throwable error;
        if (tenantObjectFuture.failed() && ServiceInvocationException.extractStatusCode(cause) == HttpURLConnection.HTTP_NOT_FOUND) {
            error = new TenantDisabledOrNotRegisteredException(command.getTenant(), HttpURLConnection.HTTP_NOT_FOUND);
        } else if (cause instanceof DeviceDisabledOrNotRegisteredException) {
            error = cause;
        } else if (ServiceInvocationException.extractStatusCode(cause) == HttpURLConnection.HTTP_NOT_FOUND) {
            log.debug("no target adapter instance found for command with device id " + command.getDeviceId(), cause);
            error = new NoConsumerException("no target adapter instance found");
        } else {
            log.debug("error getting target gateway and adapter instance for command with device id " + command.getDeviceId(), cause);
            error = new ServerErrorException(HttpURLConnection.HTTP_UNAVAILABLE, "error getting target gateway and adapter instance", cause);
        }
        if (error instanceof ClientErrorException) {
            commandContext.reject(error);
        } else {
            commandContext.release(error);
        }
        reportCommandProcessingError(command, tenantObjectFuture.result(), error, timer);
        return Future.failedFuture(cause);
    }).compose(result -> {
        final String targetAdapterInstanceId = result.getString(DeviceConnectionConstants.FIELD_ADAPTER_INSTANCE_ID);
        final String targetDeviceId = result.getString(DeviceConnectionConstants.FIELD_PAYLOAD_DEVICE_ID);
        final String targetGatewayId = targetDeviceId.equals(command.getDeviceId()) ? null : targetDeviceId;
        if (Objects.isNull(targetGatewayId)) {
            log.trace("determined target adapter instance [{}] for [{}] (command not mapped to gateway)", targetAdapterInstanceId, command);
        } else {
            command.setGatewayId(targetGatewayId);
            log.trace("determined target gateway [{}] and adapter instance [{}] for [{}]", targetGatewayId, targetAdapterInstanceId, command);
            commandContext.getTracingSpan().log("determined target gateway [" + targetGatewayId + "]");
        }
        return sendCommand(commandContext, targetAdapterInstanceId, tenantObjectFuture.result(), timer);
    });
}
Also used : HttpURLConnection(java.net.HttpURLConnection) InternalCommandSender(org.eclipse.hono.client.command.InternalCommandSender) Command(org.eclipse.hono.client.command.Command) TenantConstants(org.eclipse.hono.util.TenantConstants) Lifecycle(org.eclipse.hono.util.Lifecycle) LoggerFactory(org.slf4j.LoggerFactory) ClientErrorException(org.eclipse.hono.client.ClientErrorException) TenantDisabledOrNotRegisteredException(org.eclipse.hono.client.registry.TenantDisabledOrNotRegisteredException) ServiceInvocationException(org.eclipse.hono.client.ServiceInvocationException) Tags(io.opentracing.tag.Tags) NoConsumerException(org.eclipse.hono.client.NoConsumerException) DeviceDisabledOrNotRegisteredException(org.eclipse.hono.client.registry.DeviceDisabledOrNotRegisteredException) MessagingType(org.eclipse.hono.util.MessagingType) Timer(io.micrometer.core.instrument.Timer) JsonObject(io.vertx.core.json.JsonObject) TracingHelper(org.eclipse.hono.tracing.TracingHelper) Logger(org.slf4j.Logger) Tracer(io.opentracing.Tracer) DeviceConnectionConstants(org.eclipse.hono.util.DeviceConnectionConstants) CommandContext(org.eclipse.hono.client.command.CommandContext) MetricsTags(org.eclipse.hono.service.metric.MetricsTags) ServerErrorException(org.eclipse.hono.client.ServerErrorException) CommandTargetMapper(org.eclipse.hono.commandrouter.CommandTargetMapper) TenantClient(org.eclipse.hono.client.registry.TenantClient) Future(io.vertx.core.Future) TenantObject(org.eclipse.hono.util.TenantObject) SpanContext(io.opentracing.SpanContext) Objects(java.util.Objects) CommandRouterMetrics(org.eclipse.hono.commandrouter.CommandRouterMetrics) TenantTraceSamplingHelper(org.eclipse.hono.tracing.TenantTraceSamplingHelper) Optional(java.util.Optional) Span(io.opentracing.Span) TenantObject(org.eclipse.hono.util.TenantObject) DeviceDisabledOrNotRegisteredException(org.eclipse.hono.client.registry.DeviceDisabledOrNotRegisteredException) Command(org.eclipse.hono.client.command.Command) NoConsumerException(org.eclipse.hono.client.NoConsumerException) MessagingType(org.eclipse.hono.util.MessagingType) ClientErrorException(org.eclipse.hono.client.ClientErrorException) TenantDisabledOrNotRegisteredException(org.eclipse.hono.client.registry.TenantDisabledOrNotRegisteredException) ServerErrorException(org.eclipse.hono.client.ServerErrorException)

Example 3 with TenantDisabledOrNotRegisteredException

use of org.eclipse.hono.client.registry.TenantDisabledOrNotRegisteredException in project hono by eclipse.

the class KafkaBasedInternalCommandConsumer method handleCommandMessage.

void handleCommandMessage(final KafkaConsumerRecord<String, Buffer> record) {
    // get partition/offset of the command record - related to the tenant-based topic the command was originally received in
    final Integer commandPartition = KafkaRecordHelper.getOriginalPartitionHeader(record.headers()).orElse(null);
    final Long commandOffset = KafkaRecordHelper.getOriginalOffsetHeader(record.headers()).orElse(null);
    if (commandPartition == null || commandOffset == null) {
        LOG.warn("command record is invalid - missing required original partition/offset headers");
        return;
    }
    final KafkaBasedCommand command;
    try {
        command = KafkaBasedCommand.fromRoutedCommandRecord(record);
    } catch (final IllegalArgumentException e) {
        LOG.warn("command record is invalid [tenant-id: {}, device-id: {}]", KafkaRecordHelper.getTenantId(record.headers()).orElse(null), KafkaRecordHelper.getDeviceId(record.headers()).orElse(null), e);
        return;
    }
    // check whether command has already been received and handled;
    // partition index and offset here are related to the *tenant-based* topic the command was originally received in
    // therefore they are stored in a map with the tenant as key
    final Map<Integer, Long> lastHandledPartitionOffsets = lastHandledPartitionOffsetsPerTenant.computeIfAbsent(command.getTenant(), k -> new HashMap<>());
    final Long lastHandledOffset = lastHandledPartitionOffsets.get(commandPartition);
    if (lastHandledOffset != null && commandOffset <= lastHandledOffset) {
        if (LOG.isDebugEnabled()) {
            LOG.debug("ignoring command - record partition offset {} <= last handled offset {} [{}]", commandOffset, lastHandledOffset, command);
        }
    } else {
        lastHandledPartitionOffsets.put(commandPartition, commandOffset);
        final CommandHandlerWrapper commandHandler = commandHandlers.getCommandHandler(command.getTenant(), command.getGatewayOrDeviceId());
        if (commandHandler != null && commandHandler.getGatewayId() != null) {
            // Gateway information set in command handler means a gateway has subscribed for commands for a specific device.
            // This information isn't getting set in the record (by the Command Router) and therefore has to be adopted manually here.
            command.setGatewayId(commandHandler.getGatewayId());
        }
        final SpanContext spanContext = KafkaTracingHelper.extractSpanContext(tracer, record);
        final SpanContext followsFromSpanContext = commandHandler != null ? commandHandler.getConsumerCreationSpanContext() : null;
        final Span currentSpan = CommandContext.createSpan(tracer, command, spanContext, followsFromSpanContext, getClass().getSimpleName());
        currentSpan.setTag(MessageHelper.APP_PROPERTY_ADAPTER_INSTANCE_ID, adapterInstanceId);
        KafkaTracingHelper.TAG_OFFSET.set(currentSpan, record.offset());
        final var commandContext = new KafkaBasedCommandContext(command, commandResponseSender, currentSpan);
        tenantClient.get(command.getTenant(), spanContext).onFailure(t -> {
            if (ServiceInvocationException.extractStatusCode(t) == HttpURLConnection.HTTP_NOT_FOUND) {
                commandContext.reject(new TenantDisabledOrNotRegisteredException(command.getTenant(), HttpURLConnection.HTTP_NOT_FOUND));
            } else {
                commandContext.release(new ServerErrorException(command.getTenant(), HttpURLConnection.HTTP_UNAVAILABLE, "error retrieving tenant configuration", t));
            }
        }).onSuccess(tenantConfig -> {
            commandContext.put(CommandContext.KEY_TENANT_CONFIG, tenantConfig);
            if (commandHandler != null) {
                LOG.trace("using [{}] for received command [{}]", commandHandler, command);
                // command.isValid() check not done here - it is to be done in the command handler
                commandHandler.handleCommand(commandContext);
            } else {
                LOG.info("no command handler found for command [{}]", command);
                commandContext.release(new NoConsumerException("no command handler found for command"));
            }
        });
    }
}
Also used : HttpURLConnection(java.net.HttpURLConnection) MessagingKafkaConsumerConfigProperties(org.eclipse.hono.client.kafka.consumer.MessagingKafkaConsumerConfigProperties) LoggerFactory(org.slf4j.LoggerFactory) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) HashMap(java.util.HashMap) CommandHandlerWrapper(org.eclipse.hono.client.command.CommandHandlerWrapper) TenantDisabledOrNotRegisteredException(org.eclipse.hono.client.registry.TenantDisabledOrNotRegisteredException) ServiceInvocationException(org.eclipse.hono.client.ServiceInvocationException) Supplier(java.util.function.Supplier) CommandResponseSender(org.eclipse.hono.client.command.CommandResponseSender) KafkaClientFactory(org.eclipse.hono.client.kafka.KafkaClientFactory) Context(io.vertx.core.Context) NoConsumerException(org.eclipse.hono.client.NoConsumerException) CompositeFuture(io.vertx.core.CompositeFuture) Status(io.vertx.ext.healthchecks.Status) HealthCheckHandler(io.vertx.ext.healthchecks.HealthCheckHandler) KafkaClientMetricsSupport(org.eclipse.hono.client.kafka.metrics.KafkaClientMetricsSupport) Map(java.util.Map) KafkaAdminClientConfigProperties(org.eclipse.hono.client.kafka.KafkaAdminClientConfigProperties) Admin(org.apache.kafka.clients.admin.Admin) CommandHandlers(org.eclipse.hono.client.command.CommandHandlers) KafkaTracingHelper(org.eclipse.hono.client.kafka.tracing.KafkaTracingHelper) CommonClientConfigs(org.apache.kafka.clients.CommonClientConfigs) Logger(org.slf4j.Logger) Tracer(io.opentracing.Tracer) Promise(io.vertx.core.Promise) NewTopic(org.apache.kafka.clients.admin.NewTopic) CommandContext(org.eclipse.hono.client.command.CommandContext) Vertx(io.vertx.core.Vertx) Set(java.util.Set) ServerErrorException(org.eclipse.hono.client.ServerErrorException) ConsumerConfig(org.apache.kafka.clients.consumer.ConsumerConfig) KafkaRecordHelper(org.eclipse.hono.client.kafka.KafkaRecordHelper) TenantClient(org.eclipse.hono.client.registry.TenantClient) MessageHelper(org.eclipse.hono.util.MessageHelper) Future(io.vertx.core.Future) InternalCommandConsumer(org.eclipse.hono.client.command.InternalCommandConsumer) SpanContext(io.opentracing.SpanContext) TopicPartition(io.vertx.kafka.client.common.TopicPartition) Objects(java.util.Objects) HonoTopic(org.eclipse.hono.client.kafka.HonoTopic) List(java.util.List) TopicExistsException(org.apache.kafka.common.errors.TopicExistsException) Buffer(io.vertx.core.buffer.Buffer) KafkaConsumerRecord(io.vertx.kafka.client.consumer.KafkaConsumerRecord) Optional(java.util.Optional) Span(io.opentracing.Span) KafkaConsumer(io.vertx.kafka.client.consumer.KafkaConsumer) SpanContext(io.opentracing.SpanContext) NoConsumerException(org.eclipse.hono.client.NoConsumerException) TenantDisabledOrNotRegisteredException(org.eclipse.hono.client.registry.TenantDisabledOrNotRegisteredException) Span(io.opentracing.Span) CommandHandlerWrapper(org.eclipse.hono.client.command.CommandHandlerWrapper) ServerErrorException(org.eclipse.hono.client.ServerErrorException)

Aggregations

Span (io.opentracing.Span)3 SpanContext (io.opentracing.SpanContext)3 Future (io.vertx.core.Future)3 HttpURLConnection (java.net.HttpURLConnection)3 Objects (java.util.Objects)3 Optional (java.util.Optional)3 ServerErrorException (org.eclipse.hono.client.ServerErrorException)3 CommandContext (org.eclipse.hono.client.command.CommandContext)3 Tracer (io.opentracing.Tracer)2 Tags (io.opentracing.tag.Tags)2 CompositeFuture (io.vertx.core.CompositeFuture)2 Promise (io.vertx.core.Promise)2 Buffer (io.vertx.core.buffer.Buffer)2 JsonObject (io.vertx.core.json.JsonObject)2 List (java.util.List)2 Map (java.util.Map)2 ClientErrorException (org.eclipse.hono.client.ClientErrorException)2 Command (org.eclipse.hono.client.command.Command)2 TenantDisabledOrNotRegisteredException (org.eclipse.hono.client.registry.TenantDisabledOrNotRegisteredException)2 MetricsTags (org.eclipse.hono.service.metric.MetricsTags)2