Search in sources :

Example 81 with BadRequestException

use of io.cdap.cdap.common.BadRequestException in project cdap by cdapio.

the class ProgramLifecycleService method issueStop.

/**
 * Issues a command to stop the specified {@link RunId} of the specified {@link ProgramId} and returns a
 * {@link ListenableFuture} with the {@link ProgramRunId} for the runs that were stopped.
 * Clients can wait for completion of the {@link ListenableFuture}.
 *
 * @param programId the {@link ProgramId program} to issue a stop for
 * @param runId the runId of the program run to stop. If null, all runs of the program as returned by
 *              {@link ProgramRuntimeService} are stopped.
 * @return a list of {@link ListenableFuture} with the {@link ProgramRunId} that clients can wait on for stop
 *         to complete.
 * @throws NotFoundException if the app, program or run was not found
 * @throws BadRequestException if an attempt is made to stop a program that is either not running or
 *                             was started by a workflow
 * @throws UnauthorizedException if the user issuing the command is not authorized to stop the program. To stop a
 *                               program, a user requires {@link ApplicationPermission#EXECUTE} permission on
 *                               the program.
 */
public List<ListenableFuture<ProgramRunId>> issueStop(ProgramId programId, @Nullable String runId) throws Exception {
    accessEnforcer.enforce(programId, authenticationContext.getPrincipal(), ApplicationPermission.EXECUTE);
    // See if the program is running as per the runtime service
    Map<RunId, RuntimeInfo> runtimeInfos = findRuntimeInfo(programId, runId);
    Map<ProgramRunId, RunRecordDetail> activeRunRecords = getActiveRuns(programId, runId);
    if (runtimeInfos.isEmpty() && activeRunRecords.isEmpty()) {
        // Error out if no run information from runtime service and from run record
        Store.ensureProgramExists(programId, store.getApplication(programId.getParent()));
        throw new BadRequestException(String.format("Program '%s' is not running.", programId));
    }
    // Stop the running program based on a combination of runtime info and run record
    // It's possible that some of them are not yet available from the runtimeService due to timing
    // differences between the run record was created vs being added to runtimeService
    // So we retry in a loop for up to 3 seconds max to cater for those cases
    Set<String> pendingStops = Stream.concat(runtimeInfos.keySet().stream().map(RunId::getId), activeRunRecords.keySet().stream().map(ProgramRunId::getRun)).collect(Collectors.toSet());
    List<ListenableFuture<ProgramRunId>> futures = new ArrayList<>();
    Stopwatch stopwatch = new Stopwatch().start();
    Set<ProgramRunId> cancelledProvisionRuns = new HashSet<>();
    while (!pendingStops.isEmpty() && stopwatch.elapsedTime(TimeUnit.SECONDS) < 3L) {
        Iterator<String> iterator = pendingStops.iterator();
        while (iterator.hasNext()) {
            ProgramRunId activeRunId = programId.run(iterator.next());
            RunRecordDetail runRecord = activeRunRecords.get(activeRunId);
            if (runRecord == null) {
                runRecord = store.getRun(activeRunId);
            }
            // Check if the program is actually started from workflow and the workflow is running
            if (runRecord != null && runRecord.getProperties().containsKey("workflowrunid") && runRecord.getStatus().equals(ProgramRunStatus.RUNNING)) {
                String workflowRunId = runRecord.getProperties().get("workflowrunid");
                throw new BadRequestException(String.format("Cannot stop the program '%s' started by the Workflow " + "run '%s'. Please stop the Workflow.", activeRunId, workflowRunId));
            }
            RuntimeInfo runtimeInfo = runtimeService.lookup(programId, RunIds.fromString(activeRunId.getRun()));
            // if there is a runtimeInfo, the run is in the 'starting' state or later
            if (runtimeInfo != null) {
                ListenableFuture<ProgramController> future = runtimeInfo.getController().stop();
                futures.add(Futures.transform(future, ProgramController::getProgramRunId));
                iterator.remove();
                // if it was in this set, it means we cancelled a task, but it had already sent a PROVISIONED message
                // by the time we cancelled it. We then waited for it to show up in the runtime service and got here.
                // We added a future for this run in the lines above, but we don't want to add another duplicate future
                // at the end of this loop, so remove this run from the cancelled provision runs.
                cancelledProvisionRuns.remove(activeRunId);
            } else {
                // if there is no runtimeInfo, the run could be in the provisioning state.
                Optional<ProvisioningTaskInfo> cancelledInfo = provisioningService.cancelProvisionTask(activeRunId);
                cancelledInfo.ifPresent(taskInfo -> {
                    cancelledProvisionRuns.add(activeRunId);
                    // This state check is to handle a race condition where we cancel the provision task, but not in time
                    // to prevent it from sending the PROVISIONED notification.
                    // If the notification was sent, but not yet consumed, we are *not* done stopping the run.
                    // We have to wait for the notification to be consumed, which will start the run, and place the controller
                    // in the runtimeService. The next time we loop, we can find it in the runtimeService and tell it to stop.
                    // If the notification was not sent, then we *are* done stopping the run.
                    // Therefore, if the state is CREATED, we don't remove it from the iterator so that the run will get
                    // checked again in the next loop, when we may get the controller from the runtimeService to stop it.
                    // No other task states have this race condition, as the PROVISIONED notification is only sent
                    // after the state transitions to CREATED. Therefore it is safe to remove the runId from the iterator,
                    // as we know we are done stopping it.
                    ProvisioningOp.Status taskState = taskInfo.getProvisioningOp().getStatus();
                    if (taskState != ProvisioningOp.Status.CREATED) {
                        iterator.remove();
                    }
                });
            }
        }
        if (!pendingStops.isEmpty()) {
            // If not able to stop all of them, it means there were some runs that didn't have a runtime info and
            // didn't have a provisioning task. This can happen if the run was already finished, or the run transitioned
            // from the provisioning state to the starting state during this stop operation.
            // We'll get the active runs again and filter it by the pending stops. Stop will be retried for those.
            Set<String> finalPendingStops = pendingStops;
            activeRunRecords = getActiveRuns(programId, runId).entrySet().stream().filter(e -> finalPendingStops.contains(e.getKey().getRun())).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
            pendingStops = activeRunRecords.keySet().stream().map(ProgramRunId::getRun).collect(Collectors.toSet());
            if (!pendingStops.isEmpty()) {
                TimeUnit.MILLISECONDS.sleep(200);
            }
        }
    }
    for (ProgramRunId cancelledProvisionRun : cancelledProvisionRuns) {
        SettableFuture<ProgramRunId> future = SettableFuture.create();
        future.set(cancelledProvisionRun);
        futures.add(future);
    }
    return futures;
}
Also used : ProgramController(io.cdap.cdap.app.runtime.ProgramController) RuntimeInfo(io.cdap.cdap.app.runtime.ProgramRuntimeService.RuntimeInfo) RunRecordDetail(io.cdap.cdap.internal.app.store.RunRecordDetail) ArrayList(java.util.ArrayList) Stopwatch(com.google.common.base.Stopwatch) ProvisioningTaskInfo(io.cdap.cdap.internal.provision.ProvisioningTaskInfo) LogEntry(org.apache.twill.api.logging.LogEntry) BadRequestException(io.cdap.cdap.common.BadRequestException) ListenableFuture(com.google.common.util.concurrent.ListenableFuture) ProgramRunId(io.cdap.cdap.proto.id.ProgramRunId) ProvisioningOp(io.cdap.cdap.internal.provision.ProvisioningOp) RunId(org.apache.twill.api.RunId) ProgramRunId(io.cdap.cdap.proto.id.ProgramRunId) HashSet(java.util.HashSet) LinkedHashSet(java.util.LinkedHashSet)

Example 82 with BadRequestException

use of io.cdap.cdap.common.BadRequestException in project cdap by cdapio.

the class AppMetadataStore method getProgramRunCounts.

/**
 * Get the run counts of the given program collections.
 *
 * @param programIds the collection of program ids to get the program
 * @return the map of the program id to its run count
 */
public Map<ProgramId, Long> getProgramRunCounts(Collection<ProgramId> programIds) throws BadRequestException, IOException {
    if (programIds.size() > 100) {
        throw new BadRequestException(String.format("%d programs found, the maximum number supported is 100", programIds.size()));
    }
    Map<ProgramId, Long> result = programIds.stream().collect(Collectors.toMap(id -> id, id -> 0L, (v1, v2) -> 0L, LinkedHashMap::new));
    List<List<Field<?>>> multiKeys = programIds.stream().map(id -> getProgramCountPrimaryKeys(TYPE_COUNT, id)).collect(Collectors.toList());
    for (StructuredRow row : getProgramCountsTable().multiRead(multiKeys)) {
        ProgramId programId = getApplicationIdFromRow(row).program(ProgramType.valueOf(row.getString(StoreDefinition.AppMetadataStore.PROGRAM_TYPE_FIELD)), row.getString(StoreDefinition.AppMetadataStore.PROGRAM_FIELD));
        result.put(programId, row.getLong(StoreDefinition.AppMetadataStore.COUNTS));
    }
    return result;
}
Also used : Arrays(java.util.Arrays) NamespaceId(io.cdap.cdap.proto.id.NamespaceId) StructuredRow(io.cdap.cdap.spi.data.StructuredRow) BiFunction(java.util.function.BiFunction) LoggerFactory(org.slf4j.LoggerFactory) Bytes(io.cdap.cdap.api.common.Bytes) Fields(io.cdap.cdap.spi.data.table.field.Fields) GsonBuilder(com.google.gson.GsonBuilder) ProgramRunCluster(io.cdap.cdap.proto.ProgramRunCluster) ScanApplicationsRequest(io.cdap.cdap.app.store.ScanApplicationsRequest) DatasetId(io.cdap.cdap.proto.id.DatasetId) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) Gson(com.google.gson.Gson) Map(java.util.Map) Field(io.cdap.cdap.spi.data.table.field.Field) RunId(org.apache.twill.api.RunId) BasicWorkflowToken(io.cdap.cdap.internal.app.runtime.workflow.BasicWorkflowToken) SortOrder(io.cdap.cdap.spi.data.SortOrder) BasicThrowable(io.cdap.cdap.proto.BasicThrowable) StoreDefinition(io.cdap.cdap.store.StoreDefinition) ImmutableMap(com.google.common.collect.ImmutableMap) Predicate(java.util.function.Predicate) Collection(java.util.Collection) ApplicationSpecification(io.cdap.cdap.api.app.ApplicationSpecification) Set(java.util.Set) ProgramRunStatus(io.cdap.cdap.proto.ProgramRunStatus) StructuredTableContext(io.cdap.cdap.spi.data.StructuredTableContext) Collectors(java.util.stream.Collectors) Sets(com.google.common.collect.Sets) ApplicationSpecificationAdapter(io.cdap.cdap.internal.app.ApplicationSpecificationAdapter) Objects(java.util.Objects) AbstractCloseableIterator(io.cdap.cdap.api.dataset.lib.AbstractCloseableIterator) List(java.util.List) Type(java.lang.reflect.Type) Optional(java.util.Optional) Constants(io.cdap.cdap.common.conf.Constants) ProfileId(io.cdap.cdap.proto.id.ProfileId) ProgramOptionConstants(io.cdap.cdap.internal.app.runtime.ProgramOptionConstants) ApplicationId(io.cdap.cdap.proto.id.ApplicationId) HashMap(java.util.HashMap) TypeToken(com.google.common.reflect.TypeToken) ProgramType(io.cdap.cdap.proto.ProgramType) Function(java.util.function.Function) JsonReader(com.google.gson.stream.JsonReader) ArrayList(java.util.ArrayList) HashSet(java.util.HashSet) LinkedHashMap(java.util.LinkedHashMap) WorkflowToken(io.cdap.cdap.api.workflow.WorkflowToken) ProgramRunId(io.cdap.cdap.proto.id.ProgramRunId) ImmutableList(com.google.common.collect.ImmutableList) BiConsumer(java.util.function.BiConsumer) SystemArguments(io.cdap.cdap.internal.app.runtime.SystemArguments) LinkedHashSet(java.util.LinkedHashSet) Nullable(javax.annotation.Nullable) WorkflowNodeStateDetail(io.cdap.cdap.proto.WorkflowNodeStateDetail) Logger(org.slf4j.Logger) RunIds(io.cdap.cdap.common.app.RunIds) ApplicationFilter(io.cdap.cdap.app.store.ApplicationFilter) ProgramId(io.cdap.cdap.proto.id.ProgramId) IOException(java.io.IOException) BadRequestException(io.cdap.cdap.common.BadRequestException) CloseableIterator(io.cdap.cdap.api.dataset.lib.CloseableIterator) ProgramRunClusterStatus(io.cdap.cdap.proto.ProgramRunClusterStatus) TableNotFoundException(io.cdap.cdap.spi.data.TableNotFoundException) TimeUnit(java.util.concurrent.TimeUnit) Consumer(java.util.function.Consumer) JsonToken(com.google.gson.stream.JsonToken) StringReader(java.io.StringReader) StructuredTable(io.cdap.cdap.spi.data.StructuredTable) Range(io.cdap.cdap.spi.data.table.field.Range) Preconditions(com.google.common.base.Preconditions) VisibleForTesting(com.google.common.annotations.VisibleForTesting) Collections(java.util.Collections) ArtifactId(io.cdap.cdap.api.artifact.ArtifactId) StructuredRow(io.cdap.cdap.spi.data.StructuredRow) BadRequestException(io.cdap.cdap.common.BadRequestException) List(java.util.List) ArrayList(java.util.ArrayList) ImmutableList(com.google.common.collect.ImmutableList) ProgramId(io.cdap.cdap.proto.id.ProgramId)

Example 83 with BadRequestException

use of io.cdap.cdap.common.BadRequestException in project cdap by cdapio.

the class AbstractNamespaceClient method create.

@Override
public void create(NamespaceMeta metadata) throws Exception {
    URL url = resolve(String.format("namespaces/%s", metadata.getName()));
    HttpResponse response = execute(HttpRequest.put(url).withBody(GSON.toJson(metadata)).build());
    String responseBody = response.getResponseBodyAsString();
    if (response.getResponseCode() == HttpURLConnection.HTTP_OK) {
        if (responseBody.equals(String.format("Namespace '%s' already exists.", metadata.getName()))) {
            throw new NamespaceAlreadyExistsException(metadata.getNamespaceId());
        }
        return;
    }
    if (response.getResponseCode() == HttpURLConnection.HTTP_BAD_REQUEST) {
        throw new BadRequestException("Bad request: " + responseBody);
    }
    throw new IOException(String.format("Cannot create namespace %s. Reason: %s", metadata.getName(), responseBody));
}
Also used : HttpResponse(io.cdap.common.http.HttpResponse) BadRequestException(io.cdap.cdap.common.BadRequestException) NamespaceAlreadyExistsException(io.cdap.cdap.common.NamespaceAlreadyExistsException) IOException(java.io.IOException) URL(java.net.URL)

Example 84 with BadRequestException

use of io.cdap.cdap.common.BadRequestException in project cdap by cdapio.

the class PreferencesService method setConfig.

/**
 * Validate the profile status is enabled and set the preferences
 */
private void setConfig(ProfileStore profileStore, PreferencesTable preferencesTable, EntityId entityId, Map<String, String> propertyMap) throws NotFoundException, ProfileConflictException, BadRequestException, IOException {
    boolean isInstanceLevel = entityId.getEntityType().equals(EntityType.INSTANCE);
    NamespaceId namespaceId = isInstanceLevel ? NamespaceId.SYSTEM : ((NamespacedEntityId) entityId).getNamespaceId();
    // validate the profile and publish the necessary metadata change if the profile exists in the property
    Optional<ProfileId> profile = SystemArguments.getProfileIdFromArgs(namespaceId, propertyMap);
    if (profile.isPresent()) {
        ProfileId profileId = profile.get();
        // setting a USER scoped profile
        if (isInstanceLevel && !propertyMap.get(SystemArguments.PROFILE_NAME).startsWith(EntityScope.SYSTEM.name())) {
            throw new BadRequestException(String.format("Cannot set profile %s at the instance level. " + "Only system profiles can be set at the instance level. " + "The profile property must look like SYSTEM:[profile-name]", propertyMap.get(SystemArguments.PROFILE_NAME)));
        }
        if (profileStore.getProfile(profileId).getStatus() == ProfileStatus.DISABLED) {
            throw new ProfileConflictException(String.format("Profile %s in namespace %s is disabled. It cannot be " + "assigned to any programs or schedules", profileId.getProfile(), profileId.getNamespace()), profileId);
        }
    }
    // need to get old property and check if it contains profile information
    Map<String, String> oldProperties = preferencesTable.getPreferences(entityId).getProperties();
    // get the old profile information from the previous properties
    Optional<ProfileId> oldProfile = SystemArguments.getProfileIdFromArgs(namespaceId, oldProperties);
    long seqId = preferencesTable.setPreferences(entityId, propertyMap);
    // After everything is set, publish the update message and add the association if profile is present
    if (profile.isPresent()) {
        profileStore.addProfileAssignment(profile.get(), entityId);
    }
    // if old properties has the profile, remove the association
    if (oldProfile.isPresent()) {
        profileStore.removeProfileAssignment(oldProfile.get(), entityId);
    }
    // if new profiles do not have profile information but old profiles have, it is same as deletion of the profile
    if (profile.isPresent()) {
        adminEventPublisher.publishProfileAssignment(entityId, seqId);
    } else if (oldProfile.isPresent()) {
        adminEventPublisher.publishProfileUnAssignment(entityId, seqId);
    }
}
Also used : ProfileId(io.cdap.cdap.proto.id.ProfileId) BadRequestException(io.cdap.cdap.common.BadRequestException) NamespaceId(io.cdap.cdap.proto.id.NamespaceId) ProfileConflictException(io.cdap.cdap.common.ProfileConflictException)

Example 85 with BadRequestException

use of io.cdap.cdap.common.BadRequestException in project cdap by cdapio.

the class RuntimeClient method uploadSparkEventLogs.

/**
 * Uploads Spark program event logs to the runtime service.
 *
 * @param programRunId the program run id of the program run
 * @param eventFile the local file containing the event logs
 * @throws IOException if failed to send the event logs
 * @throws ServiceUnavailableException if the service is not available
 */
public void uploadSparkEventLogs(ProgramRunId programRunId, File eventFile) throws IOException {
    String path = String.format("%s/apps/%s/versions/%s/%s/%s/runs/%s/spark-event-logs/%s", programRunId.getNamespace(), programRunId.getApplication(), programRunId.getVersion(), programRunId.getType().getCategoryName(), programRunId.getProgram(), programRunId.getRun(), eventFile.getName());
    // Stream out the messages
    HttpURLConnection urlConn = remoteClient.openConnection(HttpMethod.POST, path);
    try {
        urlConn.setChunkedStreamingMode(CHUNK_SIZE);
        urlConn.setRequestProperty(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_OCTET_STREAM);
        // No need to use compression since event files should have compression enabled
        try (OutputStream os = urlConn.getOutputStream()) {
            Files.copy(eventFile.toPath(), os);
            throwIfError(programRunId, urlConn);
        } catch (BadRequestException e) {
            // Just treat bad request as IOException since it won't be retriable
            throw new IOException(e);
        }
    } finally {
        closeURLConnection(urlConn);
    }
}
Also used : HttpURLConnection(java.net.HttpURLConnection) OutputStream(java.io.OutputStream) GZIPOutputStream(java.util.zip.GZIPOutputStream) BadRequestException(io.cdap.cdap.common.BadRequestException) IOException(java.io.IOException)

Aggregations

BadRequestException (io.cdap.cdap.common.BadRequestException)188 Path (javax.ws.rs.Path)68 NamespaceId (io.cdap.cdap.proto.id.NamespaceId)54 IOException (java.io.IOException)46 JsonSyntaxException (com.google.gson.JsonSyntaxException)44 NotFoundException (io.cdap.cdap.common.NotFoundException)42 ApplicationId (io.cdap.cdap.proto.id.ApplicationId)42 POST (javax.ws.rs.POST)42 HttpResponse (io.cdap.common.http.HttpResponse)36 ByteBufInputStream (io.netty.buffer.ByteBufInputStream)34 URL (java.net.URL)34 ProgramType (io.cdap.cdap.proto.ProgramType)30 InputStreamReader (java.io.InputStreamReader)28 Reader (java.io.Reader)28 ArrayList (java.util.ArrayList)28 AuditPolicy (io.cdap.cdap.common.security.AuditPolicy)26 ProgramId (io.cdap.cdap.proto.id.ProgramId)26 ServiceUnavailableException (io.cdap.cdap.common.ServiceUnavailableException)24 GET (javax.ws.rs.GET)24 ProgramRunId (io.cdap.cdap.proto.id.ProgramRunId)22