Target attributes update can be (re-)triggered by management API (#690)
* extend Management API with attribute `requestAttributes` * introduce new DMF Event Topic `REQUEST_ATTRIBUTES_UPDATE` * enhance REST documentation by new functionality * add tests for: * Management API * Amqp Message Dispatcher Service * Repository (Target Management) Signed-off-by: Jeroen Jan Laverman (INST/ESY3) <jeroen.laverman@bosch-si.com>
This commit is contained in:
committed by
Dominic Schabel
parent
f4340098d9
commit
ecfe774e53
@@ -36,6 +36,7 @@ import org.eclipse.hawkbit.repository.SystemManagement;
|
|||||||
import org.eclipse.hawkbit.repository.TargetManagement;
|
import org.eclipse.hawkbit.repository.TargetManagement;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.TargetAssignDistributionSetEvent;
|
import org.eclipse.hawkbit.repository.event.remote.TargetAssignDistributionSetEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.TargetDeletedEvent;
|
import org.eclipse.hawkbit.repository.event.remote.TargetDeletedEvent;
|
||||||
|
import org.eclipse.hawkbit.repository.event.remote.TargetAttributesRequestedEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.entity.CancelTargetAssignmentEvent;
|
import org.eclipse.hawkbit.repository.event.remote.entity.CancelTargetAssignmentEvent;
|
||||||
import org.eclipse.hawkbit.repository.model.Artifact;
|
import org.eclipse.hawkbit.repository.model.Artifact;
|
||||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||||
@@ -157,8 +158,8 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
|
|||||||
* window available, the topic {@link EventTopic#DOWNLOAD_AND_INSTALL} is
|
* window available, the topic {@link EventTopic#DOWNLOAD_AND_INSTALL} is
|
||||||
* returned else {@link EventTopic#DOWNLOAD} is returned.
|
* returned else {@link EventTopic#DOWNLOAD} is returned.
|
||||||
*
|
*
|
||||||
* @param target
|
* @param maintenanceWindowAvailable
|
||||||
* for which to find the event type
|
* valid maintenance window or not.
|
||||||
*
|
*
|
||||||
* @return {@link EventTopic} to use for message.
|
* @return {@link EventTopic} to use for message.
|
||||||
*/
|
*/
|
||||||
@@ -199,6 +200,12 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
|
|||||||
sendDeleteMessage(deleteEvent.getTenant(), deleteEvent.getControllerId(), deleteEvent.getTargetAddress());
|
sendDeleteMessage(deleteEvent.getTenant(), deleteEvent.getControllerId(), deleteEvent.getTargetAddress());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@EventListener(classes = TargetAttributesRequestedEvent.class)
|
||||||
|
protected void targetTriggerUpdateAttributes(final TargetAttributesRequestedEvent updateAttributesEvent) {
|
||||||
|
sendUpdateAttributesMessageToTarget(updateAttributesEvent.getTenant(), updateAttributesEvent.getControllerId(),
|
||||||
|
updateAttributesEvent.getTargetAddress());
|
||||||
|
}
|
||||||
|
|
||||||
protected void sendUpdateMessageToTarget(final String tenant, final Target target, final Long actionId,
|
protected void sendUpdateMessageToTarget(final String tenant, final Target target, final Long actionId,
|
||||||
final Map<SoftwareModule, List<SoftwareModuleMetadata>> modules, final boolean maintenanceWindowAvailable) {
|
final Map<SoftwareModule, List<SoftwareModuleMetadata>> modules, final boolean maintenanceWindowAvailable) {
|
||||||
|
|
||||||
@@ -270,6 +277,18 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void sendUpdateAttributesMessageToTarget(final String tenant, final String controllerId,
|
||||||
|
final String targetAddress) {
|
||||||
|
if (!hasValidAddress(targetAddress)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final Message message = new Message(null,
|
||||||
|
createConnectorMessagePropertiesEvent(tenant, controllerId, EventTopic.REQUEST_ATTRIBUTES_UPDATE));
|
||||||
|
|
||||||
|
amqpSenderService.sendMessage(message, URI.create(targetAddress));
|
||||||
|
}
|
||||||
|
|
||||||
private static MessageProperties createConnectorMessagePropertiesEvent(final String tenant,
|
private static MessageProperties createConnectorMessagePropertiesEvent(final String tenant,
|
||||||
final String controllerId, final EventTopic topic) {
|
final String controllerId, final EventTopic topic) {
|
||||||
final MessageProperties messageProperties = createConnectorMessageProperties(tenant, controllerId);
|
final MessageProperties messageProperties = createConnectorMessageProperties(tenant, controllerId);
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ import org.eclipse.hawkbit.dmf.json.model.DmfDownloadAndUpdateRequest;
|
|||||||
import org.eclipse.hawkbit.dmf.json.model.DmfMetadata;
|
import org.eclipse.hawkbit.dmf.json.model.DmfMetadata;
|
||||||
import org.eclipse.hawkbit.repository.SystemManagement;
|
import org.eclipse.hawkbit.repository.SystemManagement;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.TargetAssignDistributionSetEvent;
|
import org.eclipse.hawkbit.repository.event.remote.TargetAssignDistributionSetEvent;
|
||||||
|
import org.eclipse.hawkbit.repository.event.remote.TargetAttributesRequestedEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.TargetDeletedEvent;
|
import org.eclipse.hawkbit.repository.event.remote.TargetDeletedEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.entity.CancelTargetAssignmentEvent;
|
import org.eclipse.hawkbit.repository.event.remote.entity.CancelTargetAssignmentEvent;
|
||||||
import org.eclipse.hawkbit.repository.jpa.RepositoryApplicationConfiguration;
|
import org.eclipse.hawkbit.repository.jpa.RepositoryApplicationConfiguration;
|
||||||
@@ -214,6 +215,19 @@ public class AmqpMessageDispatcherServiceTest extends AbstractIntegrationTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Description("Verifies that sending update controller attributes event works.")
|
||||||
|
public void sendUpdateAttributesRequest() {
|
||||||
|
final String amqpUri = "amqp://anyhost";
|
||||||
|
final TargetAttributesRequestedEvent targetAttributesRequestedEvent = new TargetAttributesRequestedEvent(TENANT,
|
||||||
|
1L, CONTROLLER_ID, amqpUri, Target.class.getName(), serviceMatcher.getServiceId());
|
||||||
|
|
||||||
|
amqpMessageDispatcherService.targetTriggerUpdateAttributes(targetAttributesRequestedEvent);
|
||||||
|
|
||||||
|
final Message sendMessage = createArgumentCapture(URI.create(amqpUri));
|
||||||
|
assertUpdateAttributesMessage(sendMessage);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Description("Verifies that send cancel event works")
|
@Description("Verifies that send cancel event works")
|
||||||
public void testSendCancelRequest() {
|
public void testSendCancelRequest() {
|
||||||
@@ -299,7 +313,7 @@ public class AmqpMessageDispatcherServiceTest extends AbstractIntegrationTest {
|
|||||||
final DmfDownloadAndUpdateRequest downloadAndUpdateRequest = convertMessage(sendMessage,
|
final DmfDownloadAndUpdateRequest downloadAndUpdateRequest = convertMessage(sendMessage,
|
||||||
DmfDownloadAndUpdateRequest.class);
|
DmfDownloadAndUpdateRequest.class);
|
||||||
assertEquals(downloadAndUpdateRequest.getActionId(), action);
|
assertEquals(downloadAndUpdateRequest.getActionId(), action);
|
||||||
assertEquals("The topic of the event shuold contain DOWNLOAD_AND_INSTALL", EventTopic.DOWNLOAD_AND_INSTALL,
|
assertEquals("The topic of the event should contain DOWNLOAD_AND_INSTALL", EventTopic.DOWNLOAD_AND_INSTALL,
|
||||||
sendMessage.getMessageProperties().getHeaders().get(MessageHeaderKey.TOPIC));
|
sendMessage.getMessageProperties().getHeaders().get(MessageHeaderKey.TOPIC));
|
||||||
assertEquals("Security token of target", TEST_TOKEN, downloadAndUpdateRequest.getTargetSecurityToken());
|
assertEquals("Security token of target", TEST_TOKEN, downloadAndUpdateRequest.getTargetSecurityToken());
|
||||||
|
|
||||||
@@ -307,6 +321,14 @@ public class AmqpMessageDispatcherServiceTest extends AbstractIntegrationTest {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void assertUpdateAttributesMessage(final Message sendMessage) {
|
||||||
|
assertEventMessage(sendMessage);
|
||||||
|
|
||||||
|
assertEquals("The topic of the event should contain REQUEST_ATTRIBUTES_UPDATE",
|
||||||
|
EventTopic.REQUEST_ATTRIBUTES_UPDATE,
|
||||||
|
sendMessage.getMessageProperties().getHeaders().get(MessageHeaderKey.TOPIC));
|
||||||
|
}
|
||||||
|
|
||||||
private void assertEventMessage(final Message sendMessage) {
|
private void assertEventMessage(final Message sendMessage) {
|
||||||
assertNotNull("The message should not be null", sendMessage);
|
assertNotNull("The message should not be null", sendMessage);
|
||||||
|
|
||||||
|
|||||||
@@ -32,6 +32,10 @@ public enum EventTopic {
|
|||||||
/**
|
/**
|
||||||
* Topic when sending a download only task, skipping the install.
|
* Topic when sending a download only task, skipping the install.
|
||||||
*/
|
*/
|
||||||
DOWNLOAD;
|
DOWNLOAD,
|
||||||
|
/**
|
||||||
|
* Topic when an update of device attributes is requested.
|
||||||
|
*/
|
||||||
|
REQUEST_ATTRIBUTES_UPDATE;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -109,8 +109,7 @@ public interface TargetManagement {
|
|||||||
Long installedOrAssignedDistributionSetId, Boolean selectTargetWithNoTag, String... tagNames);
|
Long installedOrAssignedDistributionSetId, Boolean selectTargetWithNoTag, String... tagNames);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Counts number of targets with given
|
* Counts number of targets with given with given distribution set Id
|
||||||
* {@link Target#getInstalledDistributionSet()}.
|
|
||||||
*
|
*
|
||||||
* @param distId
|
* @param distId
|
||||||
* to search for
|
* to search for
|
||||||
@@ -630,4 +629,25 @@ public interface TargetManagement {
|
|||||||
* if target with given ID does not exist
|
* if target with given ID does not exist
|
||||||
*/
|
*/
|
||||||
Map<String, String> getControllerAttributes(@NotEmpty String controllerId);
|
Map<String, String> getControllerAttributes(@NotEmpty String controllerId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trigger given {@link Target} to update its attributes.
|
||||||
|
*
|
||||||
|
* @param controllerId
|
||||||
|
* of the target
|
||||||
|
*
|
||||||
|
* @throws EntityNotFoundException
|
||||||
|
* if target with given ID does not exist
|
||||||
|
*/
|
||||||
|
void requestControllerAttributes(@NotEmpty String controllerId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if update of given {@link Target} attributes is already requested.
|
||||||
|
*
|
||||||
|
* @param controllerId
|
||||||
|
* of target
|
||||||
|
* @return {@code true}: update of controller attributes triggered.
|
||||||
|
* {@code false}: update of controller attributes not requested.
|
||||||
|
*/
|
||||||
|
boolean isControllerAttributesRequested(@NotEmpty String controllerId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -67,4 +67,10 @@ public interface TargetUpdate {
|
|||||||
* @return updated builder instance
|
* @return updated builder instance
|
||||||
*/
|
*/
|
||||||
TargetUpdate status(@NotNull TargetUpdateStatus status);
|
TargetUpdate status(@NotNull TargetUpdateStatus status);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param requestAttributes for {@link Target#isRequestControllerAttributes()}
|
||||||
|
* @return updated builder instance
|
||||||
|
*/
|
||||||
|
TargetUpdate requestAttributes(Boolean requestAttributes);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,58 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2018 Bosch Software Innovations GmbH and others.
|
||||||
|
*
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
*/
|
||||||
|
package org.eclipse.hawkbit.repository.event.remote;
|
||||||
|
|
||||||
|
import org.eclipse.hawkbit.repository.model.Target;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines the remote event of triggering attribute updates of a {@link Target}.
|
||||||
|
*/
|
||||||
|
public class TargetAttributesRequestedEvent extends RemoteIdEvent {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
private String controllerId;
|
||||||
|
private String targetAddress;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default constructor.
|
||||||
|
*/
|
||||||
|
public TargetAttributesRequestedEvent() {
|
||||||
|
// for serialization libs like jackson
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor json serialization
|
||||||
|
*
|
||||||
|
* @param tenant
|
||||||
|
* the tenant
|
||||||
|
* @param entityId
|
||||||
|
* the entity id
|
||||||
|
* @param controllerId
|
||||||
|
* the controllerId of the target
|
||||||
|
* @param targetAddress
|
||||||
|
* the target address
|
||||||
|
* @param entityClass
|
||||||
|
* the entity class
|
||||||
|
* @param applicationId
|
||||||
|
* the origin application id
|
||||||
|
*/
|
||||||
|
public TargetAttributesRequestedEvent(final String tenant, final Long entityId, final String controllerId,
|
||||||
|
final String targetAddress, final String entityClass, final String applicationId) {
|
||||||
|
super(entityId, tenant, entityClass, applicationId);
|
||||||
|
this.controllerId = controllerId;
|
||||||
|
this.targetAddress = targetAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getControllerId() {
|
||||||
|
return controllerId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTargetAddress() {
|
||||||
|
return targetAddress;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -34,6 +34,8 @@ public class AbstractTargetUpdateCreate<T> extends AbstractNamedEntityBuilder<T>
|
|||||||
protected Long lastTargetQuery;
|
protected Long lastTargetQuery;
|
||||||
protected TargetUpdateStatus status;
|
protected TargetUpdateStatus status;
|
||||||
|
|
||||||
|
protected Boolean requestAttributes;
|
||||||
|
|
||||||
protected AbstractTargetUpdateCreate(final String controllerId) {
|
protected AbstractTargetUpdateCreate(final String controllerId) {
|
||||||
this.controllerId = StringUtils.trimWhitespace(controllerId);
|
this.controllerId = StringUtils.trimWhitespace(controllerId);
|
||||||
}
|
}
|
||||||
@@ -62,6 +64,11 @@ public class AbstractTargetUpdateCreate<T> extends AbstractNamedEntityBuilder<T>
|
|||||||
return (T) this;
|
return (T) this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public T requestAttributes(final Boolean requestAttributes) {
|
||||||
|
this.requestAttributes = requestAttributes;
|
||||||
|
return (T) this;
|
||||||
|
}
|
||||||
|
|
||||||
public T lastTargetQuery(final Long lastTargetQuery) {
|
public T lastTargetQuery(final Long lastTargetQuery) {
|
||||||
this.lastTargetQuery = lastTargetQuery;
|
this.lastTargetQuery = lastTargetQuery;
|
||||||
return (T) this;
|
return (T) this;
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ import org.eclipse.hawkbit.repository.TimestampCalculator;
|
|||||||
import org.eclipse.hawkbit.repository.builder.TargetCreate;
|
import org.eclipse.hawkbit.repository.builder.TargetCreate;
|
||||||
import org.eclipse.hawkbit.repository.builder.TargetUpdate;
|
import org.eclipse.hawkbit.repository.builder.TargetUpdate;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.TargetDeletedEvent;
|
import org.eclipse.hawkbit.repository.event.remote.TargetDeletedEvent;
|
||||||
|
import org.eclipse.hawkbit.repository.event.remote.TargetAttributesRequestedEvent;
|
||||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||||
import org.eclipse.hawkbit.repository.jpa.builder.JpaTargetCreate;
|
import org.eclipse.hawkbit.repository.jpa.builder.JpaTargetCreate;
|
||||||
import org.eclipse.hawkbit.repository.jpa.builder.JpaTargetUpdate;
|
import org.eclipse.hawkbit.repository.jpa.builder.JpaTargetUpdate;
|
||||||
@@ -640,4 +641,24 @@ public class JpaTargetManagement implements TargetManagement {
|
|||||||
return target.getControllerAttributes();
|
return target.getControllerAttributes();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void requestControllerAttributes(final String controllerId) {
|
||||||
|
final JpaTarget target = (JpaTarget) getByControllerID(controllerId)
|
||||||
|
.orElseThrow(() -> new EntityNotFoundException(Target.class, controllerId));
|
||||||
|
|
||||||
|
target.setRequestControllerAttributes(true);
|
||||||
|
|
||||||
|
eventPublisher.publishEvent(new TargetAttributesRequestedEvent(tenantAware.getCurrentTenant(), target.getId(),
|
||||||
|
target.getControllerId(), target.getAddress() != null ? target.getAddress().toString() : null,
|
||||||
|
JpaTarget.class.getName(), applicationContext.getId()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isControllerAttributesRequested(final String controllerId) {
|
||||||
|
final JpaTarget target = (JpaTarget) getByControllerID(controllerId)
|
||||||
|
.orElseThrow(() -> new EntityNotFoundException(Target.class, controllerId));
|
||||||
|
|
||||||
|
return target.isRequestControllerAttributes();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -178,8 +178,7 @@ public interface TargetRepository extends BaseEntityRepository<JpaTarget, Long>,
|
|||||||
Page<Target> findByAssignedDistributionSetId(final Pageable pageable, final Long setID);
|
Page<Target> findByAssignedDistributionSetId(final Pageable pageable, final Long setID);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Counts number of targets with given
|
* Counts number of targets with given distribution set Id.
|
||||||
* {@link Target#getAssignedDistributionSet()}.
|
|
||||||
*
|
*
|
||||||
* @param distId
|
* @param distId
|
||||||
* to search for
|
* to search for
|
||||||
@@ -189,8 +188,7 @@ public interface TargetRepository extends BaseEntityRepository<JpaTarget, Long>,
|
|||||||
Long countByAssignedDistributionSetId(final Long distId);
|
Long countByAssignedDistributionSetId(final Long distId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Counts number of targets with given
|
* Counts number of targets with given distribution set Id.
|
||||||
* {@link Target#getInstalledDistributionSet()}.
|
|
||||||
*
|
*
|
||||||
* @param distId
|
* @param distId
|
||||||
* to search for
|
* to search for
|
||||||
|
|||||||
@@ -880,4 +880,16 @@ public class TargetManagementTest extends AbstractJpaIntegrationTest {
|
|||||||
final List<Long> collect = foundDs.stream().map(Target::getId).collect(Collectors.toList());
|
final List<Long> collect = foundDs.stream().map(Target::getId).collect(Collectors.toList());
|
||||||
assertThat(collect).containsAll(searchIds);
|
assertThat(collect).containsAll(searchIds);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Description("Verify that the flag for requesting controller attributes is set correctly.")
|
||||||
|
public void verifyRequestControllerAttributes() {
|
||||||
|
final String knownTargetId = "KnownControllerId";
|
||||||
|
createTargetWithAttributes(knownTargetId);
|
||||||
|
|
||||||
|
assertThat(targetManagement.isControllerAttributesRequested(knownTargetId)).isFalse();
|
||||||
|
targetManagement.requestControllerAttributes(knownTargetId);
|
||||||
|
assertThat(targetManagement.isControllerAttributesRequested(knownTargetId)).isTrue();
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,6 +46,9 @@ public class MgmtTarget extends MgmtNamedEntity {
|
|||||||
@JsonProperty
|
@JsonProperty
|
||||||
private String securityToken;
|
private String securityToken;
|
||||||
|
|
||||||
|
@JsonProperty
|
||||||
|
private boolean requestAttributes;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the controllerId
|
* @return the controllerId
|
||||||
*/
|
*/
|
||||||
@@ -167,4 +170,13 @@ public class MgmtTarget extends MgmtNamedEntity {
|
|||||||
public void setSecurityToken(final String securityToken) {
|
public void setSecurityToken(final String securityToken) {
|
||||||
this.securityToken = securityToken;
|
this.securityToken = securityToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isRequestAttributes() {
|
||||||
|
return requestAttributes;
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
|
public void setRequestAttributes(final boolean requestAttributes) {
|
||||||
|
this.requestAttributes = requestAttributes;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,9 @@ public class MgmtTargetRequestBody {
|
|||||||
@JsonProperty
|
@JsonProperty
|
||||||
private String securityToken;
|
private String securityToken;
|
||||||
|
|
||||||
|
@JsonProperty
|
||||||
|
private Boolean requestAttributes;
|
||||||
|
|
||||||
public String getSecurityToken() {
|
public String getSecurityToken() {
|
||||||
return securityToken;
|
return securityToken;
|
||||||
}
|
}
|
||||||
@@ -88,4 +91,11 @@ public class MgmtTargetRequestBody {
|
|||||||
this.address = address;
|
this.address = address;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Boolean isRequestAttributes() {
|
||||||
|
return requestAttributes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRequestAttributes(final Boolean requestAttributes) {
|
||||||
|
this.requestAttributes = requestAttributes;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -133,6 +133,7 @@ public final class MgmtTargetMapper {
|
|||||||
targetRest.setLastModifiedAt(target.getLastModifiedAt());
|
targetRest.setLastModifiedAt(target.getLastModifiedAt());
|
||||||
|
|
||||||
targetRest.setSecurityToken(target.getSecurityToken());
|
targetRest.setSecurityToken(target.getSecurityToken());
|
||||||
|
targetRest.setRequestAttributes(target.isRequestControllerAttributes());
|
||||||
|
|
||||||
// last target query is the last controller request date
|
// last target query is the last controller request date
|
||||||
final Long lastTargetQuery = target.getLastTargetQuery();
|
final Long lastTargetQuery = target.getLastTargetQuery();
|
||||||
|
|||||||
@@ -120,9 +120,18 @@ public class MgmtTargetResource implements MgmtTargetRestApi {
|
|||||||
public ResponseEntity<MgmtTarget> updateTarget(@PathVariable("controllerId") final String controllerId,
|
public ResponseEntity<MgmtTarget> updateTarget(@PathVariable("controllerId") final String controllerId,
|
||||||
@RequestBody final MgmtTargetRequestBody targetRest) {
|
@RequestBody final MgmtTargetRequestBody targetRest) {
|
||||||
|
|
||||||
|
if (targetRest.isRequestAttributes() != null) {
|
||||||
|
if (targetRest.isRequestAttributes()) {
|
||||||
|
targetManagement.requestControllerAttributes(controllerId);
|
||||||
|
} else {
|
||||||
|
return ResponseEntity.badRequest().build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
final Target updateTarget = this.targetManagement.update(entityFactory.target().update(controllerId)
|
final Target updateTarget = this.targetManagement.update(entityFactory.target().update(controllerId)
|
||||||
.name(targetRest.getName()).description(targetRest.getDescription()).address(targetRest.getAddress())
|
.name(targetRest.getName()).description(targetRest.getDescription()).address(targetRest.getAddress())
|
||||||
.securityToken(targetRest.getSecurityToken()));
|
.securityToken(targetRest.getSecurityToken()).requestAttributes(targetRest.isRequestAttributes()));
|
||||||
|
|
||||||
|
|
||||||
final MgmtTarget response = MgmtTargetMapper.toResponse(updateTarget);
|
final MgmtTarget response = MgmtTargetMapper.toResponse(updateTarget);
|
||||||
MgmtTargetMapper.addPollStatus(updateTarget, response);
|
MgmtTargetMapper.addPollStatus(updateTarget, response);
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ import com.jayway.jsonpath.JsonPath;
|
|||||||
|
|
||||||
import ru.yandex.qatools.allure.annotations.Description;
|
import ru.yandex.qatools.allure.annotations.Description;
|
||||||
import ru.yandex.qatools.allure.annotations.Features;
|
import ru.yandex.qatools.allure.annotations.Features;
|
||||||
|
import ru.yandex.qatools.allure.annotations.Step;
|
||||||
import ru.yandex.qatools.allure.annotations.Stories;
|
import ru.yandex.qatools.allure.annotations.Stories;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1539,6 +1540,56 @@ public class MgmtTargetResourceTest extends AbstractManagementApiIntegrationTest
|
|||||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().is(HttpStatus.NO_CONTENT.value()));
|
.andDo(MockMvcResultPrinter.print()).andExpect(status().is(HttpStatus.NO_CONTENT.value()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Description("Request update of Controller Attributes.")
|
||||||
|
public void triggerControllerAttributesUpdate() throws Exception {
|
||||||
|
// create target with attributes
|
||||||
|
final String knownTargetId = "targetIdNeedsUpdate";
|
||||||
|
final Map<String, String> knownControllerAttrs = new HashMap<>();
|
||||||
|
knownControllerAttrs.put("a", "1");
|
||||||
|
knownControllerAttrs.put("b", "2");
|
||||||
|
testdataFactory.createTarget(knownTargetId);
|
||||||
|
controllerManagement.updateControllerAttributes(knownTargetId, knownControllerAttrs, null);
|
||||||
|
assertThat(targetManagement.isControllerAttributesRequested(knownTargetId)).isFalse();
|
||||||
|
|
||||||
|
verifyAttributeUpdateCanBeRequested(knownTargetId);
|
||||||
|
|
||||||
|
verifyRequestAttributesAttributeIsOptional(knownTargetId);
|
||||||
|
|
||||||
|
verifyResettingRequestAttributesIsNotAllowed(knownTargetId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Step
|
||||||
|
private void verifyAttributeUpdateCanBeRequested(final String knownTargetId) throws Exception {
|
||||||
|
final String body = new JSONObject().put("requestAttributes", true).toString();
|
||||||
|
|
||||||
|
mvc.perform(put(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownTargetId).content(body)
|
||||||
|
.contentType(MediaType.APPLICATION_JSON))
|
||||||
|
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
|
||||||
|
|
||||||
|
assertThat(targetManagement.isControllerAttributesRequested(knownTargetId)).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Step
|
||||||
|
private void verifyRequestAttributesAttributeIsOptional(final String knownTargetId) throws Exception {
|
||||||
|
final String body = new JSONObject().put("description", "verify attribute can be missing").toString();
|
||||||
|
|
||||||
|
mvc.perform(put(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownTargetId).content(body)
|
||||||
|
.contentType(MediaType.APPLICATION_JSON))
|
||||||
|
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Step
|
||||||
|
private void verifyResettingRequestAttributesIsNotAllowed(final String knownTargetId) throws Exception {
|
||||||
|
final String body = new JSONObject().put("requestAttributes", false).toString();
|
||||||
|
|
||||||
|
mvc.perform(put(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownTargetId).content(body)
|
||||||
|
.contentType(MediaType.APPLICATION_JSON))
|
||||||
|
.andDo(MockMvcResultPrinter.print()).andExpect(status().isBadRequest());
|
||||||
|
|
||||||
|
assertThat(targetManagement.isControllerAttributesRequested(knownTargetId)).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void searchTargetsUsingRsqlQuery() throws Exception {
|
public void searchTargetsUsingRsqlQuery() throws Exception {
|
||||||
final int amountTargets = 10;
|
final int amountTargets = 10;
|
||||||
|
|||||||
@@ -219,6 +219,8 @@ public abstract class AbstractApiRestDocumentation extends AbstractRestIntegrati
|
|||||||
.type("enum")
|
.type("enum")
|
||||||
.attributes(key("value").value("['error', 'in_sync', 'pending', 'registered', 'unknown']")),
|
.attributes(key("value").value("['error', 'in_sync', 'pending', 'registered', 'unknown']")),
|
||||||
fieldWithPath(fieldArrayPrefix + "securityToken").description(MgmtApiModelProperties.SECURITY_TOKEN),
|
fieldWithPath(fieldArrayPrefix + "securityToken").description(MgmtApiModelProperties.SECURITY_TOKEN),
|
||||||
|
fieldWithPath(fieldArrayPrefix + "requestAttributes")
|
||||||
|
.description(MgmtApiModelProperties.REQUEST_ATTRIBUTES),
|
||||||
fieldWithPath(fieldArrayPrefix + "installedAt").description(MgmtApiModelProperties.INSTALLED_AT),
|
fieldWithPath(fieldArrayPrefix + "installedAt").description(MgmtApiModelProperties.INSTALLED_AT),
|
||||||
fieldWithPath(fieldArrayPrefix + "lastModifiedAt")
|
fieldWithPath(fieldArrayPrefix + "lastModifiedAt")
|
||||||
.description(ApiModelPropertiesGeneric.LAST_MODIFIED_AT).type("Number"),
|
.description(ApiModelPropertiesGeneric.LAST_MODIFIED_AT).type("Number"),
|
||||||
|
|||||||
@@ -143,6 +143,8 @@ public final class MgmtApiModelProperties {
|
|||||||
|
|
||||||
public static final String SECURITY_TOKEN = "Pre-Shared key that allows targets to authenticate at Direct Device Integration API if enabled in the tenant settings.";
|
public static final String SECURITY_TOKEN = "Pre-Shared key that allows targets to authenticate at Direct Device Integration API if enabled in the tenant settings.";
|
||||||
|
|
||||||
|
public static final String REQUEST_ATTRIBUTES = "Request re-transmission of target attributes.";
|
||||||
|
|
||||||
public static final String META_DATA = "List of metadata.";
|
public static final String META_DATA = "List of metadata.";
|
||||||
|
|
||||||
public static final String META_DATA_KEY = "Metadata property key.";
|
public static final String META_DATA_KEY = "Metadata property key.";
|
||||||
|
|||||||
@@ -90,6 +90,7 @@ public class TargetResourceDocumentationTest extends AbstractApiRestDocumentatio
|
|||||||
.type("enum").attributes(
|
.type("enum").attributes(
|
||||||
key("value").value("['error', 'in_sync', 'pending', 'registered', 'unknown']")),
|
key("value").value("['error', 'in_sync', 'pending', 'registered', 'unknown']")),
|
||||||
fieldWithPath("content[].securityToken").description(MgmtApiModelProperties.SECURITY_TOKEN),
|
fieldWithPath("content[].securityToken").description(MgmtApiModelProperties.SECURITY_TOKEN),
|
||||||
|
fieldWithPath("content[].requestAttributes").description(MgmtApiModelProperties.REQUEST_ATTRIBUTES),
|
||||||
fieldWithPath("content[].installedAt").description(MgmtApiModelProperties.INSTALLED_AT),
|
fieldWithPath("content[].installedAt").description(MgmtApiModelProperties.INSTALLED_AT),
|
||||||
fieldWithPath("content[].lastModifiedAt")
|
fieldWithPath("content[].lastModifiedAt")
|
||||||
.description(ApiModelPropertiesGeneric.LAST_MODIFIED_AT).type("Number"),
|
.description(ApiModelPropertiesGeneric.LAST_MODIFIED_AT).type("Number"),
|
||||||
@@ -141,6 +142,7 @@ public class TargetResourceDocumentationTest extends AbstractApiRestDocumentatio
|
|||||||
.attributes(key("value")
|
.attributes(key("value")
|
||||||
.value("['error', 'in_sync', 'pending', 'registered', 'unknown']")),
|
.value("['error', 'in_sync', 'pending', 'registered', 'unknown']")),
|
||||||
fieldWithPath("[]securityToken").description(MgmtApiModelProperties.SECURITY_TOKEN),
|
fieldWithPath("[]securityToken").description(MgmtApiModelProperties.SECURITY_TOKEN),
|
||||||
|
fieldWithPath("[]requestAttributes").description(MgmtApiModelProperties.REQUEST_ATTRIBUTES),
|
||||||
fieldWithPath("[]_links.self").ignored())));
|
fieldWithPath("[]_links.self").ignored())));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -180,12 +182,13 @@ public class TargetResourceDocumentationTest extends AbstractApiRestDocumentatio
|
|||||||
.andDo(this.document.document(
|
.andDo(this.document.document(
|
||||||
pathParameters(
|
pathParameters(
|
||||||
parameterWithName("controllerId").description(ApiModelPropertiesGeneric.ITEM_ID)),
|
parameterWithName("controllerId").description(ApiModelPropertiesGeneric.ITEM_ID)),
|
||||||
requestFields(requestFieldWithPath("name").description(ApiModelPropertiesGeneric.NAME),
|
requestFields(optionalRequestFieldWithPath("name").description(ApiModelPropertiesGeneric.NAME),
|
||||||
requestFieldWithPath("description").description(ApiModelPropertiesGeneric.DESCRPTION),
|
optionalRequestFieldWithPath("description").description(ApiModelPropertiesGeneric.DESCRPTION),
|
||||||
requestFieldWithPath("controllerId").description(ApiModelPropertiesGeneric.ITEM_ID),
|
optionalRequestFieldWithPath("controllerId").description(ApiModelPropertiesGeneric.ITEM_ID),
|
||||||
requestFieldWithPath("address").description(MgmtApiModelProperties.ADDRESS),
|
optionalRequestFieldWithPath("address").description(MgmtApiModelProperties.ADDRESS),
|
||||||
requestFieldWithPath("securityToken")
|
optionalRequestFieldWithPath("securityToken")
|
||||||
.description(MgmtApiModelProperties.SECURITY_TOKEN)),
|
.description(MgmtApiModelProperties.SECURITY_TOKEN),
|
||||||
|
optionalRequestFieldWithPath("requestAttributes").description(MgmtApiModelProperties.REQUEST_ATTRIBUTES)),
|
||||||
getResponseFieldTarget(false)));
|
getResponseFieldTarget(false)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -570,6 +573,7 @@ public class TargetResourceDocumentationTest extends AbstractApiRestDocumentatio
|
|||||||
target.put("name", name);
|
target.put("name", name);
|
||||||
target.put("address", "https://192.168.0.1");
|
target.put("address", "https://192.168.0.1");
|
||||||
target.put("securityToken", "2345678DGGDGFTDzztgf");
|
target.put("securityToken", "2345678DGGDGFTDzztgf");
|
||||||
|
target.put("requestAttributes", true);
|
||||||
return this.objectMapper.writeValueAsString(target);
|
return this.objectMapper.writeValueAsString(target);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user