Search in sources :

Example 6 with Id

use of co.cask.cdap.proto.Id in project cdap by caskdata.

the class ApplicationLifecycleService method updateApp.

/**
   * Update an existing application. An application's configuration and artifact version can be updated.
   *
   * @param appId the id of the application to update
   * @param appRequest the request to update the application, including new config and artifact
   * @param programTerminator a program terminator that will stop programs that are removed when updating an app.
   *                          For example, if an update removes a flow, the terminator defines how to stop that flow.
   * @return information about the deployed application
   * @throws ApplicationNotFoundException if the specified application does not exist
   * @throws ArtifactNotFoundException if the requested artifact does not exist
   * @throws InvalidArtifactException if the specified artifact is invalid. For example, if the artifact name changed,
   *                                  if the version is an invalid version, or the artifact contains no app classes
   * @throws Exception if there was an exception during the deployment pipeline. This exception will often wrap
   *                   the actual exception
   */
public ApplicationWithPrograms updateApp(ApplicationId appId, AppRequest appRequest, ProgramTerminator programTerminator) throws Exception {
    // check that app exists
    ApplicationSpecification currentSpec = store.getApplication(appId);
    if (currentSpec == null) {
        throw new ApplicationNotFoundException(appId);
    }
    // App exists. Check if the current user has admin privileges on it before updating. The user's write privileges on
    // the namespace will get enforced in the deployApp method.
    authorizationEnforcer.enforce(appId, authenticationContext.getPrincipal(), Action.ADMIN);
    ArtifactId currentArtifact = currentSpec.getArtifactId();
    // if no artifact is given, use the current one.
    ArtifactId newArtifactId = currentArtifact;
    // otherwise, check requested artifact is valid and use it
    ArtifactSummary requestedArtifact = appRequest.getArtifact();
    if (requestedArtifact != null) {
        // cannot change artifact name, only artifact version.
        if (!currentArtifact.getName().equals(requestedArtifact.getName())) {
            throw new InvalidArtifactException(String.format(" Only artifact version updates are allowed. Cannot change from artifact '%s' to '%s'.", currentArtifact.getName(), requestedArtifact.getName()));
        }
        if (!currentArtifact.getScope().equals(requestedArtifact.getScope())) {
            throw new InvalidArtifactException("Only artifact version updates are allowed. " + "Cannot change from a non-system artifact to a system artifact or vice versa.");
        }
        // check requested artifact version is valid
        ArtifactVersion requestedVersion = new ArtifactVersion(requestedArtifact.getVersion());
        if (requestedVersion.getVersion() == null) {
            throw new InvalidArtifactException(String.format("Requested artifact version '%s' is invalid", requestedArtifact.getVersion()));
        }
        newArtifactId = new ArtifactId(currentArtifact.getName(), requestedVersion, currentArtifact.getScope());
    }
    // ownerAdmin.getImpersonationPrincipal will give the owner which will be impersonated for the application
    // irrespective of the version
    SecurityUtil.verifyOwnerPrincipal(appId, appRequest.getOwnerPrincipal(), ownerAdmin);
    Object requestedConfigObj = appRequest.getConfig();
    // if config is null, use the previous config. Shouldn't use a static GSON since the request Config object can
    // be a user class, otherwise there will be ClassLoader leakage.
    String requestedConfigStr = requestedConfigObj == null ? currentSpec.getConfiguration() : new Gson().toJson(requestedConfigObj);
    Id.Artifact artifactId = Artifacts.toArtifactId(appId.getParent(), newArtifactId).toId();
    return deployApp(appId.getParent(), appId.getApplication(), null, artifactId, requestedConfigStr, programTerminator, ownerAdmin.getOwner(appId), appRequest.canUpdateSchedules());
}
Also used : ApplicationSpecification(co.cask.cdap.api.app.ApplicationSpecification) ArtifactSummary(co.cask.cdap.api.artifact.ArtifactSummary) ArtifactVersion(co.cask.cdap.api.artifact.ArtifactVersion) ArtifactId(co.cask.cdap.api.artifact.ArtifactId) ApplicationNotFoundException(co.cask.cdap.common.ApplicationNotFoundException) Gson(com.google.gson.Gson) ArtifactId(co.cask.cdap.api.artifact.ArtifactId) Id(co.cask.cdap.proto.Id) ProgramId(co.cask.cdap.proto.id.ProgramId) NamespaceId(co.cask.cdap.proto.id.NamespaceId) KerberosPrincipalId(co.cask.cdap.proto.id.KerberosPrincipalId) ApplicationId(co.cask.cdap.proto.id.ApplicationId) EntityId(co.cask.cdap.proto.id.EntityId) InvalidArtifactException(co.cask.cdap.common.InvalidArtifactException)

Example 7 with Id

use of co.cask.cdap.proto.Id in project cdap by caskdata.

the class ApplicationLifecycleService method deleteApp.

// deletes without performs checks that no programs are running
/**
   * Delete the specified application without performing checks that its programs are stopped.
   *
   * @param appId the id of the application to delete
   * @param spec the spec of the application to delete
   * @throws Exception
   */
private void deleteApp(final ApplicationId appId, ApplicationSpecification spec) throws Exception {
    Id.Application idApplication = appId.toId();
    // enforce ADMIN privileges on the app
    authorizationEnforcer.enforce(appId, authenticationContext.getPrincipal(), Action.ADMIN);
    // first remove all privileges on the app
    revokePrivileges(appId, spec);
    //Delete the schedules
    scheduler.deleteSchedules(appId);
    deleteMetrics(appId);
    //Delete all preferences of the application and of all its programs
    deletePreferences(appId);
    // TODO: This should be unified with the DeletedProgramHandlerStage
    for (final FlowSpecification flowSpecification : spec.getFlows().values()) {
        Id.Program flowProgramId = Id.Program.from(idApplication, ProgramType.FLOW, flowSpecification.getName());
        // Collects stream name to all group ids consuming that stream
        final Multimap<String, Long> streamGroups = HashMultimap.create();
        for (FlowletConnection connection : flowSpecification.getConnections()) {
            if (connection.getSourceType() == FlowletConnection.Type.STREAM) {
                long groupId = FlowUtils.generateConsumerGroupId(flowProgramId, connection.getTargetName());
                streamGroups.put(connection.getSourceName(), groupId);
            }
        }
        // Remove all process states and group states for each stream
        final String namespace = String.format("%s.%s", flowProgramId.getApplicationId(), flowProgramId.getId());
        impersonator.doAs(appId, new Callable<Void>() {

            // TODO: (CDAP-7326) since one worker or flow can only be ran by a single instance of APP, (also a single
            // version), should delete flow for each version
            @Override
            public Void call() throws Exception {
                for (Map.Entry<String, Collection<Long>> entry : streamGroups.asMap().entrySet()) {
                    streamConsumerFactory.dropAll(appId.getParent().stream(entry.getKey()), namespace, entry.getValue());
                }
                queueAdmin.dropAllForFlow(appId.flow(flowSpecification.getName()));
                return null;
            }
        });
    }
    ApplicationSpecification appSpec = store.getApplication(appId);
    deleteAppMetadata(appId, appSpec);
    deleteRouteConfig(appId, appSpec);
    store.deleteWorkflowStats(appId);
    store.removeApplication(appId);
    try {
        // delete the owner as it has already been determined that this is the only version of the app
        ownerAdmin.delete(appId);
    } catch (Exception e) {
        LOG.warn("Failed to delete app owner principal for application {} if one existed while deleting the " + "application.", appId);
    }
    try {
        usageRegistry.unregister(appId);
    } catch (Exception e) {
        LOG.warn("Failed to unregister usage of app: {}", appId, e);
    }
}
Also used : ApplicationSpecification(co.cask.cdap.api.app.ApplicationSpecification) FlowletConnection(co.cask.cdap.api.flow.FlowletConnection) CannotBeDeletedException(co.cask.cdap.common.CannotBeDeletedException) ApplicationNotFoundException(co.cask.cdap.common.ApplicationNotFoundException) ArtifactNotFoundException(co.cask.cdap.common.ArtifactNotFoundException) ArtifactAlreadyExistsException(co.cask.cdap.common.ArtifactAlreadyExistsException) UnauthorizedException(co.cask.cdap.security.spi.authorization.UnauthorizedException) IOException(java.io.IOException) InvalidArtifactException(co.cask.cdap.common.InvalidArtifactException) ExecutionException(java.util.concurrent.ExecutionException) NotFoundException(co.cask.cdap.common.NotFoundException) FlowSpecification(co.cask.cdap.api.flow.FlowSpecification) ArtifactId(co.cask.cdap.api.artifact.ArtifactId) Id(co.cask.cdap.proto.Id) ProgramId(co.cask.cdap.proto.id.ProgramId) NamespaceId(co.cask.cdap.proto.id.NamespaceId) KerberosPrincipalId(co.cask.cdap.proto.id.KerberosPrincipalId) ApplicationId(co.cask.cdap.proto.id.ApplicationId) EntityId(co.cask.cdap.proto.id.EntityId)

Example 8 with Id

use of co.cask.cdap.proto.Id in project cdap by caskdata.

the class ProgramLifecycleHttpHandlerTest method testFlows.

@Test
public void testFlows() throws Exception {
    // deploy WordCountApp in namespace1 and verify
    HttpResponse response = deploy(WordCountApp.class, Constants.Gateway.API_VERSION_3_TOKEN, TEST_NAMESPACE1);
    Assert.assertEquals(200, response.getStatusLine().getStatusCode());
    // check initial flowlet instances
    int initial = getFlowletInstances(TEST_NAMESPACE1, WORDCOUNT_APP_NAME, WORDCOUNT_FLOW_NAME, WORDCOUNT_FLOWLET_NAME);
    Assert.assertEquals(1, initial);
    // request two more instances
    Assert.assertEquals(200, requestFlowletInstances(TEST_NAMESPACE1, WORDCOUNT_APP_NAME, WORDCOUNT_FLOW_NAME, WORDCOUNT_FLOWLET_NAME, 3));
    // verify
    int after = getFlowletInstances(TEST_NAMESPACE1, WORDCOUNT_APP_NAME, WORDCOUNT_FLOW_NAME, WORDCOUNT_FLOWLET_NAME);
    Assert.assertEquals(3, after);
    // invalid namespace
    Assert.assertEquals(404, requestFlowletInstances(TEST_NAMESPACE2, WORDCOUNT_APP_NAME, WORDCOUNT_FLOW_NAME, WORDCOUNT_FLOWLET_NAME, 3));
    // invalid app
    Assert.assertEquals(404, requestFlowletInstances(TEST_NAMESPACE1, APP_WITH_SERVICES_APP_ID, WORDCOUNT_FLOW_NAME, WORDCOUNT_FLOWLET_NAME, 3));
    // invalid flow
    Assert.assertEquals(404, requestFlowletInstances(TEST_NAMESPACE1, WORDCOUNT_APP_NAME, "random", WORDCOUNT_FLOWLET_NAME, 3));
    // invalid flowlet
    Assert.assertEquals(404, requestFlowletInstances(TEST_NAMESPACE1, WORDCOUNT_APP_NAME, WORDCOUNT_FLOW_NAME, "random", 3));
    // test live info
    // send invalid program type to live info
    response = sendLiveInfoRequest(TEST_NAMESPACE1, WORDCOUNT_APP_NAME, "random", WORDCOUNT_FLOW_NAME);
    Assert.assertEquals(405, response.getStatusLine().getStatusCode());
    // test valid live info
    JsonObject liveInfo = getLiveInfo(TEST_NAMESPACE1, WORDCOUNT_APP_NAME, ProgramType.FLOW.getCategoryName(), WORDCOUNT_FLOW_NAME);
    Assert.assertEquals(WORDCOUNT_APP_NAME, liveInfo.get("app").getAsString());
    Assert.assertEquals(ProgramType.FLOW.getPrettyName(), liveInfo.get("type").getAsString());
    Assert.assertEquals(WORDCOUNT_FLOW_NAME, liveInfo.get("id").getAsString());
    // start flow
    Id.Program wordcountFlow1 = Id.Program.from(TEST_NAMESPACE1, WORDCOUNT_APP_NAME, ProgramType.FLOW, WORDCOUNT_FLOW_NAME);
    startProgram(wordcountFlow1);
    liveInfo = getLiveInfo(TEST_NAMESPACE1, WORDCOUNT_APP_NAME, ProgramType.FLOW.getCategoryName(), WORDCOUNT_FLOW_NAME);
    Assert.assertEquals(WORDCOUNT_APP_NAME, liveInfo.get("app").getAsString());
    Assert.assertEquals(ProgramType.FLOW.getPrettyName(), liveInfo.get("type").getAsString());
    Assert.assertEquals(WORDCOUNT_FLOW_NAME, liveInfo.get("id").getAsString());
    Assert.assertEquals("in-memory", liveInfo.get("runtime").getAsString());
    // should not delete queues while running
    Assert.assertEquals(403, deleteQueues(TEST_NAMESPACE1, WORDCOUNT_APP_NAME, WORDCOUNT_FLOW_NAME));
    Assert.assertEquals(403, deleteQueues(TEST_NAMESPACE1));
    // stop
    stopProgram(wordcountFlow1);
    // delete queues
    Assert.assertEquals(200, deleteQueues(TEST_NAMESPACE1, WORDCOUNT_APP_NAME, WORDCOUNT_FLOW_NAME));
}
Also used : HttpResponse(org.apache.http.HttpResponse) JsonObject(com.google.gson.JsonObject) Id(co.cask.cdap.proto.Id) ProgramId(co.cask.cdap.proto.id.ProgramId) NamespaceId(co.cask.cdap.proto.id.NamespaceId) StreamId(co.cask.cdap.proto.id.StreamId) ApplicationId(co.cask.cdap.proto.id.ApplicationId) Constraint(co.cask.cdap.internal.schedule.constraint.Constraint) ServiceHttpEndpoint(co.cask.cdap.api.service.http.ServiceHttpEndpoint) ProtoConstraint(co.cask.cdap.proto.ProtoConstraint) ConcurrencyConstraint(co.cask.cdap.internal.app.runtime.schedule.constraint.ConcurrencyConstraint) Test(org.junit.Test)

Example 9 with Id

use of co.cask.cdap.proto.Id in project cdap by caskdata.

the class WorkflowHttpHandlerTest method testWorkflowSchedules.

@Ignore
@Test
public void testWorkflowSchedules() throws Exception {
    // Steps for the test:
    // 1. Deploy the app
    // 2. Verify the schedules
    // 3. Verify the history after waiting a while
    // 4. Suspend the schedule
    // 5. Verify there are no runs after the suspend by looking at the history
    // 6. Resume the schedule
    // 7. Verify there are runs after the resume by looking at the history
    String appName = AppWithSchedule.NAME;
    String workflowName = AppWithSchedule.WORKFLOW_NAME;
    String sampleSchedule = AppWithSchedule.SCHEDULE;
    // deploy app with schedule in namespace 2
    HttpResponse response = deploy(AppWithSchedule.class, Constants.Gateway.API_VERSION_3_TOKEN, TEST_NAMESPACE2);
    Assert.assertEquals(200, response.getStatusLine().getStatusCode());
    Id.Program programId = Id.Program.from(TEST_NAMESPACE2, appName, ProgramType.WORKFLOW, workflowName);
    Map<String, String> runtimeArguments = ImmutableMap.of("someKey", "someWorkflowValue", "workflowKey", "workflowValue");
    setAndTestRuntimeArgs(programId, runtimeArguments);
    // get schedules
    List<ScheduleDetail> schedules = getSchedules(TEST_NAMESPACE2, appName, workflowName);
    Assert.assertEquals(1, schedules.size());
    String scheduleName = schedules.get(0).getName();
    Assert.assertFalse(scheduleName.isEmpty());
    // get schedules in backward-compatible ScheduleSpecification form
    List<ScheduleSpecification> specs = getScheduleSpecs(TEST_NAMESPACE2, appName, workflowName);
    Assert.assertEquals(1, specs.size());
    String specName = specs.get(0).getSchedule().getName();
    Assert.assertEquals(scheduleName, specName);
    // TODO [CDAP-2327] Sagar Investigate why following check fails sometimes. Mostly test case issue.
    // List<ScheduledRuntime> previousRuntimes = getScheduledRunTime(programId, scheduleName, "previousruntime");
    // Assert.assertTrue(previousRuntimes.size() == 0);
    long current = System.currentTimeMillis();
    // Resume the schedule
    Assert.assertEquals(200, resumeSchedule(TEST_NAMESPACE2, appName, sampleSchedule));
    // Check schedule status
    assertSchedule(programId, scheduleName, true, 30, TimeUnit.SECONDS);
    List<ScheduledRuntime> runtimes = getScheduledRunTime(programId, true);
    String id = runtimes.get(0).getId();
    Assert.assertTrue(String.format("Expected schedule id '%s' to contain schedule name '%s'", id, scheduleName), id.contains(scheduleName));
    Long nextRunTime = runtimes.get(0).getTime();
    Assert.assertTrue(String.format("Expected nextRuntime '%s' to be greater than current runtime '%s'", nextRunTime, current), nextRunTime > current);
    // Verify that at least one program is completed
    verifyProgramRuns(programId, "completed");
    // Suspend the schedule
    Assert.assertEquals(200, suspendSchedule(TEST_NAMESPACE2, appName, scheduleName));
    // check paused state
    assertSchedule(programId, scheduleName, false, 30, TimeUnit.SECONDS);
    // check that there were at least 1 previous runs
    List<ScheduledRuntime> previousRuntimes = getScheduledRunTime(programId, false);
    int numRuns = previousRuntimes.size();
    Assert.assertTrue(String.format("After sleeping for two seconds, the schedule should have at least triggered " + "once, but found %s previous runs", numRuns), numRuns >= 1);
    // Verify no program running
    verifyNoRunWithStatus(programId, "running");
    // get number of completed runs after schedule is suspended
    int workflowRuns = getProgramRuns(programId, "completed").size();
    // verify that resuming the suspended schedule again has expected behavior (spawns new runs)
    Assert.assertEquals(200, resumeSchedule(TEST_NAMESPACE2, appName, scheduleName));
    //check scheduled state
    assertSchedule(programId, scheduleName, true, 30, TimeUnit.SECONDS);
    // Verify that the program ran after the schedule was resumed
    verifyProgramRuns(programId, "completed", workflowRuns);
    // Suspend the schedule
    Assert.assertEquals(200, suspendSchedule(TEST_NAMESPACE2, appName, scheduleName));
    //check paused state
    assertSchedule(programId, scheduleName, false, 30, TimeUnit.SECONDS);
    //Check status of a non existing schedule
    try {
        assertSchedule(programId, "invalid", true, 2, TimeUnit.SECONDS);
        Assert.fail();
    } catch (Exception e) {
    // expected
    }
    //Schedule operations using invalid namespace
    try {
        assertSchedule(Id.Program.from(TEST_NAMESPACE1, appName, ProgramType.WORKFLOW, workflowName), scheduleName, true, 2, TimeUnit.SECONDS);
        Assert.fail();
    } catch (Exception e) {
    // expected
    }
    Assert.assertEquals(404, suspendSchedule(TEST_NAMESPACE1, appName, scheduleName));
    Assert.assertEquals(404, resumeSchedule(TEST_NAMESPACE1, appName, scheduleName));
    verifyNoRunWithStatus(programId, "running");
    deleteApp(Id.Application.from(TEST_NAMESPACE2, AppWithSchedule.class.getSimpleName()), 200);
}
Also used : HttpResponse(org.apache.http.HttpResponse) IOException(java.io.IOException) Id(co.cask.cdap.proto.Id) ProgramId(co.cask.cdap.proto.id.ProgramId) ScheduleDetail(co.cask.cdap.proto.ScheduleDetail) ScheduledRuntime(co.cask.cdap.proto.ScheduledRuntime) ScheduleSpecification(co.cask.cdap.api.schedule.ScheduleSpecification) Ignore(org.junit.Ignore) Test(org.junit.Test)

Example 10 with Id

use of co.cask.cdap.proto.Id in project cdap by caskdata.

the class WorkflowHttpHandlerTest method testWorkflowTokenPut.

@Test
public void testWorkflowTokenPut() throws Exception {
    Assert.assertEquals(200, deploy(WorkflowTokenTestPutApp.class).getStatusLine().getStatusCode());
    Id.Application appId = Id.Application.from(Id.Namespace.DEFAULT, WorkflowTokenTestPutApp.NAME);
    Id.Workflow workflowId = Id.Workflow.from(appId, WorkflowTokenTestPutApp.WorkflowTokenTestPut.NAME);
    Id.Program mapReduceId = Id.Program.from(appId, ProgramType.MAPREDUCE, WorkflowTokenTestPutApp.RecordCounter.NAME);
    Id.Program sparkId = Id.Program.from(appId, ProgramType.SPARK, WorkflowTokenTestPutApp.SparkTestApp.NAME);
    // Start program with inputPath and outputPath arguments.
    // This should succeed. The programs inside the workflow will attempt to write to the workflow token
    // from the Mapper's and Reducer's methods as well as from a Spark closure, and they will throw an exception
    // if that succeeds.
    // The MapReduce's initialize will record the workflow run id in the token, and the destroy as well
    // as the mapper and the reducer will validate that they have the same workflow run id.
    String outputPath = new File(tmpFolder.newFolder(), "output").getAbsolutePath();
    startProgram(workflowId, ImmutableMap.of("inputPath", createInputForRecordVerification("sixthInput"), "outputPath", outputPath));
    waitState(workflowId, ProgramStatus.RUNNING.name());
    waitState(workflowId, ProgramStatus.STOPPED.name());
    // validate the completed workflow run and validate that it is the same as recorded in the token
    verifyProgramRuns(workflowId, "completed");
    List<RunRecord> runs = getProgramRuns(workflowId, "completed");
    Assert.assertEquals(1, runs.size());
    String wfRunId = runs.get(0).getPid();
    WorkflowTokenDetail tokenDetail = getWorkflowToken(workflowId, wfRunId, null, null);
    List<WorkflowTokenDetail.NodeValueDetail> details = tokenDetail.getTokenData().get("wf.runid");
    Assert.assertEquals(1, details.size());
    Assert.assertEquals(wfRunId, details.get(0).getValue());
    // validate that none of the mapper, reducer or spark closure were able to write to the token
    for (String key : new String[] { "mapper.initialize.key", "map.key", "reducer.initialize.key", "reduce.key", "some.key" }) {
        Assert.assertFalse(tokenDetail.getTokenData().containsKey(key));
    }
    List<RunRecord> sparkProgramRuns = getProgramRuns(sparkId, ProgramRunStatus.COMPLETED.name());
    Assert.assertEquals(1, sparkProgramRuns.size());
}
Also used : RunRecord(co.cask.cdap.proto.RunRecord) Id(co.cask.cdap.proto.Id) ProgramId(co.cask.cdap.proto.id.ProgramId) File(java.io.File) WorkflowTokenDetail(co.cask.cdap.proto.WorkflowTokenDetail) WorkflowTokenTestPutApp(co.cask.cdap.WorkflowTokenTestPutApp) Test(org.junit.Test)

Aggregations

Id (co.cask.cdap.proto.Id)24 NamespaceId (co.cask.cdap.proto.id.NamespaceId)19 IOException (java.io.IOException)15 Path (javax.ws.rs.Path)14 ArtifactId (co.cask.cdap.proto.id.ArtifactId)13 GET (javax.ws.rs.GET)6 AuditPolicy (co.cask.cdap.common.security.AuditPolicy)5 ProgramId (co.cask.cdap.proto.id.ProgramId)5 ArtifactId (co.cask.cdap.api.artifact.ArtifactId)4 PluginClass (co.cask.cdap.api.plugin.PluginClass)4 ArtifactNotFoundException (co.cask.cdap.common.ArtifactNotFoundException)4 BadRequestException (co.cask.cdap.common.BadRequestException)4 ArtifactDescriptor (co.cask.cdap.internal.app.runtime.artifact.ArtifactDescriptor)4 ArtifactSummary (co.cask.cdap.api.artifact.ArtifactSummary)3 ArtifactVersion (co.cask.cdap.api.artifact.ArtifactVersion)3 ArtifactAlreadyExistsException (co.cask.cdap.common.ArtifactAlreadyExistsException)3 ArtifactRangeNotFoundException (co.cask.cdap.common.ArtifactRangeNotFoundException)3 NotFoundException (co.cask.cdap.common.NotFoundException)3 ArtifactDetail (co.cask.cdap.internal.app.runtime.artifact.ArtifactDetail)3 PluginNotExistsException (co.cask.cdap.internal.app.runtime.plugin.PluginNotExistsException)3