Search in sources :

Example 16 with InvalidArtifactException

use of co.cask.cdap.common.InvalidArtifactException in project cdap by caskdata.

the class AppLifecycleHttpHandler method deployAppFromArtifact.

// normally we wouldn't want to use a body consumer but would just want to read the request body directly
// since it wont be big. But the deploy app API has one path with different behavior based on content type
// the other behavior requires a BodyConsumer and only have one method per path is allowed,
// so we have to use a BodyConsumer
private BodyConsumer deployAppFromArtifact(final ApplicationId appId) throws IOException {
    // createTempFile() needs a prefix of at least 3 characters
    return new AbstractBodyConsumer(File.createTempFile("apprequest-" + appId, ".json", tmpDir)) {

        @Override
        protected void onFinish(HttpResponder responder, File uploadedFile) {
            try (FileReader fileReader = new FileReader(uploadedFile)) {
                AppRequest<?> appRequest = DECODE_GSON.fromJson(fileReader, AppRequest.class);
                ArtifactSummary artifactSummary = appRequest.getArtifact();
                KerberosPrincipalId ownerPrincipalId = appRequest.getOwnerPrincipal() == null ? null : new KerberosPrincipalId(appRequest.getOwnerPrincipal());
                // if we don't null check, it gets serialized to "null"
                String configString = appRequest.getConfig() == null ? null : GSON.toJson(appRequest.getConfig());
                try {
                    applicationLifecycleService.deployApp(appId.getParent(), appId.getApplication(), appId.getVersion(), artifactSummary, configString, createProgramTerminator(), ownerPrincipalId, appRequest.canUpdateSchedules());
                } catch (DatasetManagementException e) {
                    if (e.getCause() instanceof UnauthorizedException) {
                        throw (UnauthorizedException) e.getCause();
                    } else {
                        throw e;
                    }
                }
                responder.sendString(HttpResponseStatus.OK, "Deploy Complete");
            } catch (ArtifactNotFoundException e) {
                responder.sendString(HttpResponseStatus.NOT_FOUND, e.getMessage());
            } catch (ConflictException e) {
                responder.sendString(HttpResponseStatus.CONFLICT, e.getMessage());
            } catch (UnauthorizedException e) {
                responder.sendString(HttpResponseStatus.FORBIDDEN, e.getMessage());
            } catch (InvalidArtifactException e) {
                responder.sendString(HttpResponseStatus.BAD_REQUEST, e.getMessage());
            } catch (IOException e) {
                LOG.error("Error reading request body for creating app {}.", appId);
                responder.sendString(HttpResponseStatus.INTERNAL_SERVER_ERROR, String.format("Error while reading json request body for app %s.", appId));
            } catch (Exception e) {
                LOG.error("Deploy failure", e);
                responder.sendString(HttpResponseStatus.BAD_REQUEST, e.getMessage());
            }
        }
    };
}
Also used : HttpResponder(co.cask.http.HttpResponder) ConflictException(co.cask.cdap.common.ConflictException) WriteConflictException(co.cask.cdap.internal.app.runtime.artifact.WriteConflictException) IOException(java.io.IOException) ApplicationNotFoundException(co.cask.cdap.common.ApplicationNotFoundException) NamespaceNotFoundException(co.cask.cdap.common.NamespaceNotFoundException) ArtifactNotFoundException(co.cask.cdap.common.ArtifactNotFoundException) ArtifactAlreadyExistsException(co.cask.cdap.common.ArtifactAlreadyExistsException) ConflictException(co.cask.cdap.common.ConflictException) BadRequestException(co.cask.cdap.common.BadRequestException) UnauthorizedException(co.cask.cdap.security.spi.authorization.UnauthorizedException) DatasetManagementException(co.cask.cdap.api.dataset.DatasetManagementException) WriteConflictException(co.cask.cdap.internal.app.runtime.artifact.WriteConflictException) JsonSyntaxException(com.google.gson.JsonSyntaxException) IOException(java.io.IOException) InvalidArtifactException(co.cask.cdap.common.InvalidArtifactException) ExecutionException(java.util.concurrent.ExecutionException) NotFoundException(co.cask.cdap.common.NotFoundException) DatasetManagementException(co.cask.cdap.api.dataset.DatasetManagementException) ArtifactSummary(co.cask.cdap.api.artifact.ArtifactSummary) AbstractBodyConsumer(co.cask.cdap.common.http.AbstractBodyConsumer) UnauthorizedException(co.cask.cdap.security.spi.authorization.UnauthorizedException) FileReader(java.io.FileReader) File(java.io.File) KerberosPrincipalId(co.cask.cdap.proto.id.KerberosPrincipalId) ArtifactNotFoundException(co.cask.cdap.common.ArtifactNotFoundException) InvalidArtifactException(co.cask.cdap.common.InvalidArtifactException)

Example 17 with InvalidArtifactException

use of co.cask.cdap.common.InvalidArtifactException in project cdap by caskdata.

the class AppLifecycleHttpHandler method updateApp.

/**
 * Updates an existing application.
 */
@POST
@Path("/apps/{app-id}/update")
@AuditPolicy(AuditDetail.REQUEST_BODY)
public void updateApp(FullHttpRequest request, HttpResponder responder, @PathParam("namespace-id") final String namespaceId, @PathParam("app-id") final String appName) throws NotFoundException, BadRequestException, UnauthorizedException, IOException {
    ApplicationId appId = validateApplicationId(namespaceId, appName);
    AppRequest appRequest;
    try (Reader reader = new InputStreamReader(new ByteBufInputStream(request.content()), StandardCharsets.UTF_8)) {
        appRequest = DECODE_GSON.fromJson(reader, AppRequest.class);
    } catch (IOException e) {
        LOG.error("Error reading request to update app {} in namespace {}.", appName, namespaceId, e);
        throw new IOException("Error reading request body.");
    } catch (JsonSyntaxException e) {
        throw new BadRequestException("Request body is invalid json: " + e.getMessage());
    }
    try {
        applicationLifecycleService.updateApp(appId, appRequest, createProgramTerminator());
        responder.sendString(HttpResponseStatus.OK, "Update complete.");
    } catch (InvalidArtifactException e) {
        throw new BadRequestException(e.getMessage());
    } catch (ConflictException e) {
        responder.sendString(HttpResponseStatus.CONFLICT, e.getMessage());
    } catch (NotFoundException | UnauthorizedException e) {
        throw e;
    } catch (Exception e) {
        // this is the same behavior as deploy app pipeline, but this is bad behavior. Error handling needs improvement.
        LOG.error("Deploy failure", e);
        responder.sendString(HttpResponseStatus.BAD_REQUEST, e.getMessage());
    }
}
Also used : InputStreamReader(java.io.InputStreamReader) ConflictException(co.cask.cdap.common.ConflictException) WriteConflictException(co.cask.cdap.internal.app.runtime.artifact.WriteConflictException) Reader(java.io.Reader) InputStreamReader(java.io.InputStreamReader) FileReader(java.io.FileReader) ApplicationNotFoundException(co.cask.cdap.common.ApplicationNotFoundException) NamespaceNotFoundException(co.cask.cdap.common.NamespaceNotFoundException) ArtifactNotFoundException(co.cask.cdap.common.ArtifactNotFoundException) NotFoundException(co.cask.cdap.common.NotFoundException) ByteBufInputStream(io.netty.buffer.ByteBufInputStream) IOException(java.io.IOException) ApplicationNotFoundException(co.cask.cdap.common.ApplicationNotFoundException) NamespaceNotFoundException(co.cask.cdap.common.NamespaceNotFoundException) ArtifactNotFoundException(co.cask.cdap.common.ArtifactNotFoundException) ArtifactAlreadyExistsException(co.cask.cdap.common.ArtifactAlreadyExistsException) ConflictException(co.cask.cdap.common.ConflictException) BadRequestException(co.cask.cdap.common.BadRequestException) UnauthorizedException(co.cask.cdap.security.spi.authorization.UnauthorizedException) DatasetManagementException(co.cask.cdap.api.dataset.DatasetManagementException) WriteConflictException(co.cask.cdap.internal.app.runtime.artifact.WriteConflictException) JsonSyntaxException(com.google.gson.JsonSyntaxException) IOException(java.io.IOException) InvalidArtifactException(co.cask.cdap.common.InvalidArtifactException) ExecutionException(java.util.concurrent.ExecutionException) NotFoundException(co.cask.cdap.common.NotFoundException) AppRequest(co.cask.cdap.proto.artifact.AppRequest) JsonSyntaxException(com.google.gson.JsonSyntaxException) UnauthorizedException(co.cask.cdap.security.spi.authorization.UnauthorizedException) BadRequestException(co.cask.cdap.common.BadRequestException) ApplicationId(co.cask.cdap.proto.id.ApplicationId) InvalidArtifactException(co.cask.cdap.common.InvalidArtifactException) Path(javax.ws.rs.Path) AuditPolicy(co.cask.cdap.common.security.AuditPolicy) POST(javax.ws.rs.POST)

Example 18 with InvalidArtifactException

use of co.cask.cdap.common.InvalidArtifactException in project cdap by caskdata.

the class ArtifactInspector method inspectArtifact.

/**
 * Inspect the given artifact to determine the classes contained in the artifact.
 *
 * @param artifactId the id of the artifact to inspect
 * @param artifactFile the artifact file
 * @param parentClassLoader the parent classloader to use when inspecting plugins contained in the artifact.
 *                          For example, a ProgramClassLoader created from the artifact the input artifact extends
 * @return metadata about the classes contained in the artifact
 * @throws IOException if there was an exception opening the jar file
 * @throws InvalidArtifactException if the artifact is invalid. For example, if the application main class is not
 *                                  actually an Application.
 */
ArtifactClasses inspectArtifact(Id.Artifact artifactId, File artifactFile, @Nullable ClassLoader parentClassLoader) throws IOException, InvalidArtifactException {
    Path tmpDir = Paths.get(cConf.get(Constants.CFG_LOCAL_DATA_DIR), cConf.get(Constants.AppFabric.TEMP_DIR)).toAbsolutePath();
    Files.createDirectories(tmpDir);
    Location artifactLocation = Locations.toLocation(artifactFile);
    Path stageDir = Files.createTempDirectory(tmpDir, artifactFile.getName());
    try {
        File unpackedDir = BundleJarUtil.unJar(artifactLocation, Files.createTempDirectory(stageDir, "unpacked-").toFile());
        try (CloseableClassLoader artifactClassLoader = artifactClassLoaderFactory.createClassLoader(unpackedDir);
            PluginInstantiator pluginInstantiator = new PluginInstantiator(cConf, parentClassLoader == null ? artifactClassLoader : parentClassLoader, Files.createTempDirectory(stageDir, "plugins-").toFile(), false)) {
            pluginInstantiator.addArtifact(artifactLocation, artifactId.toArtifactId());
            ArtifactClasses.Builder builder = inspectApplications(artifactId, ArtifactClasses.builder(), artifactLocation, artifactClassLoader);
            return inspectPlugins(builder, artifactFile, artifactId.toArtifactId(), pluginInstantiator).build();
        }
    } catch (EOFException | ZipException e) {
        throw new InvalidArtifactException("Artifact " + artifactId + " is not a valid zip file.", e);
    } finally {
        try {
            DirUtils.deleteDirectoryContents(stageDir.toFile());
        } catch (IOException e) {
            LOG.warn("Exception raised while deleting directory {}", stageDir, e);
        }
    }
}
Also used : Path(java.nio.file.Path) ArtifactClasses(co.cask.cdap.api.artifact.ArtifactClasses) EOFException(java.io.EOFException) PluginInstantiator(co.cask.cdap.internal.app.runtime.plugin.PluginInstantiator) ZipException(java.util.zip.ZipException) CloseableClassLoader(co.cask.cdap.api.artifact.CloseableClassLoader) IOException(java.io.IOException) JarFile(java.util.jar.JarFile) File(java.io.File) InvalidArtifactException(co.cask.cdap.common.InvalidArtifactException) Location(org.apache.twill.filesystem.Location)

Example 19 with InvalidArtifactException

use of co.cask.cdap.common.InvalidArtifactException in project cdap by caskdata.

the class InMemoryConfigurator method getSpecJson.

private <T extends Config> String getSpecJson(Application<T> app) throws Exception {
    // This Gson cannot be static since it is used to deserialize user class.
    // Gson will keep a static map to class, hence will leak the classloader
    Gson gson = new GsonBuilder().registerTypeAdapterFactory(new CaseInsensitiveEnumTypeAdapterFactory()).create();
    // Now, we call configure, which returns application specification.
    DefaultAppConfigurer configurer;
    File tempDir = DirUtils.createTempDir(baseUnpackDir);
    try (PluginInstantiator pluginInstantiator = new PluginInstantiator(cConf, app.getClass().getClassLoader(), tempDir)) {
        configurer = new DefaultAppConfigurer(appNamespace, artifactId, app, configString, artifactRepository, pluginInstantiator);
        T appConfig;
        Type configType = Artifacts.getConfigType(app.getClass());
        if (configString.isEmpty()) {
            // noinspection unchecked
            appConfig = ((Class<T>) configType).newInstance();
        } else {
            try {
                appConfig = gson.fromJson(configString, configType);
            } catch (JsonSyntaxException e) {
                throw new IllegalArgumentException("Invalid JSON configuration was provided. Please check the syntax.", e);
            }
        }
        try {
            ClassLoader oldClassLoader = ClassLoaders.setContextClassLoader(new CombineClassLoader(null, app.getClass().getClassLoader(), getClass().getClassLoader()));
            try {
                app.configure(configurer, new DefaultApplicationContext<>(appConfig));
            } finally {
                ClassLoaders.setContextClassLoader(oldClassLoader);
            }
        } catch (Throwable t) {
            Throwable rootCause = Throwables.getRootCause(t);
            if (rootCause instanceof ClassNotFoundException) {
                // Heuristic to provide better error message
                String missingClass = rootCause.getMessage();
                // If the missing class has "spark" in the name, try to see if Spark is available
                if (missingClass.startsWith("org.apache.spark.") || missingClass.startsWith("co.cask.cdap.api.spark.")) {
                    // Try to load the SparkContext class, which should be available if Spark is available in the platform
                    try {
                        artifactClassLoader.loadClass("org.apache.spark.SparkContext");
                    } catch (ClassNotFoundException e) {
                        // Spark is not available, it is most likely caused by missing Spark in the platform
                        throw new IllegalStateException("Missing Spark related class " + missingClass + ". It may be caused by unavailability of Spark. " + "Please verify environment variable " + Constants.SPARK_HOME + " is set correctly", t);
                    }
                    // Spark is available, can be caused by incompatible Spark version
                    throw new InvalidArtifactException("Missing Spark related class " + missingClass + ". Configured to use Spark located at " + System.getenv(Constants.SPARK_HOME) + ", which may be incompatible with the one required by the application", t);
                }
                // then the missing class is most likely due to some missing library in the artifact jar
                throw new InvalidArtifactException("Missing class " + missingClass + ". It may be caused by missing dependency jar(s) in the artifact jar.", t);
            }
            throw t;
        }
    } finally {
        try {
            DirUtils.deleteDirectoryContents(tempDir);
        } catch (IOException e) {
            LOG.warn("Exception raised when deleting directory {}", tempDir, e);
        }
    }
    ApplicationSpecification specification = configurer.createSpecification(applicationName, applicationVersion);
    // TODO: The SchemaGenerator should be injected
    return ApplicationSpecificationAdapter.create(new ReflectionSchemaGenerator()).toJson(specification);
}
Also used : ApplicationSpecification(co.cask.cdap.api.app.ApplicationSpecification) GsonBuilder(com.google.gson.GsonBuilder) DefaultAppConfigurer(co.cask.cdap.app.DefaultAppConfigurer) Gson(com.google.gson.Gson) IOException(java.io.IOException) ReflectionSchemaGenerator(co.cask.cdap.internal.io.ReflectionSchemaGenerator) CombineClassLoader(co.cask.cdap.common.lang.CombineClassLoader) Type(java.lang.reflect.Type) CaseInsensitiveEnumTypeAdapterFactory(co.cask.cdap.common.io.CaseInsensitiveEnumTypeAdapterFactory) JsonSyntaxException(com.google.gson.JsonSyntaxException) CombineClassLoader(co.cask.cdap.common.lang.CombineClassLoader) PluginInstantiator(co.cask.cdap.internal.app.runtime.plugin.PluginInstantiator) File(java.io.File) InvalidArtifactException(co.cask.cdap.common.InvalidArtifactException)

Example 20 with InvalidArtifactException

use of co.cask.cdap.common.InvalidArtifactException in project cdap by caskdata.

the class ApplicationLifecycleService method deployAppAndArtifact.

/**
 * Deploy an application by first adding the application jar to the artifact repository, then creating an application
 * using that newly added artifact.
 *
 * @param namespace the namespace to deploy the application and artifact in
 * @param appName the name of the app. If null, the name will be set based on the application spec
 * @param artifactId the id of the artifact to add and create the application from
 * @param jarFile the application jar to add as an artifact and create the application from
 * @param configStr the configuration to send to the application when generating the application specification
 * @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 InvalidArtifactException the the artifact is invalid. For example, if it does not contain any app classes
 * @throws ArtifactAlreadyExistsException if the specified artifact already exists
 * @throws IOException if there was an IO error writing the artifact
 */
public ApplicationWithPrograms deployAppAndArtifact(NamespaceId namespace, @Nullable String appName, Id.Artifact artifactId, File jarFile, @Nullable String configStr, @Nullable KerberosPrincipalId ownerPrincipal, ProgramTerminator programTerminator, boolean updateSchedules) throws Exception {
    ArtifactDetail artifactDetail = artifactRepository.addArtifact(artifactId, jarFile);
    try {
        return deployApp(namespace, appName, null, configStr, programTerminator, artifactDetail, ownerPrincipal, updateSchedules);
    } catch (Exception e) {
        // to the state we were in before this call.
        try {
            artifactRepository.deleteArtifact(artifactId);
        } catch (IOException e2) {
            // if the delete fails, nothing we can do, just log it and continue on
            LOG.warn("Failed to delete artifact {} after deployment of artifact and application failed.", artifactId, e2);
            e.addSuppressed(e2);
        }
        throw e;
    }
}
Also used : IOException(java.io.IOException) CannotBeDeletedException(co.cask.cdap.common.CannotBeDeletedException) ApplicationNotFoundException(co.cask.cdap.common.ApplicationNotFoundException) ArtifactNotFoundException(co.cask.cdap.common.ArtifactNotFoundException) ArtifactAlreadyExistsException(co.cask.cdap.common.ArtifactAlreadyExistsException) IOException(java.io.IOException) InvalidArtifactException(co.cask.cdap.common.InvalidArtifactException) ExecutionException(java.util.concurrent.ExecutionException) NotFoundException(co.cask.cdap.common.NotFoundException) ArtifactDetail(co.cask.cdap.internal.app.runtime.artifact.ArtifactDetail)

Aggregations

InvalidArtifactException (co.cask.cdap.common.InvalidArtifactException)21 IOException (java.io.IOException)9 File (java.io.File)8 ApplicationNotFoundException (co.cask.cdap.common.ApplicationNotFoundException)7 ArtifactRange (co.cask.cdap.api.artifact.ArtifactRange)6 ArtifactAlreadyExistsException (co.cask.cdap.common.ArtifactAlreadyExistsException)6 ArtifactNotFoundException (co.cask.cdap.common.ArtifactNotFoundException)6 NotFoundException (co.cask.cdap.common.NotFoundException)6 HashSet (java.util.HashSet)6 ExecutionException (java.util.concurrent.ExecutionException)6 JsonSyntaxException (com.google.gson.JsonSyntaxException)5 BadRequestException (co.cask.cdap.common.BadRequestException)4 ConflictException (co.cask.cdap.common.ConflictException)4 NamespaceNotFoundException (co.cask.cdap.common.NamespaceNotFoundException)4 WriteConflictException (co.cask.cdap.internal.app.runtime.artifact.WriteConflictException)4 UnauthorizedException (co.cask.cdap.security.spi.authorization.UnauthorizedException)4 VisibleForTesting (com.google.common.annotations.VisibleForTesting)4 Location (org.apache.twill.filesystem.Location)4 ArtifactId (co.cask.cdap.api.artifact.ArtifactId)3 ArtifactVersion (co.cask.cdap.api.artifact.ArtifactVersion)3