Feature mgmt simulator semi aware (#377)
* Mgmt simulator is Semic automatic rollout aware Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>
This commit is contained in:
@@ -8,9 +8,12 @@
|
|||||||
*/
|
*/
|
||||||
package org.eclipse.hawkbit.mgmt.client.resource.builder;
|
package org.eclipse.hawkbit.mgmt.client.resource.builder;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import org.eclipse.hawkbit.mgmt.json.model.rollout.MgmtRolloutCondition;
|
import org.eclipse.hawkbit.mgmt.json.model.rollout.MgmtRolloutCondition;
|
||||||
import org.eclipse.hawkbit.mgmt.json.model.rollout.MgmtRolloutCondition.Condition;
|
import org.eclipse.hawkbit.mgmt.json.model.rollout.MgmtRolloutCondition.Condition;
|
||||||
import org.eclipse.hawkbit.mgmt.json.model.rollout.MgmtRolloutRestRequestBody;
|
import org.eclipse.hawkbit.mgmt.json.model.rollout.MgmtRolloutRestRequestBody;
|
||||||
|
import org.eclipse.hawkbit.mgmt.json.model.rolloutgroup.MgmtRolloutGroup;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@@ -28,6 +31,7 @@ public class RolloutBuilder {
|
|||||||
private String successThreshold;
|
private String successThreshold;
|
||||||
private String errorThreshold;
|
private String errorThreshold;
|
||||||
private String description;
|
private String description;
|
||||||
|
private List<MgmtRolloutGroup> semiAutomaticGroups;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param name
|
* @param name
|
||||||
@@ -39,6 +43,16 @@ public class RolloutBuilder {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param semiAutomaticGroups
|
||||||
|
* as alternative to full automatic, i.e. {@link #groupSize(int)}
|
||||||
|
* @return the builder itself
|
||||||
|
*/
|
||||||
|
public RolloutBuilder semiAutomaticGroups(final List<MgmtRolloutGroup> semiAutomaticGroups) {
|
||||||
|
this.semiAutomaticGroups = semiAutomaticGroups;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param groupSize
|
* @param groupSize
|
||||||
* the amount of groups the rollout should be split into
|
* the amount of groups the rollout should be split into
|
||||||
@@ -121,6 +135,7 @@ public class RolloutBuilder {
|
|||||||
body.setDescription(description);
|
body.setDescription(description);
|
||||||
body.setSuccessCondition(new MgmtRolloutCondition(Condition.THRESHOLD, successThreshold));
|
body.setSuccessCondition(new MgmtRolloutCondition(Condition.THRESHOLD, successThreshold));
|
||||||
body.setErrorCondition(new MgmtRolloutCondition(Condition.THRESHOLD, errorThreshold));
|
body.setErrorCondition(new MgmtRolloutCondition(Condition.THRESHOLD, errorThreshold));
|
||||||
|
body.setGroups(semiAutomaticGroups);
|
||||||
return body;
|
return body;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -110,7 +110,7 @@ public class TargetBuilder {
|
|||||||
public List<MgmtTargetRequestBody> buildAsList(final int offset, final int count) {
|
public List<MgmtTargetRequestBody> buildAsList(final int offset, final int count) {
|
||||||
final List<MgmtTargetRequestBody> bodyList = Lists.newArrayList();
|
final List<MgmtTargetRequestBody> bodyList = Lists.newArrayList();
|
||||||
for (int index = offset; index < count + offset; index++) {
|
for (int index = offset; index < count + offset; index++) {
|
||||||
bodyList.add(doBuild(String.valueOf(index)));
|
bodyList.add(doBuild(String.format("%06d", index)));
|
||||||
}
|
}
|
||||||
return bodyList;
|
return bodyList;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
package org.eclipse.hawkbit.mgmt.client;
|
package org.eclipse.hawkbit.mgmt.client;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
@@ -55,8 +56,10 @@ public class ClientConfigurationProperties {
|
|||||||
private int artifactsPerSM = 1;
|
private int artifactsPerSM = 1;
|
||||||
private String targetAddress = "amqp:/simulator.replyTo";
|
private String targetAddress = "amqp:/simulator.replyTo";
|
||||||
private boolean runRollouts = true;
|
private boolean runRollouts = true;
|
||||||
|
private boolean runSemiAutomaticRollouts = true;
|
||||||
private short rolloutSuccessThreshold = 80;
|
private short rolloutSuccessThreshold = 80;
|
||||||
private int rolloutDeploymentGroups = 4;
|
private int rolloutDeploymentGroups = 4;
|
||||||
|
private List<String> deviceGroups = Arrays.asList("EU", "AM", "APAC");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Targets tags per page.
|
* Targets tags per page.
|
||||||
@@ -74,6 +77,22 @@ public class ClientConfigurationProperties {
|
|||||||
*/
|
*/
|
||||||
private String artifactSize = "1MB";
|
private String artifactSize = "1MB";
|
||||||
|
|
||||||
|
public boolean isRunSemiAutomaticRollouts() {
|
||||||
|
return runSemiAutomaticRollouts;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRunSemiAutomaticRollouts(final boolean runSemiAutomaticRollouts) {
|
||||||
|
this.runSemiAutomaticRollouts = runSemiAutomaticRollouts;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getDeviceGroups() {
|
||||||
|
return deviceGroups;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDeviceGroups(final List<String> deviceGroups) {
|
||||||
|
this.deviceGroups = deviceGroups;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isCleanRepository() {
|
public boolean isCleanRepository() {
|
||||||
return cleanRepository;
|
return cleanRepository;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.eclipse.hawkbit.mgmt.client.scenarios;
|
package org.eclipse.hawkbit.mgmt.client.scenarios;
|
||||||
|
|
||||||
|
import java.security.SecureRandom;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
@@ -32,6 +33,7 @@ import org.eclipse.hawkbit.mgmt.client.scenarios.upload.ArtifactFile;
|
|||||||
import org.eclipse.hawkbit.mgmt.json.model.PagedList;
|
import org.eclipse.hawkbit.mgmt.json.model.PagedList;
|
||||||
import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtDistributionSet;
|
import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtDistributionSet;
|
||||||
import org.eclipse.hawkbit.mgmt.json.model.rollout.MgmtRolloutResponseBody;
|
import org.eclipse.hawkbit.mgmt.json.model.rollout.MgmtRolloutResponseBody;
|
||||||
|
import org.eclipse.hawkbit.mgmt.json.model.rolloutgroup.MgmtRolloutGroup;
|
||||||
import org.eclipse.hawkbit.mgmt.json.model.softwaremodule.MgmtSoftwareModule;
|
import org.eclipse.hawkbit.mgmt.json.model.softwaremodule.MgmtSoftwareModule;
|
||||||
import org.eclipse.hawkbit.mgmt.json.model.tag.MgmtAssignedDistributionSetRequestBody;
|
import org.eclipse.hawkbit.mgmt.json.model.tag.MgmtAssignedDistributionSetRequestBody;
|
||||||
import org.eclipse.hawkbit.mgmt.json.model.tag.MgmtAssignedTargetRequestBody;
|
import org.eclipse.hawkbit.mgmt.json.model.tag.MgmtAssignedTargetRequestBody;
|
||||||
@@ -40,6 +42,8 @@ import org.eclipse.hawkbit.mgmt.json.model.target.MgmtTarget;
|
|||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* A configurable scenario which runs the configured scenarios.
|
* A configurable scenario which runs the configured scenarios.
|
||||||
@@ -100,12 +104,30 @@ public class ConfigurableScenario {
|
|||||||
cleanRepository();
|
cleanRepository();
|
||||||
}
|
}
|
||||||
|
|
||||||
createTargets(scenario);
|
final List<Long> deviceGroupTags = createDeviceGroupTags(scenario.getDeviceGroups());
|
||||||
|
createTargets(scenario, deviceGroupTags);
|
||||||
createDistributionSets(scenario);
|
createDistributionSets(scenario);
|
||||||
|
|
||||||
if (scenario.isRunRollouts()) {
|
if (scenario.isRunRollouts()) {
|
||||||
runRollouts(scenario);
|
runRollouts(scenario);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (scenario.isRunRollouts()) {
|
||||||
|
runRollouts(scenario);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (scenario.isRunSemiAutomaticRollouts() && !scenario.getDeviceGroups().isEmpty()) {
|
||||||
|
runSemiAutomaticRollouts(scenario);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Long> createDeviceGroupTags(final List<String> deviceGroups) {
|
||||||
|
return deviceGroups.stream()
|
||||||
|
.map(group -> targetTagResource
|
||||||
|
.createTargetTags(new TagBuilder().name(group).description("Group " + group).build()).getBody()
|
||||||
|
.get(0).getTagId())
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void cleanRepository() {
|
private void cleanRepository() {
|
||||||
@@ -174,7 +196,50 @@ public class ConfigurableScenario {
|
|||||||
private void runRollouts(final Scenario scenario) {
|
private void runRollouts(final Scenario scenario) {
|
||||||
distributionSetResource.getDistributionSets(0, scenario.getDistributionSets(), null, null).getBody()
|
distributionSetResource.getDistributionSets(0, scenario.getDistributionSets(), null, null).getBody()
|
||||||
.getContent().forEach(set -> runRollout(set, scenario));
|
.getContent().forEach(set -> runRollout(set, scenario));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void runSemiAutomaticRollouts(final Scenario scenario) {
|
||||||
|
distributionSetResource.getDistributionSets(0, scenario.getDistributionSets(), null, null).getBody()
|
||||||
|
.getContent().forEach(set -> runSemiAutomaticRollout(set, scenario));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void runSemiAutomaticRollout(final MgmtDistributionSet set, final Scenario scenario) {
|
||||||
|
LOGGER.info("Run semi automatic rollout for set {}", set.getDsId());
|
||||||
|
// create a Rollout
|
||||||
|
final MgmtRolloutResponseBody rolloutResponseBody = rolloutResource.create(new RolloutBuilder()
|
||||||
|
.name("Rollout" + set.getName() + set.getVersion()).semiAutomaticGroups(createRolloutGroups(scenario))
|
||||||
|
.targetFilterQuery("name==*").distributionSetId(set.getDsId())
|
||||||
|
.successThreshold(String.valueOf(scenario.getRolloutSuccessThreshold())).errorThreshold("5").build())
|
||||||
|
.getBody();
|
||||||
|
|
||||||
|
waitUntilRolloutIsReady(rolloutResponseBody.getRolloutId());
|
||||||
|
|
||||||
|
// start the created Rollout
|
||||||
|
rolloutResource.start(rolloutResponseBody.getRolloutId());
|
||||||
|
|
||||||
|
waitUntilRolloutIsComplete(scenario);
|
||||||
|
LOGGER.info("Run rollout for set {} -> Done", set.getDsId());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<MgmtRolloutGroup> createRolloutGroups(final Scenario scenario) {
|
||||||
|
final List<MgmtRolloutGroup> result = Lists.newArrayListWithCapacity(scenario.getDeviceGroups().size() * 2);
|
||||||
|
|
||||||
|
scenario.getDeviceGroups().forEach(groupname -> {
|
||||||
|
result.add(createGroup(1, groupname, 10F));
|
||||||
|
result.add(createGroup(2, groupname, 50F));
|
||||||
|
result.add(createGroup(3, groupname, 100F));
|
||||||
|
});
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static MgmtRolloutGroup createGroup(final int number, final String groupname, final Float percent) {
|
||||||
|
final MgmtRolloutGroup one = new MgmtRolloutGroup();
|
||||||
|
one.setName(groupname + "-" + number);
|
||||||
|
one.setDescription("Group of " + groupname);
|
||||||
|
one.setTargetFilterQuery("tag==" + groupname);
|
||||||
|
one.setTargetPercentage(percent);
|
||||||
|
return one;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void runRollout(final MgmtDistributionSet set, final Scenario scenario) {
|
private void runRollout(final MgmtDistributionSet set, final Scenario scenario) {
|
||||||
@@ -186,20 +251,16 @@ public class ConfigurableScenario {
|
|||||||
.successThreshold(String.valueOf(scenario.getRolloutSuccessThreshold())).errorThreshold("5").build())
|
.successThreshold(String.valueOf(scenario.getRolloutSuccessThreshold())).errorThreshold("5").build())
|
||||||
.getBody();
|
.getBody();
|
||||||
|
|
||||||
do {
|
waitUntilRolloutIsReady(rolloutResponseBody.getRolloutId());
|
||||||
try {
|
|
||||||
TimeUnit.SECONDS.sleep(5);
|
|
||||||
} catch (final InterruptedException e) {
|
|
||||||
LOGGER.warn("Interrupted!");
|
|
||||||
Thread.currentThread().interrupt();
|
|
||||||
}
|
|
||||||
} while (!"READY".equalsIgnoreCase(
|
|
||||||
rolloutResource.getRollout(rolloutResponseBody.getRolloutId()).getBody().getStatus()));
|
|
||||||
|
|
||||||
// start the created Rollout
|
// start the created Rollout
|
||||||
rolloutResource.start(rolloutResponseBody.getRolloutId());
|
rolloutResource.start(rolloutResponseBody.getRolloutId());
|
||||||
|
|
||||||
// wait until rollout is complete
|
waitUntilRolloutIsComplete(scenario);
|
||||||
|
LOGGER.info("Run rollout for set {} -> Done", set.getDsId());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void waitUntilRolloutIsComplete(final Scenario scenario) {
|
||||||
do {
|
do {
|
||||||
try {
|
try {
|
||||||
TimeUnit.SECONDS.sleep(35);
|
TimeUnit.SECONDS.sleep(35);
|
||||||
@@ -209,7 +270,17 @@ public class ConfigurableScenario {
|
|||||||
}
|
}
|
||||||
} while (targetResource.getTargets(0, 1, null, "updateStatus==IN_SYNC").getBody().getTotal() < scenario
|
} while (targetResource.getTargets(0, 1, null, "updateStatus==IN_SYNC").getBody().getTotal() < scenario
|
||||||
.getTargets());
|
.getTargets());
|
||||||
LOGGER.info("Run rollout for set {} -> Done", set.getDsId());
|
}
|
||||||
|
|
||||||
|
private void waitUntilRolloutIsReady(final Long id) {
|
||||||
|
do {
|
||||||
|
try {
|
||||||
|
TimeUnit.SECONDS.sleep(5);
|
||||||
|
} catch (final InterruptedException e) {
|
||||||
|
LOGGER.warn("Interrupted!");
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
}
|
||||||
|
} while (!"READY".equalsIgnoreCase(rolloutResource.getRollout(id).getBody().getStatus()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createDistributionSets(final Scenario scenario) {
|
private void createDistributionSets(final Scenario scenario) {
|
||||||
@@ -275,16 +346,18 @@ public class ConfigurableScenario {
|
|||||||
return modules;
|
return modules;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createTargets(final Scenario scenario) {
|
private void createTargets(final Scenario scenario, final List<Long> deviceGroupTags) {
|
||||||
LOGGER.info("Creating {} targets", scenario.getTargets());
|
LOGGER.info("Creating {} targets", scenario.getTargets());
|
||||||
IntStream.range(0, scenario.getTargets() / PAGE_SIZE).parallel().forEach(i -> createTargetPage(scenario, i));
|
IntStream.range(0, scenario.getTargets() / PAGE_SIZE).parallel()
|
||||||
|
.forEach(i -> createTargetPage(scenario, i, deviceGroupTags));
|
||||||
LOGGER.info("Creating {} targets -> Done", scenario.getTargets());
|
LOGGER.info("Creating {} targets -> Done", scenario.getTargets());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createTargetPage(final Scenario scenario, final int page) {
|
private void createTargetPage(final Scenario scenario, final int page, final List<Long> deviceGroupTags) {
|
||||||
final List<MgmtTarget> targets = createTargets(scenario, page);
|
final List<MgmtTarget> targets = createTargets(scenario, page);
|
||||||
|
|
||||||
tagTargets(scenario, page, targets);
|
tagTargets(scenario, page, targets, deviceGroupTags);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<MgmtTarget> createTargets(final Scenario scenario, final int page) {
|
private List<MgmtTarget> createTargets(final Scenario scenario, final int page) {
|
||||||
@@ -297,7 +370,8 @@ public class ConfigurableScenario {
|
|||||||
.getBody();
|
.getBody();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void tagTargets(final Scenario scenario, final int page, final List<MgmtTarget> targets) {
|
private void tagTargets(final Scenario scenario, final int page, final List<MgmtTarget> targets,
|
||||||
|
final List<Long> deviceGroupTags) {
|
||||||
if (scenario.getTargetTags() > 0) {
|
if (scenario.getTargetTags() > 0) {
|
||||||
targetTagResource
|
targetTagResource
|
||||||
.createTargetTags(new TagBuilder().name("Page " + page)
|
.createTargetTags(new TagBuilder().name("Page " + page)
|
||||||
@@ -307,6 +381,15 @@ public class ConfigurableScenario {
|
|||||||
target -> new MgmtAssignedTargetRequestBody().setControllerId(target.getControllerId()))
|
target -> new MgmtAssignedTargetRequestBody().setControllerId(target.getControllerId()))
|
||||||
.collect(Collectors.toList())));
|
.collect(Collectors.toList())));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!deviceGroupTags.isEmpty()) {
|
||||||
|
final Long tagid = deviceGroupTags.get(new SecureRandom().nextInt(deviceGroupTags.size()));
|
||||||
|
|
||||||
|
targetTagResource.assignTargets(tagid,
|
||||||
|
targets.stream().map(
|
||||||
|
target -> new MgmtAssignedTargetRequestBody().setControllerId(target.getControllerId()))
|
||||||
|
.collect(Collectors.toList()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int calculateOffset(final int page) {
|
private static int calculateOffset(final int page) {
|
||||||
|
|||||||
Reference in New Issue
Block a user