Search in sources :

Example 1 with RolloutOptions

use of com.spotify.helios.common.descriptors.RolloutOptions in project helios by spotify.

the class RollingUpdateCommand method runWithJobId.

@Override
protected int runWithJobId(final Namespace options, final HeliosClient client, final PrintStream out, final boolean json, final JobId jobId, final BufferedReader stdin) throws ExecutionException, InterruptedException, IOException {
    final String name = options.getString(nameArg.getDest());
    final long timeout = options.getLong(timeoutArg.getDest());
    final int parallelism = options.getInt(parallelismArg.getDest());
    final boolean async = options.getBoolean(asyncArg.getDest());
    final long rolloutTimeout = options.getLong(rolloutTimeoutArg.getDest());
    final boolean migrate = options.getBoolean(migrateArg.getDest());
    final boolean overlap = options.getBoolean(overlapArg.getDest());
    final String token = options.getString(tokenArg.getDest());
    checkArgument(timeout > 0, "Timeout must be greater than 0");
    checkArgument(parallelism > 0, "Parallelism must be greater than 0");
    checkArgument(rolloutTimeout > 0, "Rollout timeout must be greater than 0");
    final long startTime = timeSupplier.get();
    final RolloutOptions rolloutOptions = RolloutOptions.newBuilder().setTimeout(timeout).setParallelism(parallelism).setMigrate(migrate).setOverlap(overlap).setToken(token).build();
    final RollingUpdateResponse response = client.rollingUpdate(name, jobId, rolloutOptions).get();
    if (response.getStatus() != RollingUpdateResponse.Status.OK) {
        if (!json) {
            out.println("Failed: " + response);
        } else {
            out.println(response.toJsonString());
        }
        return 1;
    }
    if (!json) {
        out.println(format("Rolling update%s started: %s -> %s " + "(parallelism=%d, timeout=%d, overlap=%b, token=%s)%s", async ? " (async)" : "", name, jobId.toShortString(), parallelism, timeout, overlap, token, async ? "" : "\n"));
    }
    final Map<String, Object> jsonOutput = Maps.newHashMap();
    jsonOutput.put("parallelism", parallelism);
    jsonOutput.put("timeout", timeout);
    jsonOutput.put("overlap", overlap);
    jsonOutput.put("token", token);
    if (async) {
        if (json) {
            jsonOutput.put("status", response.getStatus());
            out.println(Json.asStringUnchecked(jsonOutput));
        }
        return 0;
    }
    String error = "";
    boolean failed = false;
    boolean timedOut = false;
    final Set<String> reported = Sets.newHashSet();
    while (true) {
        final DeploymentGroupStatusResponse status = client.deploymentGroupStatus(name).get();
        if (status == null) {
            failed = true;
            error = "Failed to fetch deployment-group status";
            break;
        }
        if (!jobId.equals(status.getDeploymentGroup().getJobId())) {
            // Another rolling-update was started, overriding this one -- exit
            failed = true;
            error = "Deployment-group job id changed during rolling-update";
            break;
        }
        if (!json) {
            for (final DeploymentGroupStatusResponse.HostStatus hostStatus : status.getHostStatuses()) {
                final JobId hostJobId = hostStatus.getJobId();
                final String host = hostStatus.getHost();
                final TaskStatus.State state = hostStatus.getState();
                final boolean done = hostJobId != null && hostJobId.equals(jobId) && state == TaskStatus.State.RUNNING;
                if (done && reported.add(host)) {
                    out.println(format("%s -> %s (%d/%d)", host, state, reported.size(), status.getHostStatuses().size()));
                }
            }
        }
        if (status.getStatus() != DeploymentGroupStatusResponse.Status.ROLLING_OUT) {
            if (status.getStatus() == DeploymentGroupStatusResponse.Status.FAILED) {
                failed = true;
                error = status.getError();
            }
            break;
        }
        if (timeSupplier.get() - startTime > TimeUnit.MINUTES.toMillis(rolloutTimeout)) {
            // Rollout timed out
            timedOut = true;
            break;
        }
        sleepFunction.sleep(POLL_INTERVAL_MILLIS);
    }
    final double duration = (timeSupplier.get() - startTime) / 1000.0;
    if (json) {
        if (failed) {
            jsonOutput.put("status", "FAILED");
            jsonOutput.put("error", error);
        } else if (timedOut) {
            jsonOutput.put("status", "TIMEOUT");
        } else {
            jsonOutput.put("status", "DONE");
        }
        jsonOutput.put("duration", duration);
        out.println(Json.asStringUnchecked(jsonOutput));
    } else {
        out.println();
        if (failed) {
            out.println(format("Failed: %s", error));
        } else if (timedOut) {
            out.println("Timed out! (rolling-update still in progress)");
        } else {
            out.println("Done.");
        }
        out.println(format("Duration: %.2f s", duration));
    }
    return (failed || timedOut) ? 1 : 0;
}
Also used : RolloutOptions(com.spotify.helios.common.descriptors.RolloutOptions) TaskStatus(com.spotify.helios.common.descriptors.TaskStatus) DeploymentGroupStatusResponse(com.spotify.helios.common.protocol.DeploymentGroupStatusResponse) RollingUpdateResponse(com.spotify.helios.common.protocol.RollingUpdateResponse) JobId(com.spotify.helios.common.descriptors.JobId)

Example 2 with RolloutOptions

use of com.spotify.helios.common.descriptors.RolloutOptions in project helios by spotify.

the class JobCreateCommand method run.

@Override
int run(final Namespace options, final HeliosClient client, final PrintStream out, final boolean json, final BufferedReader stdin) throws ExecutionException, InterruptedException, IOException {
    final boolean quiet = options.getBoolean(quietArg.getDest());
    final Job.Builder builder;
    final String id = options.getString(idArg.getDest());
    final String imageIdentifier = options.getString(imageArg.getDest());
    // Read job configuration from file
    // TODO (dano): look for e.g. Heliosfile in cwd by default?
    final String templateJobId = options.getString(templateArg.getDest());
    final File file = options.get(fileArg.getDest());
    if (file != null && templateJobId != null) {
        throw new IllegalArgumentException("Please use only one of -t/--template and -f/--file");
    }
    if (file != null) {
        if (!file.exists() || !file.isFile() || !file.canRead()) {
            throw new IllegalArgumentException("Cannot read file " + file);
        }
        final byte[] bytes = Files.readAllBytes(file.toPath());
        final String config = new String(bytes, UTF_8);
        final Job job = Json.read(config, Job.class);
        builder = job.toBuilder();
    } else if (templateJobId != null) {
        final Map<JobId, Job> jobs = client.jobs(templateJobId).get();
        if (jobs.size() == 0) {
            if (!json) {
                out.printf("Unknown job: %s%n", templateJobId);
            } else {
                final CreateJobResponse createJobResponse = new CreateJobResponse(CreateJobResponse.Status.UNKNOWN_JOB, null, null);
                out.print(createJobResponse.toJsonString());
            }
            return 1;
        } else if (jobs.size() > 1) {
            if (!json) {
                out.printf("Ambiguous job reference: %s%n", templateJobId);
            } else {
                final CreateJobResponse createJobResponse = new CreateJobResponse(CreateJobResponse.Status.AMBIGUOUS_JOB_REFERENCE, null, null);
                out.print(createJobResponse.toJsonString());
            }
            return 1;
        }
        final Job template = Iterables.getOnlyElement(jobs.values());
        builder = template.toBuilder();
        if (id == null) {
            throw new IllegalArgumentException("Please specify new job name and version");
        }
    } else {
        if (id == null || imageIdentifier == null) {
            throw new IllegalArgumentException("Please specify a file, or a template, or a job name, version and container image");
        }
        builder = Job.newBuilder();
    }
    if (id != null) {
        final String[] parts = id.split(":");
        switch(parts.length) {
            case 3:
                builder.setHash(parts[2]);
            // fall through
            case 2:
                builder.setVersion(parts[1]);
            // fall through
            case 1:
                builder.setName(parts[0]);
                break;
            default:
                throw new IllegalArgumentException("Invalid Job id: " + id);
        }
    }
    if (imageIdentifier != null) {
        builder.setImage(imageIdentifier);
    }
    final String hostname = options.getString(hostnameArg.getDest());
    if (!isNullOrEmpty(hostname)) {
        builder.setHostname(hostname);
    }
    final List<String> command = options.getList(argsArg.getDest());
    if (command != null && !command.isEmpty()) {
        builder.setCommand(command);
    }
    final List<String> envList = options.getList(envArg.getDest());
    // TODO (mbrown): does this mean that env config is only added when there is a CLI flag too?
    if (!envList.isEmpty()) {
        final Map<String, String> env = Maps.newHashMap();
        // Add environmental variables from helios job configuration file
        env.putAll(builder.getEnv());
        // Add environmental variables passed in via CLI
        // Overwrite any redundant keys to make CLI args take precedence
        env.putAll(parseListOfPairs(envList, "environment variable"));
        builder.setEnv(env);
    }
    final Map<String, String> metadata = Maps.newHashMap();
    metadata.putAll(defaultMetadata());
    metadata.putAll(builder.getMetadata());
    final List<String> metadataList = options.getList(metadataArg.getDest());
    metadata.putAll(parseListOfPairs(metadataList, "metadata"));
    builder.setMetadata(metadata);
    // Parse port mappings
    final List<String> portSpecs = options.getList(portArg.getDest());
    final Map<String, PortMapping> explicitPorts = PortMappingParser.parsePortMappings(portSpecs);
    // Merge port mappings
    final Map<String, PortMapping> ports = Maps.newHashMap();
    ports.putAll(builder.getPorts());
    ports.putAll(explicitPorts);
    builder.setPorts(ports);
    // Parse service registrations
    final Map<ServiceEndpoint, ServicePorts> explicitRegistration = Maps.newHashMap();
    final Pattern registrationPattern = compile("(?<srv>[a-zA-Z][_\\-\\w]+)(?:/(?<prot>\\w+))?(?:=(?<port>[_\\-\\w]+))?");
    final List<String> registrationSpecs = options.getList(registrationArg.getDest());
    for (final String spec : registrationSpecs) {
        final Matcher matcher = registrationPattern.matcher(spec);
        if (!matcher.matches()) {
            throw new IllegalArgumentException("Bad registration: " + spec);
        }
        final String service = matcher.group("srv");
        final String proto = fromNullable(matcher.group("prot")).or(HTTP);
        final String optionalPort = matcher.group("port");
        final String port;
        if (ports.size() == 0) {
            throw new IllegalArgumentException("Need port mappings for service registration.");
        }
        if (optionalPort == null) {
            if (ports.size() != 1) {
                throw new IllegalArgumentException("Need exactly one port mapping for implicit service registration");
            }
            port = Iterables.getLast(ports.keySet());
        } else {
            port = optionalPort;
        }
        explicitRegistration.put(ServiceEndpoint.of(service, proto), ServicePorts.of(port));
    }
    final String registrationDomain = options.getString(registrationDomainArg.getDest());
    if (!isNullOrEmpty(registrationDomain)) {
        builder.setRegistrationDomain(registrationDomain);
    }
    // Merge service registrations
    final Map<ServiceEndpoint, ServicePorts> registration = Maps.newHashMap();
    registration.putAll(builder.getRegistration());
    registration.putAll(explicitRegistration);
    builder.setRegistration(registration);
    // Get grace period interval
    final Integer gracePeriod = options.getInt(gracePeriodArg.getDest());
    if (gracePeriod != null) {
        builder.setGracePeriod(gracePeriod);
    }
    // Parse volumes
    final List<String> volumeSpecs = options.getList(volumeArg.getDest());
    for (final String spec : volumeSpecs) {
        final String[] parts = spec.split(":", 2);
        switch(parts.length) {
            // Data volume
            case 1:
                builder.addVolume(parts[0]);
                break;
            // Bind mount
            case 2:
                final String path = parts[1];
                final String source = parts[0];
                builder.addVolume(path, source);
                break;
            default:
                throw new IllegalArgumentException("Invalid volume: " + spec);
        }
    }
    // Parse expires timestamp
    final String expires = options.getString(expiresArg.getDest());
    if (expires != null) {
        // Use DateTime to parse the ISO-8601 string
        builder.setExpires(new DateTime(expires).toDate());
    }
    // Parse health check
    final String execString = options.getString(healthCheckExecArg.getDest());
    final List<String> execHealthCheck = (execString == null) ? null : Arrays.asList(execString.split(" "));
    final String httpHealthCheck = options.getString(healthCheckHttpArg.getDest());
    final String tcpHealthCheck = options.getString(healthCheckTcpArg.getDest());
    int numberOfHealthChecks = 0;
    for (final String c : asList(httpHealthCheck, tcpHealthCheck)) {
        if (!isNullOrEmpty(c)) {
            numberOfHealthChecks++;
        }
    }
    if (execHealthCheck != null && !execHealthCheck.isEmpty()) {
        numberOfHealthChecks++;
    }
    if (numberOfHealthChecks > 1) {
        throw new IllegalArgumentException("Only one health check may be specified.");
    }
    if (execHealthCheck != null && !execHealthCheck.isEmpty()) {
        builder.setHealthCheck(ExecHealthCheck.of(execHealthCheck));
    } else if (!isNullOrEmpty(httpHealthCheck)) {
        final String[] parts = httpHealthCheck.split(":", 2);
        if (parts.length != 2) {
            throw new IllegalArgumentException("Invalid HTTP health check: " + httpHealthCheck);
        }
        builder.setHealthCheck(HttpHealthCheck.of(parts[0], parts[1]));
    } else if (!isNullOrEmpty(tcpHealthCheck)) {
        builder.setHealthCheck(TcpHealthCheck.of(tcpHealthCheck));
    }
    final List<String> securityOpt = options.getList(securityOptArg.getDest());
    if (securityOpt != null && !securityOpt.isEmpty()) {
        builder.setSecurityOpt(securityOpt);
    }
    final String networkMode = options.getString(networkModeArg.getDest());
    if (!isNullOrEmpty(networkMode)) {
        builder.setNetworkMode(networkMode);
    }
    final String token = options.getString(tokenArg.getDest());
    if (!isNullOrEmpty(token)) {
        builder.setToken(token);
    }
    final List<String> addCaps = options.getList(addCapabilityArg.getDest());
    if (addCaps != null && !addCaps.isEmpty()) {
        builder.setAddCapabilities(addCaps);
    }
    final List<String> dropCaps = options.getList(dropCapabilityArg.getDest());
    if (dropCaps != null && !dropCaps.isEmpty()) {
        builder.setDropCapabilities(dropCaps);
    }
    final List<String> labelsList = options.getList(labelsArg.getDest());
    if (!labelsList.isEmpty()) {
        final Map<String, String> labels = Maps.newHashMap();
        labels.putAll(parseListOfPairs(labelsList, "labels"));
        builder.setLabels(labels);
    }
    final List<String> rolloutOptionsList = options.getList(rolloutOptionsArg.getDest());
    if (!rolloutOptionsList.isEmpty()) {
        final Map<String, String> rolloutOptionsMap = Maps.newHashMap();
        rolloutOptionsMap.putAll(parseListOfPairs(rolloutOptionsList, "rollout_options"));
        final RolloutOptions rolloutOptions = Json.convert(rolloutOptionsMap, RolloutOptions.class);
        builder.setRolloutOptions(rolloutOptions);
    }
    final String runtime = options.getString(runtimeArg.getDest());
    if (!isNullOrEmpty(runtime)) {
        builder.setRuntime(runtime);
    }
    // We build without a hash here because we want the hash to be calculated server-side.
    // This allows different CLI versions to be cross-compatible with different master versions
    // that have either more or fewer job parameters.
    final Job job = builder.buildWithoutHash();
    final Collection<String> errors = JOB_VALIDATOR.validate(job);
    if (!errors.isEmpty()) {
        if (!json) {
            for (final String error : errors) {
                out.println(error);
            }
        } else {
            final CreateJobResponse createJobResponse = new CreateJobResponse(CreateJobResponse.Status.INVALID_JOB_DEFINITION, ImmutableList.copyOf(errors), job.getId().toString());
            out.println(createJobResponse.toJsonString());
        }
        return 1;
    }
    if (!quiet && !json) {
        out.println("Creating job: " + job.toJsonString());
    }
    final CreateJobResponse status = client.createJob(job).get();
    if (status.getStatus() == CreateJobResponse.Status.OK) {
        if (!quiet && !json) {
            out.println("Done.");
        }
        if (json) {
            out.println(status.toJsonString());
        } else {
            out.println(status.getId());
        }
        return 0;
    } else {
        if (!quiet && !json) {
            out.println("Failed: " + status);
        } else if (json) {
            out.println(status.toJsonString());
        }
        return 1;
    }
}
Also used : RolloutOptions(com.spotify.helios.common.descriptors.RolloutOptions) Pattern(java.util.regex.Pattern) Matcher(java.util.regex.Matcher) DateTime(org.joda.time.DateTime) ServiceEndpoint(com.spotify.helios.common.descriptors.ServiceEndpoint) CreateJobResponse(com.spotify.helios.common.protocol.CreateJobResponse) ServicePorts(com.spotify.helios.common.descriptors.ServicePorts) PortMapping(com.spotify.helios.common.descriptors.PortMapping) Job(com.spotify.helios.common.descriptors.Job) File(java.io.File) Map(java.util.Map) ImmutableMap(com.google.common.collect.ImmutableMap) HashMap(java.util.HashMap) ServiceEndpoint(com.spotify.helios.common.descriptors.ServiceEndpoint)

Example 3 with RolloutOptions

use of com.spotify.helios.common.descriptors.RolloutOptions in project helios by spotify.

the class DeploymentGroupInspectCommand method run.

@Override
int run(final Namespace options, final HeliosClient client, final PrintStream out, final boolean json, final BufferedReader stdin) throws ExecutionException, InterruptedException, IOException {
    final String name = options.getString(nameArg.getDest());
    final DeploymentGroup deploymentGroup = client.deploymentGroup(name).get();
    if (deploymentGroup == null) {
        if (json) {
            final Map<String, Object> output = Maps.newHashMap();
            output.put("status", "DEPLOYMENT_GROUP_NOT_FOUND");
            out.print(Json.asStringUnchecked(output));
        } else {
            out.printf("Unknown deployment group: %s%n", name);
        }
        return 1;
    }
    if (json) {
        out.println(Json.asPrettyStringUnchecked(deploymentGroup));
    } else {
        out.printf("Name: %s%n", deploymentGroup.getName());
        out.printf("Host selectors:%n");
        for (final HostSelector hostSelector : deploymentGroup.getHostSelectors()) {
            out.printf("  %s%n", hostSelector.toPrettyString());
        }
        out.printf("Job: %s%n", deploymentGroup.getJobId());
        if (deploymentGroup.getRollingUpdateReason() != null) {
            out.printf("Rolling update reason: %s%n", deploymentGroup.getRollingUpdateReason());
        }
        final RolloutOptions rolloutOptions = deploymentGroup.getRolloutOptions();
        if (rolloutOptions != null) {
            out.printf("Rollout options:%n");
            out.printf("  Migrate: %s%n", rolloutOptions.getMigrate());
            out.printf("  Overlap: %s%n", rolloutOptions.getOverlap());
            out.printf("  Parallelism: %d%n", rolloutOptions.getParallelism());
            out.printf("  Timeout: %d%n", rolloutOptions.getTimeout());
            if (!isNullOrEmpty(rolloutOptions.getToken())) {
                out.printf("  Token: %s%n", rolloutOptions.getToken());
            }
            out.printf("  Ignore failures: %b%n", rolloutOptions.getIgnoreFailures());
        }
    }
    return 0;
}
Also used : RolloutOptions(com.spotify.helios.common.descriptors.RolloutOptions) HostSelector(com.spotify.helios.common.descriptors.HostSelector) DeploymentGroup(com.spotify.helios.common.descriptors.DeploymentGroup)

Example 4 with RolloutOptions

use of com.spotify.helios.common.descriptors.RolloutOptions in project helios by spotify.

the class RollingUpdateCommand method runWithJob.

@Override
protected int runWithJob(final Namespace options, final HeliosClient client, final PrintStream out, final boolean json, final Job job, final BufferedReader stdin) throws ExecutionException, InterruptedException, IOException {
    final JobId jobId = job.getId();
    final String name = options.getString(nameArg.getDest());
    final Long timeout = options.getLong(timeoutArg.getDest());
    final Integer parallelism = options.getInt(parallelismArg.getDest());
    final boolean async = options.getBoolean(asyncArg.getDest());
    final long rolloutTimeout = options.getLong(rolloutTimeoutArg.getDest());
    final Boolean migrate = options.getBoolean(migrateArg.getDest());
    final Boolean overlap = options.getBoolean(overlapArg.getDest());
    final String token = options.getString(tokenArg.getDest());
    final Boolean ignoreFailures = options.getBoolean(ignoreFailuresArg.getDest());
    checkArgument(timeout == null || timeout > 0, "Timeout must be greater than 0");
    checkArgument(parallelism == null || parallelism > 0, "Parallelism must be greater than 0");
    checkArgument(rolloutTimeout > 0, "Rollout timeout must be greater than 0");
    final long startTime = timeSupplier.get();
    final RolloutOptions rolloutOptions = RolloutOptions.newBuilder().setTimeout(timeout).setParallelism(parallelism).setMigrate(migrate).setOverlap(overlap).setToken(token).setIgnoreFailures(ignoreFailures).build();
    final RollingUpdateResponse response = client.rollingUpdate(name, jobId, rolloutOptions).get();
    if (response.getStatus() != RollingUpdateResponse.Status.OK) {
        if (!json) {
            out.println("Failed: " + response);
        } else {
            out.println(response.toJsonString());
        }
        return 1;
    }
    final RolloutOptions optionsFromJob = MoreObjects.firstNonNull(job.getRolloutOptions(), RolloutOptions.getDefault());
    final Integer actualParallelism = nullableWithFallback(parallelism, optionsFromJob.getParallelism());
    final Long actualTimeout = nullableWithFallback(timeout, optionsFromJob.getTimeout());
    final Boolean actualOverlap = nullableWithFallback(overlap, optionsFromJob.getOverlap());
    final String actualToken = nullableWithFallback(token, optionsFromJob.getToken());
    final Boolean actualIgnoreFailures = nullableWithFallback(ignoreFailures, optionsFromJob.getIgnoreFailures());
    final Boolean actualMigrate = nullableWithFallback(migrate, optionsFromJob.getMigrate());
    if (!json) {
        out.println(format("Rolling update%s started: %s -> %s " + "(parallelism=%d, timeout=%d, overlap=%b, token=%s, " + "ignoreFailures=%b, migrate=%b)%s", async ? " (async)" : "", name, jobId.toShortString(), actualParallelism, actualTimeout, actualOverlap, actualToken, actualIgnoreFailures, actualMigrate, async ? "" : "\n"));
    }
    final Map<String, Object> jsonOutput = Maps.newHashMap();
    jsonOutput.put("parallelism", actualParallelism);
    jsonOutput.put("timeout", actualTimeout);
    jsonOutput.put("overlap", actualOverlap);
    jsonOutput.put("token", actualToken);
    jsonOutput.put("ignoreFailures", actualIgnoreFailures);
    jsonOutput.put("migrate", actualMigrate);
    if (async) {
        if (json) {
            jsonOutput.put("status", response.getStatus());
            out.println(Json.asStringUnchecked(jsonOutput));
        }
        return 0;
    }
    String error = "";
    boolean failed = false;
    boolean timedOut = false;
    final Set<String> reported = Sets.newHashSet();
    while (true) {
        final DeploymentGroupStatusResponse status = client.deploymentGroupStatus(name).get();
        if (status == null) {
            failed = true;
            error = "Failed to fetch deployment-group status";
            break;
        }
        if (!jobId.equals(status.getDeploymentGroup().getJobId())) {
            // Another rolling-update was started, overriding this one -- exit
            failed = true;
            error = "Deployment-group job id changed during rolling-update";
            break;
        }
        if (!json) {
            for (final DeploymentGroupStatusResponse.HostStatus hostStatus : status.getHostStatuses()) {
                final JobId hostJobId = hostStatus.getJobId();
                final String host = hostStatus.getHost();
                final TaskStatus.State state = hostStatus.getState();
                final boolean done = hostJobId != null && hostJobId.equals(jobId) && state == TaskStatus.State.RUNNING;
                if (done && reported.add(host)) {
                    out.println(format("%s -> %s (%d/%d)", host, state, reported.size(), status.getHostStatuses().size()));
                }
            }
        }
        if (status.getStatus() != DeploymentGroupStatusResponse.Status.ROLLING_OUT) {
            if (status.getStatus() == DeploymentGroupStatusResponse.Status.FAILED) {
                failed = true;
                error = status.getError();
            }
            break;
        }
        if (timeSupplier.get() - startTime > TimeUnit.MINUTES.toMillis(rolloutTimeout)) {
            // Rollout timed out
            timedOut = true;
            break;
        }
        sleepFunction.sleep(POLL_INTERVAL_MILLIS);
    }
    final double duration = (timeSupplier.get() - startTime) / 1000.0;
    if (json) {
        if (failed) {
            jsonOutput.put("status", "FAILED");
            jsonOutput.put("error", error);
        } else if (timedOut) {
            jsonOutput.put("status", "TIMEOUT");
        } else {
            jsonOutput.put("status", "DONE");
        }
        jsonOutput.put("duration", duration);
        out.println(Json.asStringUnchecked(jsonOutput));
    } else {
        out.println();
        if (failed) {
            out.println(format("Failed: %s", error));
        } else if (timedOut) {
            out.println("Timed out! (rolling-update still in progress)");
        } else {
            out.println("Done.");
        }
        out.println(format("Duration: %.2f s", duration));
    }
    return (failed || timedOut) ? 1 : 0;
}
Also used : RolloutOptions(com.spotify.helios.common.descriptors.RolloutOptions) TaskStatus(com.spotify.helios.common.descriptors.TaskStatus) DeploymentGroupStatusResponse(com.spotify.helios.common.protocol.DeploymentGroupStatusResponse) RollingUpdateResponse(com.spotify.helios.common.protocol.RollingUpdateResponse) JobId(com.spotify.helios.common.descriptors.JobId)

Example 5 with RolloutOptions

use of com.spotify.helios.common.descriptors.RolloutOptions in project helios by spotify.

the class RollingUpdateCommandTest method testRollingUpdateOverlapJson.

@Test
public void testRollingUpdateOverlapJson() throws Exception {
    when(client.rollingUpdate(anyString(), any(JobId.class), any(RolloutOptions.class))).thenReturn(immediateFuture(new RollingUpdateResponse(RollingUpdateResponse.Status.OK)));
    when(client.deploymentGroupStatus(GROUP_NAME)).then(new ResponseAnswer(statusResponse(DeploymentGroupStatusResponse.Status.ACTIVE, null, makeHostStatus("host1", JOB_ID, TaskStatus.State.RUNNING))));
    when(options.getBoolean("overlap")).thenReturn(true);
    final int ret = command.runWithJob(options, client, out, true, JOB, null);
    final String output = baos.toString();
    // Verify that rollingUpdate() was called with migrate=true
    final RolloutOptions rolloutOptions = RolloutOptions.newBuilder().setTimeout(TIMEOUT).setParallelism(PARALLELISM).setMigrate(false).setOverlap(true).setToken(TOKEN).setIgnoreFailures(false).build();
    verify(client).rollingUpdate(GROUP_NAME, JOB_ID, rolloutOptions);
    assertEquals(0, ret);
    assertJsonOutputEquals(output, ImmutableMap.<String, Object>builder().put("status", "DONE").put("duration", 0.00).put("parallelism", PARALLELISM).put("timeout", TIMEOUT).put("overlap", true).put("token", TOKEN).put("ignoreFailures", false).put("migrate", false).build());
}
Also used : RolloutOptions(com.spotify.helios.common.descriptors.RolloutOptions) RollingUpdateResponse(com.spotify.helios.common.protocol.RollingUpdateResponse) Matchers.anyString(org.mockito.Matchers.anyString) CoreMatchers.containsString(org.hamcrest.CoreMatchers.containsString) JobId(com.spotify.helios.common.descriptors.JobId) Test(org.junit.Test)

Aggregations

RolloutOptions (com.spotify.helios.common.descriptors.RolloutOptions)10 JobId (com.spotify.helios.common.descriptors.JobId)5 RollingUpdateResponse (com.spotify.helios.common.protocol.RollingUpdateResponse)5 Test (org.junit.Test)4 Job (com.spotify.helios.common.descriptors.Job)3 Matchers.anyString (org.mockito.Matchers.anyString)3 DeploymentGroup (com.spotify.helios.common.descriptors.DeploymentGroup)2 TaskStatus (com.spotify.helios.common.descriptors.TaskStatus)2 DeploymentGroupStatusResponse (com.spotify.helios.common.protocol.DeploymentGroupStatusResponse)2 KeeperException (org.apache.zookeeper.KeeperException)2 CoreMatchers.containsString (org.hamcrest.CoreMatchers.containsString)2 ImmutableMap (com.google.common.collect.ImmutableMap)1 HeliosRuntimeException (com.spotify.helios.common.HeliosRuntimeException)1 HostSelector (com.spotify.helios.common.descriptors.HostSelector)1 PortMapping (com.spotify.helios.common.descriptors.PortMapping)1 ServiceEndpoint (com.spotify.helios.common.descriptors.ServiceEndpoint)1 ServicePorts (com.spotify.helios.common.descriptors.ServicePorts)1 CreateJobResponse (com.spotify.helios.common.protocol.CreateJobResponse)1 RollingUpdateOp (com.spotify.helios.rollingupdate.RollingUpdateOp)1 ZooKeeperClient (com.spotify.helios.servicescommon.coordination.ZooKeeperClient)1