use of io.opentracing.SpanContext in project hono by eclipse.
the class TableManagementStore method setCredentials.
/**
* Set all credentials for a device.
* <p>
* This will set/update all credentials of the device. If the device does not exist, the result
* will be {@code false}. If the update was successful, then the result will be {@code true}.
* If the resource version was provided, but the provided version was no longer the current version,
* then the future will fail with a {@link OptimisticLockingException}.
*
* @param key The key of the device to update.
* @param credentials The credentials to set.
* @param resourceVersion The optional resource version to update.
* @param spanContext The span to contribute to.
* @return A future, tracking the outcome of the operation.
*/
public Future<Versioned<Boolean>> setCredentials(final DeviceKey key, final List<CommonCredential> credentials, final Optional<String> resourceVersion, final SpanContext spanContext) {
final Span span = TracingHelper.buildChildSpan(this.tracer, spanContext, "set credentials", getClass().getSimpleName()).withTag(TracingHelper.TAG_TENANT_ID, key.getTenantId()).withTag(TracingHelper.TAG_DEVICE_ID, key.getDeviceId()).withTag("num_credentials", credentials.size()).start();
resourceVersion.ifPresent(version -> span.setTag("version", version));
final String nextVersion = UUID.randomUUID().toString();
return SQL.runTransactionally(this.client, this.tracer, span.context(), (connection, context) -> readDeviceForUpdate(connection, key, context).compose(result -> extractVersionForUpdate(result, resourceVersion)).compose(version -> Future.succeededFuture().compose(x -> {
final Promise<CredentialsDto> result = Promise.promise();
final var updatedCredentialsDto = CredentialsDto.forUpdate(key.getTenantId(), key.getDeviceId(), credentials, nextVersion);
if (updatedCredentialsDto.requiresMerging()) {
getCredentialsDto(key, connection, span).map(updatedCredentialsDto::merge).onComplete(result);
} else {
// simply replace the existing credentials with the
// updated ones provided by the client
result.complete(updatedCredentialsDto);
}
return result.future();
}).compose(updatedCredentials -> this.deleteAllCredentialsStatement.expand(map -> {
map.put("tenant_id", key.getTenantId());
map.put("device_id", key.getDeviceId());
}).trace(this.tracer, span.context()).update(connection).map(updatedCredentials)).compose(updatedCredentials -> {
updatedCredentials.createMissingSecretIds();
return CompositeFuture.all(updatedCredentials.getData().stream().map(JsonObject::mapFrom).filter(c -> c.containsKey("type") && c.containsKey("auth-id")).map(c -> this.insertCredentialEntryStatement.expand(map -> {
map.put("tenant_id", key.getTenantId());
map.put("device_id", key.getDeviceId());
map.put("type", c.getString("type"));
map.put("auth_id", c.getString("auth-id"));
map.put("data", c.toString());
}).trace(this.tracer, span.context()).update(connection)).collect(Collectors.toList())).mapEmpty();
}).compose(x -> this.updateDeviceVersionStatement.expand(map -> {
map.put("tenant_id", key.getTenantId());
map.put("device_id", key.getDeviceId());
map.put("expected_version", version);
map.put("next_version", nextVersion);
}).trace(this.tracer, span.context()).update(connection).compose(TableManagementStore::checkUpdateOutcome)).map(true))).recover(err -> recoverNotFound(span, err, () -> false)).map(ok -> new Versioned<>(nextVersion, ok)).onComplete(x -> span.finish());
}
use of io.opentracing.SpanContext in project hono by eclipse.
the class TableManagementStore method getCredentials.
/**
* Get all credentials for a device.
* <p>
* This gets the credentials of a device. If the device cannot be found, the
* result must be empty. If no credentials could be found for an existing device,
* the result must not be empty, but provide an empty {@link CredentialsReadResult}.
*
* @param key The key of the device.
* @param spanContext The span to contribute to.
* @return A future, tracking the outcome of the operation.
*/
public Future<Optional<CredentialsReadResult>> getCredentials(final DeviceKey key, final SpanContext spanContext) {
final Span span = TracingHelper.buildChildSpan(this.tracer, spanContext, "get credentials", getClass().getSimpleName()).withTag(TracingHelper.TAG_TENANT_ID, key.getTenantId()).withTag(TracingHelper.TAG_DEVICE_ID, key.getDeviceId()).start();
final var expanded = this.readCredentialsStatement.expand(map -> {
map.put("tenant_id", key.getTenantId());
map.put("device_id", key.getDeviceId());
});
final Promise<SQLConnection> promise = Promise.promise();
this.client.getConnection(promise);
return promise.future().compose(connection -> readDevice(connection, key, span).compose(result -> extractVersionForUpdate(result, Optional.empty())).compose(version -> expanded.trace(this.tracer, span.context()).query(connection).compose(r -> {
span.log(Map.of(Fields.EVENT, "read result", "rows", r.getNumRows()));
final var credentials = parseCredentials(r);
log.debug("Credentials: {}", credentials);
return Future.succeededFuture(Optional.of(new CredentialsReadResult(key.getDeviceId(), credentials, Optional.ofNullable(version))));
})).onComplete(x -> connection.close())).recover(err -> recoverNotFound(span, err, Optional::empty)).onComplete(x -> span.finish());
}
use of io.opentracing.SpanContext in project hono by eclipse.
the class TableManagementStore method createDevice.
/**
* Creates a new device.
* <p>
* This method executes the {@code create} statement, providing the named parameters
* {@code tenant_id}, {@code device_id}, {@code version}, and {@code data}.
* <p>
* It returns the plain update result. In case a device with the same ID already
* exists, the underlying database must throw an {@link java.sql.SQLException}, indicating
* a duplicate entity or constraint violation. This will be translated into a
* failed future with an {@link org.eclipse.hono.service.base.jdbc.store.DuplicateKeyException}.
*
* @param key The key of the device to create.
* @param device The device data.
* @param tenant The configuration of the tenant that the device belongs to.
* @param globalDevicesPerTenantLimit The globally defined maximum number of devices per tenant. A value
* <= 0 will be interpreted as no limit being defined.
* @param spanContext The span to contribute to.
* @return A future, tracking the outcome of the operation.
*/
public Future<Versioned<Void>> createDevice(final DeviceKey key, final Device device, final Tenant tenant, final int globalDevicesPerTenantLimit, final SpanContext spanContext) {
final Span span = TracingHelper.buildChildSpan(this.tracer, spanContext, "create device", getClass().getSimpleName()).withTag(TracingHelper.TAG_TENANT_ID, key.getTenantId()).withTag(TracingHelper.TAG_DEVICE_ID, key.getDeviceId()).start();
final JdbcBasedDeviceDto deviceDto = JdbcBasedDeviceDto.forCreation(key, device, DeviceRegistryUtils.getUniqueIdentifier());
return SQL.runTransactionally(this.client, this.tracer, span.context(), (connection, context) -> {
final var expanded = this.createStatement.expand(params -> {
params.put("tenant_id", deviceDto.getTenantId());
params.put("device_id", deviceDto.getDeviceId());
params.put("version", deviceDto.getVersion());
params.put("data", deviceDto.getDeviceJson());
params.put("created", Timestamp.from(deviceDto.getCreationTime()));
params.put("auto_provisioned", deviceDto.isAutoProvisioned());
});
log.debug("createDevice - statement: {}", expanded);
return getDeviceCount(key.getTenantId(), span.context()).compose(currentDeviceCount -> tenant.checkDeviceLimitReached(key.getTenantId(), currentDeviceCount, globalDevicesPerTenantLimit)).compose(ok -> expanded.trace(this.tracer, context).update(this.client).recover(SQL::translateException)).compose(x -> createGroups(connection, key, new HashSet<>(device.getMemberOf()), context));
}).map(new Versioned<Void>(deviceDto.getVersion(), null)).onComplete(x -> span.finish());
}
use of io.opentracing.SpanContext in project hono by eclipse.
the class KafkaBasedMappingAndDelegatingCommandHandler 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 consumerRecord The consumer record corresponding to the command.
* @return A future indicating the outcome of the operation.
* @throws NullPointerException if any of the parameters is {@code null}.
*/
public Future<Void> mapAndDelegateIncomingCommandMessage(final KafkaConsumerRecord<String, Buffer> consumerRecord) {
Objects.requireNonNull(consumerRecord);
final Timer.Sample timer = getMetrics().startTimer();
final KafkaBasedCommand command;
try {
command = KafkaBasedCommand.from(consumerRecord);
} catch (final IllegalArgumentException exception) {
log.debug("command record is invalid", exception);
return Future.failedFuture("command record is invalid");
}
final SpanContext spanContext = KafkaTracingHelper.extractSpanContext(tracer, consumerRecord);
final Span currentSpan = createSpan(command.getTenant(), command.getDeviceId(), spanContext);
KafkaTracingHelper.setRecordTags(currentSpan, consumerRecord);
final KafkaBasedCommandContext commandContext = new KafkaBasedCommandContext(command, kafkaBasedCommandResponseSender, currentSpan);
command.logToSpan(currentSpan);
if (!command.isValid()) {
log.debug("received invalid command record [{}]", command);
return tenantClient.get(command.getTenant(), currentSpan.context()).compose(tenantConfig -> {
commandContext.put(CommandContext.KEY_TENANT_CONFIG, tenantConfig);
return Future.failedFuture("command is invalid");
}).onComplete(ar -> {
commandContext.reject("malformed command message");
reportInvalidCommand(commandContext, timer);
}).mapEmpty();
}
log.trace("received valid command record [{}]", command);
commandQueue.add(commandContext);
final Promise<Void> resultPromise = Promise.promise();
final long timerId = vertx.setTimer(PROCESSING_TIMEOUT.toMillis(), tid -> {
if (commandQueue.remove(commandContext) || !commandContext.isCompleted()) {
log.info("command processing timed out after {}s [{}]", PROCESSING_TIMEOUT.toSeconds(), commandContext.getCommand());
TracingHelper.logError(commandContext.getTracingSpan(), String.format("command processing timed out after %ds", PROCESSING_TIMEOUT.toSeconds()));
final ServerErrorException error = new ServerErrorException(HttpURLConnection.HTTP_UNAVAILABLE, "command processing timed out");
commandContext.release(error);
resultPromise.tryFail(error);
}
});
mapAndDelegateIncomingCommand(commandContext, timer).onComplete(ar -> {
vertx.cancelTimer(timerId);
if (ar.failed()) {
commandQueue.remove(commandContext);
}
Futures.tryHandleResult(resultPromise, ar);
});
return resultPromise.future();
}
use of io.opentracing.SpanContext in project hono by eclipse.
the class TableAdapterStore method resolveGroupMembers.
/**
* Resolve a list of group members.
*
* @param tenantId The tenant the device belongs to.
* @param viaGroups The viaGroups list of a device. This list contains the ids of groups.
* @param spanContext The span to contribute to.
*
* @return A future tracking the outcome of the operation.
*
* @see org.eclipse.hono.deviceregistry.service.device.AbstractRegistrationService#resolveGroupMembers(String, JsonArray, Span)
*/
public Future<Set<String>> resolveGroupMembers(final String tenantId, final Set<String> viaGroups, final SpanContext spanContext) {
final Span span = TracingHelper.buildChildSpan(this.tracer, spanContext, "resolve group members", getClass().getSimpleName()).withTag(TracingHelper.TAG_TENANT_ID, tenantId).withTag("via_groups", String.join(", ", viaGroups)).start();
final var expanded = this.resolveGroupsStatement.expand(params -> {
params.put("tenant_id", tenantId);
params.put("group_ids", convertToArrayValue(viaGroups));
});
log.debug("resolveGroupMembers - statement: {}", expanded);
return expanded.trace(this.tracer, span.context()).query(this.client).flatMap(r -> {
final var entries = r.getRows(true);
span.log(Map.of("event", "read result", "rows", entries.size()));
return Future.succeededFuture(entries.stream().map(o -> o.getString("device_id")).filter(Objects::nonNull).collect(Collectors.toSet()));
}).onComplete(x -> span.finish());
}
Aggregations