@Override public DeploymentGroupStatus call() throws Exception { final DeploymentGroupStatusResponse response = getOrNull( client.deploymentGroupStatus(name)); if (response != null) { final DeploymentGroupStatus status = response.getDeploymentGroupStatus(); final DeploymentGroupStatus.State actual = status.getState(); // The deployment group failed when we did not expect it to. if (actual == FAILED && actual != expected) { throw new AssertionError("Deployment group " + name + " failed unexpectedly: " + status.getError()); } // The deployment group reached our desired status. if (actual == expected) { return status; } } return null; } });
public Builder toBuilder() { return newBuilder() .setState(state) .setError(error); }
public DeploymentGroupStatus build() { return new DeploymentGroupStatus(this); } }
if (deploymentGroupStatus == null) { status = DeploymentGroupStatusResponse.Status.IDLE; } else if (deploymentGroupStatus.getState() == DeploymentGroupStatus.State.FAILED) { status = DeploymentGroupStatusResponse.Status.FAILED; } else if (deploymentGroupStatus.getSuccessfulIterations() > 0) { status = DeploymentGroupStatusResponse.Status.ACTIVE; } else { final String error = deploymentGroupStatus == null ? "" : deploymentGroupStatus.getError(); return Response.ok(new DeploymentGroupStatusResponse( deploymentGroup, status, error, result, deploymentGroupStatus)).build();
final DeploymentGroupStatus.State state = status.getState(); if (state.equals(START_ROLLING_UPDATE) || state.equals(PLANNING_ROLLOUT)) { final List<RolloutTask> oldPlan = status.getRolloutTasks(); final List<RolloutTask> newPlan = rolloutPlanner.plan(hostsAndStatuses); final DeploymentGroupStatus.Builder newStatus = status.toBuilder() .setState(ROLLING_OUT) .setRolloutTasks(newPlan) } else if (status.getState().equals(ROLLING_OUT)) { } else if (status.getState().equals(DONE)) { if (status.getSuccessfulIterations() == 1) { opsEvents.addOperation(set(statusPath, status.toBuilder() .setState(PLANNING_ROLLOUT) .build())); final List<ZooKeeperOperation> zkOperations = opsEvents.getOperations(); client.transaction(Lists.asList( check(statusPath, status.getVersion()), zkOperations.toArray(new ZooKeeperOperation[zkOperations.size()]) ));
/** * Determines whether we should allow deployment group hosts to be updated. * * <p>We don't want deployment groups that are ROLLING_OUT to change hosts in order to avoid the * following race: * * <p>- Manual rolling update A of a bad, broken job is triggered. * - The hosts change before rolling update A completes, triggering rolling update B. * - Rolling update B fails, because it inherited the bad, broken job from update A. * - The hosts change again, and we trigger unwanted rolling update C because the the previous * rolling update (B) had reason=HOSTS_CHANGED. * * <p>It's safe to simply abort the hosts changed operation as updateOnHostsChange will be called * again by a reactor. * * @param status The status of the deployment group attempting to change hosts. * * @return True if it's safe to update the hosts. */ private boolean allowHostChange(final DeploymentGroupStatus status) { if (status == null) { // We're in an unknown state. Go hog wild. return true; } return status.getState() != ROLLING_OUT; }
private RolloutOpsEvents getRolloutOperations(final DeploymentGroup deploymentGroup, final DeploymentGroupStatus status) { final int taskIndex = status.getTaskIndex(); final RolloutTask currentTask = Iterables.get(status.getRolloutTasks(), taskIndex, null); final RollingUpdateTaskResult result = getRollingUpdateTaskResult(currentTask, deploymentGroup); .setDeploymentGroupStatus(status.toBuilder().setState(FAILED).build()) .build()); final String errMsg = isNullOrEmpty(result.host) ? result.error.getMessage() : result.host + ": " + result.error.getMessage(); opsEvents.addOperation(set(statusPath, status.toBuilder() .setState(FAILED) .setError(errMsg) .setDeploymentGroupStatus(status.toBuilder().setState(ROLLING_OUT).build()); if (taskIndex + 1 >= status.getRolloutTasks().size()) { opsEvents.addOperation(set(statusPath, status.toBuilder() .setSuccessfulIterations(status.getSuccessfulIterations() + 1) .setState(DONE) .build())); } else { opsEvents.addOperation(set(statusPath, status.toBuilder() .setTaskIndex(taskIndex + 1) .build()));
@Override public boolean equals(final Object obj) { if (this == obj) { return true; } if (obj == null || getClass() != obj.getClass()) { return false; } final DeploymentGroupStatusResponse response = (DeploymentGroupStatusResponse) obj; if (deploymentGroup != null ? !deploymentGroup.equals(response.deploymentGroup) : response.deploymentGroup != null) { return false; } if (deploymentGroupStatus != null ? !deploymentGroupStatus .equals(response.deploymentGroupStatus) : response.deploymentGroupStatus != null) { return false; } if (error != null ? !error.equals(response.error) : response.error != null) { return false; } if (hostStatuses != null ? !hostStatuses.equals(response.hostStatuses) : response.hostStatuses != null) { return false; } if (status != response.status) { return false; } return true; }
/** * Determines whether we should trigger a rolling update when deployment group hosts change. * * <p>We want to avoid triggering an automatic rolling update if the most recent rolling update * was triggered manually, and failed. * * @param group The deployment group that is changing hosts. * @param status The status of the aforementioned deployment group. * * @return True if we should perform a rolling update. */ private boolean updateOnHostChange(final DeploymentGroup group, final DeploymentGroupStatus status) { if (status == null) { // We're in an unknown state. Go hog wild. return true; } if (group.getRollingUpdateReason() == null) { // The last rolling update didn't fail, so there's no reason to expect this one will. return status.getState() != FAILED; } if (group.getRollingUpdateReason() == HOSTS_CHANGED && status.getState() == FAILED) { // The last rolling update failed, but it was triggered by hosts changing. Try again. return true; } // The last rolling update didn't fail, so there's no reason to expect this one will. return status.getState() != FAILED; }
if (deploymentGroupStatus == null) { status = DeploymentGroupStatusResponse.Status.IDLE; } else if (deploymentGroupStatus.getState() == DeploymentGroupStatus.State.FAILED) { status = DeploymentGroupStatusResponse.Status.FAILED; } else if (deploymentGroupStatus.getState() == DeploymentGroupStatus.State.ROLLING_OUT) { status = DeploymentGroupStatusResponse.Status.ROLLING_OUT; } else { final String error = deploymentGroupStatus == null ? "" : deploymentGroupStatus.getError(); return Response.ok(new DeploymentGroupStatusResponse( deploymentGroup, status, error, result, deploymentGroupStatus)).build();
final DeploymentGroupStatus status = DeploymentGroupStatus.newBuilder() .setState(FAILED) .setError(errMsg)
public RollingUpdateOp nextTask(final List<ZooKeeperOperation> operations) { final List<ZooKeeperOperation> ops = Lists.newArrayList(operations); final List<Map<String, Object>> events = Lists.newArrayList(); final RolloutTask task = tasks.getRolloutTasks().get(tasks.getTaskIndex()); // Update the task index, delete tasks if done if (tasks.getTaskIndex() + 1 == tasks.getRolloutTasks().size()) { final DeploymentGroupStatus status = DeploymentGroupStatus.newBuilder() .setState(DONE) .build(); // We are done -> delete tasks & update status ops.add(delete(Paths.statusDeploymentGroupTasks(deploymentGroup.getName()))); ops.add(set(Paths.statusDeploymentGroup(deploymentGroup.getName()), status)); // Emit an event signalling that we're DONE! events.add(eventFactory.rollingUpdateDone(deploymentGroup)); } else { ops.add( set(Paths.statusDeploymentGroupTasks(deploymentGroup.getName()), tasks.toBuilder() .setTaskIndex(tasks.getTaskIndex() + 1) .build())); // Only emit an event if the task resulted in taking in action. If there are no ZK operations // the task was effectively a no-op. if (!operations.isEmpty()) { events.add(eventFactory.rollingUpdateTaskSucceeded(deploymentGroup, task)); } } return new RollingUpdateOp(ImmutableList.copyOf(ops), ImmutableList.copyOf(events)); }
status = DeploymentGroupStatus.newBuilder() .setState(DONE) .build(); .setDeploymentGroup(deploymentGroup) .build(); status = DeploymentGroupStatus.newBuilder() .setState(ROLLING_OUT) .build();
final DeploymentGroupStatus status = DeploymentGroupStatus.newBuilder() .setState(FAILED) .setError("Stopped by user")
@Override public void stopDeploymentGroup(final String deploymentGroupName) throws DeploymentGroupDoesNotExistException { checkNotNull(deploymentGroupName, "name"); log.info("stop deployment-group: name={}", deploymentGroupName); final ZooKeeperClient client = provider.get("stopDeploymentGroup"); final DeploymentGroup deploymentGroup = getDeploymentGroup(deploymentGroupName); final String statusPath = Paths.statusDeploymentGroup(deploymentGroupName); final DeploymentGroupStatus status = DeploymentGroupStatus.newBuilder() .setDeploymentGroup(deploymentGroup) .setState(FAILED) .setError("Stopped by user") .build(); try { client.ensurePath(statusPath); client.transaction(set(statusPath, status)); } catch (final NoNodeException e) { throw new DeploymentGroupDoesNotExistException(deploymentGroupName); } catch (final KeeperException e) { throw new HeliosRuntimeException( "stop deployment-group " + deploymentGroupName + " failed", e); } }
final DeploymentGroupStatus initialStatus = DeploymentGroupStatus.newBuilder() .setDeploymentGroup(deploymentGroup) .setState(START_ROLLING_UPDATE)