From d15084974a952190430a1bec0773c6fed71099c8 Mon Sep 17 00:00:00 2001 From: Kai Zimmermann Date: Tue, 6 Dec 2016 19:33:53 +0100 Subject: [PATCH] Feature mgmt simulator semi aware (#377) * Mgmt simulator is Semic automatic rollout aware Signed-off-by: kaizimmerm --- .../resource/builder/RolloutBuilder.java | 15 +++ .../resource/builder/TargetBuilder.java | 2 +- .../client/ClientConfigurationProperties.java | 19 +++ .../scenarios/ConfigurableScenario.java | 117 +++++++++++++++--- 4 files changed, 135 insertions(+), 18 deletions(-) diff --git a/examples/hawkbit-example-mgmt-feign-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/RolloutBuilder.java b/examples/hawkbit-example-mgmt-feign-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/RolloutBuilder.java index 02ebe2de3..d2d291128 100644 --- a/examples/hawkbit-example-mgmt-feign-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/RolloutBuilder.java +++ b/examples/hawkbit-example-mgmt-feign-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/RolloutBuilder.java @@ -8,9 +8,12 @@ */ 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.Condition; 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 errorThreshold; private String description; + private List semiAutomaticGroups; /** * @param name @@ -39,6 +43,16 @@ public class RolloutBuilder { return this; } + /** + * @param semiAutomaticGroups + * as alternative to full automatic, i.e. {@link #groupSize(int)} + * @return the builder itself + */ + public RolloutBuilder semiAutomaticGroups(final List semiAutomaticGroups) { + this.semiAutomaticGroups = semiAutomaticGroups; + return this; + } + /** * @param groupSize * the amount of groups the rollout should be split into @@ -121,6 +135,7 @@ public class RolloutBuilder { body.setDescription(description); body.setSuccessCondition(new MgmtRolloutCondition(Condition.THRESHOLD, successThreshold)); body.setErrorCondition(new MgmtRolloutCondition(Condition.THRESHOLD, errorThreshold)); + body.setGroups(semiAutomaticGroups); return body; } diff --git a/examples/hawkbit-example-mgmt-feign-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/TargetBuilder.java b/examples/hawkbit-example-mgmt-feign-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/TargetBuilder.java index 5fbcd0313..0b33d6458 100644 --- a/examples/hawkbit-example-mgmt-feign-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/TargetBuilder.java +++ b/examples/hawkbit-example-mgmt-feign-client/src/main/java/org/eclipse/hawkbit/mgmt/client/resource/builder/TargetBuilder.java @@ -110,7 +110,7 @@ public class TargetBuilder { public List buildAsList(final int offset, final int count) { final List bodyList = Lists.newArrayList(); for (int index = offset; index < count + offset; index++) { - bodyList.add(doBuild(String.valueOf(index))); + bodyList.add(doBuild(String.format("%06d", index))); } return bodyList; } diff --git a/examples/hawkbit-example-mgmt-simulator/src/main/java/org/eclipse/hawkbit/mgmt/client/ClientConfigurationProperties.java b/examples/hawkbit-example-mgmt-simulator/src/main/java/org/eclipse/hawkbit/mgmt/client/ClientConfigurationProperties.java index 9d33e1273..6fc70eeaf 100644 --- a/examples/hawkbit-example-mgmt-simulator/src/main/java/org/eclipse/hawkbit/mgmt/client/ClientConfigurationProperties.java +++ b/examples/hawkbit-example-mgmt-simulator/src/main/java/org/eclipse/hawkbit/mgmt/client/ClientConfigurationProperties.java @@ -9,6 +9,7 @@ package org.eclipse.hawkbit.mgmt.client; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import org.springframework.boot.context.properties.ConfigurationProperties; @@ -55,8 +56,10 @@ public class ClientConfigurationProperties { private int artifactsPerSM = 1; private String targetAddress = "amqp:/simulator.replyTo"; private boolean runRollouts = true; + private boolean runSemiAutomaticRollouts = true; private short rolloutSuccessThreshold = 80; private int rolloutDeploymentGroups = 4; + private List deviceGroups = Arrays.asList("EU", "AM", "APAC"); /** * Targets tags per page. @@ -74,6 +77,22 @@ public class ClientConfigurationProperties { */ private String artifactSize = "1MB"; + public boolean isRunSemiAutomaticRollouts() { + return runSemiAutomaticRollouts; + } + + public void setRunSemiAutomaticRollouts(final boolean runSemiAutomaticRollouts) { + this.runSemiAutomaticRollouts = runSemiAutomaticRollouts; + } + + public List getDeviceGroups() { + return deviceGroups; + } + + public void setDeviceGroups(final List deviceGroups) { + this.deviceGroups = deviceGroups; + } + public boolean isCleanRepository() { return cleanRepository; } diff --git a/examples/hawkbit-example-mgmt-simulator/src/main/java/org/eclipse/hawkbit/mgmt/client/scenarios/ConfigurableScenario.java b/examples/hawkbit-example-mgmt-simulator/src/main/java/org/eclipse/hawkbit/mgmt/client/scenarios/ConfigurableScenario.java index a343b6576..c71a002ba 100644 --- a/examples/hawkbit-example-mgmt-simulator/src/main/java/org/eclipse/hawkbit/mgmt/client/scenarios/ConfigurableScenario.java +++ b/examples/hawkbit-example-mgmt-simulator/src/main/java/org/eclipse/hawkbit/mgmt/client/scenarios/ConfigurableScenario.java @@ -8,6 +8,7 @@ */ package org.eclipse.hawkbit.mgmt.client.scenarios; +import java.security.SecureRandom; import java.util.List; import java.util.Random; 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.distributionset.MgmtDistributionSet; 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.tag.MgmtAssignedDistributionSetRequestBody; 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.LoggerFactory; +import com.google.common.collect.Lists; + /** * * A configurable scenario which runs the configured scenarios. @@ -100,12 +104,30 @@ public class ConfigurableScenario { cleanRepository(); } - createTargets(scenario); + final List deviceGroupTags = createDeviceGroupTags(scenario.getDeviceGroups()); + createTargets(scenario, deviceGroupTags); createDistributionSets(scenario); if (scenario.isRunRollouts()) { runRollouts(scenario); } + + if (scenario.isRunRollouts()) { + runRollouts(scenario); + } + + if (scenario.isRunSemiAutomaticRollouts() && !scenario.getDeviceGroups().isEmpty()) { + runSemiAutomaticRollouts(scenario); + } + } + + private List createDeviceGroupTags(final List 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() { @@ -174,7 +196,50 @@ public class ConfigurableScenario { private void runRollouts(final Scenario scenario) { distributionSetResource.getDistributionSets(0, scenario.getDistributionSets(), null, null).getBody() .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 createRolloutGroups(final Scenario scenario) { + final List 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) { @@ -186,20 +251,16 @@ public class ConfigurableScenario { .successThreshold(String.valueOf(scenario.getRolloutSuccessThreshold())).errorThreshold("5").build()) .getBody(); - do { - try { - TimeUnit.SECONDS.sleep(5); - } catch (final InterruptedException e) { - LOGGER.warn("Interrupted!"); - Thread.currentThread().interrupt(); - } - } while (!"READY".equalsIgnoreCase( - rolloutResource.getRollout(rolloutResponseBody.getRolloutId()).getBody().getStatus())); + waitUntilRolloutIsReady(rolloutResponseBody.getRolloutId()); // start the created Rollout 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 { try { TimeUnit.SECONDS.sleep(35); @@ -209,7 +270,17 @@ public class ConfigurableScenario { } } while (targetResource.getTargets(0, 1, null, "updateStatus==IN_SYNC").getBody().getTotal() < scenario .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) { @@ -275,16 +346,18 @@ public class ConfigurableScenario { return modules; } - private void createTargets(final Scenario scenario) { + private void createTargets(final Scenario scenario, final List deviceGroupTags) { 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()); } - private void createTargetPage(final Scenario scenario, final int page) { + private void createTargetPage(final Scenario scenario, final int page, final List deviceGroupTags) { final List targets = createTargets(scenario, page); - tagTargets(scenario, page, targets); + tagTargets(scenario, page, targets, deviceGroupTags); + } private List createTargets(final Scenario scenario, final int page) { @@ -297,7 +370,8 @@ public class ConfigurableScenario { .getBody(); } - private void tagTargets(final Scenario scenario, final int page, final List targets) { + private void tagTargets(final Scenario scenario, final int page, final List targets, + final List deviceGroupTags) { if (scenario.getTargetTags() > 0) { targetTagResource .createTargetTags(new TagBuilder().name("Page " + page) @@ -307,6 +381,15 @@ public class ConfigurableScenario { target -> new MgmtAssignedTargetRequestBody().setControllerId(target.getControllerId())) .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) {