Search in sources :

Example 56 with JobId

use of com.spotify.helios.common.descriptors.JobId 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 57 with JobId

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

the class HeliosSoloDeploymentTest method testUndeployLeftoverJobs.

@Test
public void testUndeployLeftoverJobs() throws Exception {
    final HeliosSoloDeployment solo = buildHeliosSoloDeployment();
    final ListenableFuture<List<String>> hostsFuture = Futures.<List<String>>immediateFuture(ImmutableList.of(HOST1, HOST2));
    when(heliosClient.listHosts()).thenReturn(hostsFuture);
    // These futures represent HostStatuses when the job is still deployed
    final ListenableFuture<HostStatus> statusFuture11 = Futures.immediateFuture(HostStatus.newBuilder().setStatus(Status.UP).setStatuses(ImmutableMap.of(JOB_ID1, TASK_STATUS1)).setJobs(ImmutableMap.of(JOB_ID1, Deployment.of(JOB_ID1, Goal.START))).build());
    final ListenableFuture<HostStatus> statusFuture21 = Futures.immediateFuture(HostStatus.newBuilder().setStatus(Status.UP).setStatuses(ImmutableMap.of(JOB_ID2, TASK_STATUS2)).setJobs(ImmutableMap.of(JOB_ID2, Deployment.of(JOB_ID2, Goal.START))).build());
    // These futures represent HostStatuses when the job is undeployed
    final ListenableFuture<HostStatus> statusFuture12 = Futures.immediateFuture(HostStatus.newBuilder().setStatus(Status.UP).setStatuses(Collections.<JobId, TaskStatus>emptyMap()).setJobs(ImmutableMap.of(JOB_ID1, Deployment.of(JOB_ID1, Goal.START))).build());
    final ListenableFuture<HostStatus> statusFuture22 = Futures.immediateFuture(HostStatus.newBuilder().setStatus(Status.UP).setStatuses(Collections.<JobId, TaskStatus>emptyMap()).setJobs(ImmutableMap.of(JOB_ID2, Deployment.of(JOB_ID2, Goal.START))).build());
    //noinspection unchecked
    when(heliosClient.hostStatus(HOST1)).thenReturn(statusFuture11);
    //noinspection unchecked
    when(heliosClient.hostStatus(HOST2)).thenReturn(statusFuture21);
    final ListenableFuture<JobUndeployResponse> undeployFuture1 = Futures.immediateFuture(new JobUndeployResponse(JobUndeployResponse.Status.OK, HOST1, JOB_ID1));
    final ListenableFuture<JobUndeployResponse> undeployFuture2 = Futures.immediateFuture(new JobUndeployResponse(JobUndeployResponse.Status.OK, HOST2, JOB_ID2));
    // when undeploy is called, respond correctly & patch the mock to return
    // the undeployed HostStatus
    when(heliosClient.undeploy(JOB_ID1, HOST1)).thenAnswer(new Answer<ListenableFuture<JobUndeployResponse>>() {

        @Override
        public ListenableFuture<JobUndeployResponse> answer(final InvocationOnMock invocation) throws Throwable {
            when(heliosClient.hostStatus(HOST1)).thenReturn(statusFuture12);
            return undeployFuture1;
        }
    });
    when(heliosClient.undeploy(JOB_ID2, HOST2)).thenAnswer(new Answer<ListenableFuture<JobUndeployResponse>>() {

        @Override
        public ListenableFuture<JobUndeployResponse> answer(final InvocationOnMock invocation) throws Throwable {
            when(heliosClient.hostStatus(HOST1)).thenReturn(statusFuture22);
            return undeployFuture2;
        }
    });
    solo.undeployLeftoverJobs();
    verify(heliosClient).undeploy(JOB_ID1, HOST1);
    verify(heliosClient).undeploy(JOB_ID2, HOST2);
}
Also used : TaskStatus(com.spotify.helios.common.descriptors.TaskStatus) JobUndeployResponse(com.spotify.helios.common.protocol.JobUndeployResponse) InvocationOnMock(org.mockito.invocation.InvocationOnMock) ListenableFuture(com.google.common.util.concurrent.ListenableFuture) ImmutableList(com.google.common.collect.ImmutableList) List(java.util.List) HostStatus(com.spotify.helios.common.descriptors.HostStatus) JobId(com.spotify.helios.common.descriptors.JobId) Test(org.junit.Test)

Example 58 with JobId

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

the class JobNamePrefixTest method testJobNamePrefix.

@Test
public void testJobNamePrefix() throws Exception {
    // Create four jobs which represent these use cases:
    //  job1 - Created, deployed, locked. Simulates a job being used by another process. The
    //         job should not get undeployed or deleted since it is in use.
    //  job2 - Created, not deployed, locked. Simulates a job being used by another process. The
    //         job should not get deleted since it is in use.
    //  job3 - Created, deployed, not locked. Simulates an old job no longer in use, which should
    //         be undeployed and deleted.
    //  job4 - Created, not deployed, not locked. Simulates an old job no longer in use, which
    //         should be deleted.
    // job1 - create and deploy
    final JobId jobId1 = createJob(testJobName + "_1", testJobVersion, BUSYBOX, IDLE_COMMAND);
    deployJob(jobId1, testHost1);
    // job2 - create
    final JobId jobId2 = createJob(testJobName + "_2", testJobVersion, BUSYBOX, IDLE_COMMAND);
    // job3 - create and deploy
    final JobId jobId3 = createJob(testJobName + "_3", testJobVersion, BUSYBOX, IDLE_COMMAND);
    deployJob(jobId3, testHost1);
    // job4 - create
    final JobId jobId4 = createJob(testJobName + "_4", testJobVersion, BUSYBOX, IDLE_COMMAND);
    try (// Create prefix files for all four jobs. They will be locked by default.
    JobPrefixFile file1 = JobPrefixFile.create(jobId1.getName(), prefixDirectory);
        JobPrefixFile file2 = JobPrefixFile.create(jobId2.getName(), prefixDirectory);
        JobPrefixFile file3 = JobPrefixFile.create(jobId3.getName(), prefixDirectory);
        JobPrefixFile file4 = JobPrefixFile.create(jobId4.getName(), prefixDirectory)) {
        // Release the locks of jobs 3 and 4 so they can be cleaned up
        file3.release();
        file4.release();
        assertThat(testResult(JobNamePrefixTestImpl.class), isSuccessful());
        final Map<JobId, Job> jobs = client.jobs().get();
        // Verify job1 is still deployed and the prefix file has not been deleted.
        assertThat(jobs, hasKey(jobId1));
        final JobStatus status1 = client.jobStatus(jobId1).get();
        assertThat(status1.getDeployments().size(), is(1));
        assertTrue(fileExists(prefixDirectory, jobId1.getName()));
        // Verify job2 still exists, is not deployed, and the prefix file is still there.
        assertThat(jobs, hasKey(jobId2));
        final JobStatus status2 = client.jobStatus(jobId2).get();
        assertThat(status2.getDeployments().size(), is(0));
        assertTrue(fileExists(prefixDirectory, jobId2.getName()));
        // Verify that job3 has been deleted (which means it has also been undeployed), and
        // the prefix file has been deleted.
        assertThat(jobs, not(hasKey(jobId3)));
        assertFalse(fileExists(prefixDirectory, jobId3.getName()));
        // Verify that job4 and its prefix file have been deleted.
        assertThat(jobs, not(hasKey(jobId4)));
        assertFalse(fileExists(prefixDirectory, jobId4.getName()));
        // Verify the prefix file created during the run of JobNamePrefixTest was deleted
        assertFalse(fileExists(prefixDirectory, jobPrefixFile.prefix()));
    }
}
Also used : JobStatus(com.spotify.helios.common.descriptors.JobStatus) Job(com.spotify.helios.common.descriptors.Job) JobId(com.spotify.helios.common.descriptors.JobId) Test(org.junit.Test)

Example 59 with JobId

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

the class JobStatusCommand method run.

@Override
int run(final Namespace options, final HeliosClient client, final PrintStream out, final boolean json, final BufferedReader stdin) throws ExecutionException, InterruptedException {
    final String jobIdString = options.getString(jobArg.getDest());
    final String hostPattern = options.getString(hostArg.getDest());
    final boolean full = options.getBoolean(fullArg.getDest());
    final Map<JobId, Job> jobs;
    if (Strings.isNullOrEmpty(jobIdString)) {
        jobs = client.jobs().get();
    } else {
        jobs = client.jobs(jobIdString).get();
    }
    if (jobs == null) {
        out.printf("The specified Helios master either returned an error or job id matcher " + "\"%s\" matched no jobs%n", jobIdString);
        return 1;
    }
    final Set<JobId> jobIds = jobs.keySet();
    if (!Strings.isNullOrEmpty(jobIdString) && jobIds.isEmpty()) {
        if (json) {
            out.println("{ }");
        } else {
            out.printf("job id matcher \"%s\" matched no jobs%n", jobIdString);
        }
        return 1;
    }
    final Map<JobId, JobStatus> statuses = Maps.newTreeMap();
    statuses.putAll(client.jobStatuses(jobIds).get());
    if (json) {
        showJsonStatuses(out, hostPattern, jobIds, statuses);
        return 0;
    }
    final JobStatusTable table = jobStatusTable(out, full);
    final boolean noHostMatchedEver = showStatusesForHosts(hostPattern, jobIds, statuses, new HostStatusDisplayer() {

        @Override
        public void matchedStatus(JobStatus jobStatus, Iterable<String> matchingHosts, Map<String, TaskStatus> taskStatuses) {
            displayTask(full, table, jobStatus.getJob().getId(), jobStatus, taskStatuses, matchingHosts);
        }
    });
    if (noHostMatchedEver) {
        String domainsSwitchString = "";
        final List<String> domains = options.get("domains");
        if (domains.size() > 0) {
            domainsSwitchString = "-d " + Joiner.on(",").join(domains);
        }
        out.printf("There are no jobs deployed to hosts with the host pattern '%s'%n" + "Run 'helios %s hosts %s' to check your host exists and is up.%n", hostPattern, domainsSwitchString, hostPattern);
        return 1;
    }
    table.print();
    return 0;
}
Also used : JobStatusTable(com.spotify.helios.cli.JobStatusTable) TaskStatus(com.spotify.helios.common.descriptors.TaskStatus) JobStatus(com.spotify.helios.common.descriptors.JobStatus) Job(com.spotify.helios.common.descriptors.Job) JobId(com.spotify.helios.common.descriptors.JobId)

Example 60 with JobId

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

the class JobStatusCommand method showStatusesForHosts.

private boolean showStatusesForHosts(final String hostPattern, final Set<JobId> jobIds, final Map<JobId, JobStatus> statuses, final HostStatusDisplayer statusDisplayer) {
    boolean noHostMatchedEver = true;
    for (final JobId jobId : Ordering.natural().sortedCopy(jobIds)) {
        final JobStatus jobStatus = statuses.get(jobId);
        // jobStatus will be null if the job was deleted after we first got the list of job IDs
        if (jobStatus == null) {
            continue;
        }
        final Map<String, TaskStatus> taskStatuses = Maps.newTreeMap();
        taskStatuses.putAll(jobStatus.getTaskStatuses());
        // This will help us see hosts where jobs aren't running correctly.
        for (final String host : jobStatus.getDeployments().keySet()) {
            if (!taskStatuses.containsKey(host)) {
                taskStatuses.put(host, null);
            }
        }
        final FluentIterable<String> matchingHosts = FluentIterable.from(taskStatuses.keySet()).filter(containsPattern(hostPattern));
        if (Strings.isNullOrEmpty(hostPattern) || !Strings.isNullOrEmpty(hostPattern) && !matchingHosts.isEmpty()) {
            noHostMatchedEver = false;
        }
        statusDisplayer.matchedStatus(jobStatus, matchingHosts, taskStatuses);
    }
    return noHostMatchedEver;
}
Also used : JobStatus(com.spotify.helios.common.descriptors.JobStatus) TaskStatus(com.spotify.helios.common.descriptors.TaskStatus) JobId(com.spotify.helios.common.descriptors.JobId)

Aggregations

JobId (com.spotify.helios.common.descriptors.JobId)115 Test (org.junit.Test)68 TaskStatus (com.spotify.helios.common.descriptors.TaskStatus)41 Job (com.spotify.helios.common.descriptors.Job)37 HeliosClient (com.spotify.helios.client.HeliosClient)35 Deployment (com.spotify.helios.common.descriptors.Deployment)29 Matchers.containsString (org.hamcrest.Matchers.containsString)25 DockerClient (com.spotify.docker.client.DockerClient)19 JobStatus (com.spotify.helios.common.descriptors.JobStatus)19 JobDeployResponse (com.spotify.helios.common.protocol.JobDeployResponse)16 CreateJobResponse (com.spotify.helios.common.protocol.CreateJobResponse)13 IOException (java.io.IOException)12 HostStatus (com.spotify.helios.common.descriptors.HostStatus)11 Map (java.util.Map)11 LogStream (com.spotify.docker.client.LogStream)10 HeliosRuntimeException (com.spotify.helios.common.HeliosRuntimeException)10 KeeperException (org.apache.zookeeper.KeeperException)9 TaskStatusEvent (com.spotify.helios.common.descriptors.TaskStatusEvent)8 AgentMain (com.spotify.helios.agent.AgentMain)7 PortMapping (com.spotify.helios.common.descriptors.PortMapping)7