Search in sources :

Example 1 with CloseableClassLoader

use of io.cdap.cdap.api.artifact.CloseableClassLoader in project cdap by caskdata.

the class ArtifactClassLoaderFactory method createClassLoader.

/**
 * Unpack the given {@code artifactLocation} to a temporary directory and call
 * {@link #createClassLoader(File)} to create the {@link ClassLoader}.
 *
 * @param artifactLocation the location of the artifact to create the classloader from
 * @return a closeable classloader based off the specified artifact; on closing the returned {@link ClassLoader},
 *         all temporary resources created for the classloader will be removed
 * @see #createClassLoader(File)
 */
CloseableClassLoader createClassLoader(Location artifactLocation, EntityImpersonator entityImpersonator) {
    try {
        ClassLoaderFolder classLoaderFolder = entityImpersonator.impersonate(() -> BundleJarUtil.prepareClassLoaderFolder(artifactLocation, () -> DirUtils.createTempDir(tmpDir)));
        CloseableClassLoader classLoader = createClassLoader(classLoaderFolder.getDir());
        return new CloseableClassLoader(classLoader, () -> {
            Closeables.closeQuietly(classLoader);
            Closeables.closeQuietly(classLoaderFolder);
        });
    } catch (Exception e) {
        throw Throwables.propagate(e);
    }
}
Also used : CloseableClassLoader(io.cdap.cdap.api.artifact.CloseableClassLoader) ClassLoaderFolder(io.cdap.cdap.common.lang.jar.ClassLoaderFolder)

Example 2 with CloseableClassLoader

use of io.cdap.cdap.api.artifact.CloseableClassLoader in project cdap by caskdata.

the class SystemAppTask method run.

@Override
public void run(RunnableTaskContext context) throws Exception {
    ArtifactId systemAppArtifactId = context.getArtifactId();
    if (systemAppArtifactId == null) {
        throw new IllegalArgumentException("Missing artifactId from the system app task request");
    }
    LOG.debug("Received system app task for artifact {}", systemAppArtifactId);
    Injector injector = createInjector(cConf);
    ArtifactRepository artifactRepository = injector.getInstance(ArtifactRepository.class);
    Impersonator impersonator = injector.getInstance(Impersonator.class);
    String systemAppNamespace = context.getNamespace();
    Id.Artifact artifactId = Id.Artifact.from(Id.Namespace.from(systemAppNamespace), systemAppArtifactId.getName(), systemAppArtifactId.getVersion());
    ArtifactLocalizerClient localizerClient = injector.getInstance(ArtifactLocalizerClient.class);
    File artifactLocation = localizerClient.getUnpackedArtifactLocation(Artifacts.toProtoArtifactId(new NamespaceId(systemAppNamespace), systemAppArtifactId));
    EntityImpersonator classLoaderImpersonator = new EntityImpersonator(artifactId.toEntityId(), impersonator);
    try (CloseableClassLoader artifactClassLoader = artifactRepository.createArtifactClassLoader(new ArtifactDescriptor(artifactId.getNamespace().getId(), artifactId.toArtifactId(), Locations.toLocation(artifactLocation)), classLoaderImpersonator);
        SystemAppTaskContext systemAppTaskContext = buildTaskSystemAppContext(injector, systemAppNamespace, systemAppArtifactId, artifactClassLoader)) {
        RunnableTaskRequest taskRequest = context.getEmbeddedRequest();
        String taskClassName = taskRequest.getClassName();
        if (taskClassName == null) {
            LOG.debug("No system app task to execute");
            return;
        }
        LOG.debug("Requested to run system app task {}", taskClassName);
        Class<?> clazz = artifactClassLoader.loadClass(taskClassName);
        if (!(RunnableTask.class.isAssignableFrom(clazz))) {
            throw new ClassCastException(String.format("%s is not a RunnableTask", taskClassName));
        }
        LOG.debug("Launching system app task {}", taskClassName);
        RunnableTask runnableTask = (RunnableTask) injector.getInstance(clazz);
        RunnableTaskContext runnableTaskContext = new RunnableTaskContext(taskRequest.getParam().getSimpleParam(), null, null, null, systemAppTaskContext) {

            @Override
            public void writeResult(byte[] data) throws IOException {
                context.writeResult(data);
            }

            @Override
            public void setTerminateOnComplete(boolean terminate) {
                context.setTerminateOnComplete(terminate);
            }

            @Override
            public boolean isTerminateOnComplete() {
                return context.isTerminateOnComplete();
            }
        };
        runnableTask.run(runnableTaskContext);
        LOG.debug("System app task completed {}", taskClassName);
    }
}
Also used : ArtifactId(io.cdap.cdap.api.artifact.ArtifactId) EntityImpersonator(io.cdap.cdap.security.impersonation.EntityImpersonator) SystemAppTaskContext(io.cdap.cdap.api.service.worker.SystemAppTaskContext) ArtifactRepository(io.cdap.cdap.internal.app.runtime.artifact.ArtifactRepository) CloseableClassLoader(io.cdap.cdap.api.artifact.CloseableClassLoader) Impersonator(io.cdap.cdap.security.impersonation.Impersonator) EntityImpersonator(io.cdap.cdap.security.impersonation.EntityImpersonator) ArtifactDescriptor(io.cdap.cdap.internal.app.runtime.artifact.ArtifactDescriptor) Injector(com.google.inject.Injector) RunnableTaskContext(io.cdap.cdap.api.service.worker.RunnableTaskContext) NamespaceId(io.cdap.cdap.proto.id.NamespaceId) Id(io.cdap.cdap.common.id.Id) ArtifactId(io.cdap.cdap.api.artifact.ArtifactId) NamespaceId(io.cdap.cdap.proto.id.NamespaceId) RunnableTask(io.cdap.cdap.api.service.worker.RunnableTask) ArtifactLocalizerClient(io.cdap.cdap.internal.app.worker.sidecar.ArtifactLocalizerClient) File(java.io.File) RunnableTaskRequest(io.cdap.cdap.api.service.worker.RunnableTaskRequest)

Example 3 with CloseableClassLoader

use of io.cdap.cdap.api.artifact.CloseableClassLoader in project cdap by caskdata.

the class DeployDatasetModulesStage method process.

/**
 * Deploys dataset modules specified in the given application spec.
 *
 * @param input An instance of {@link ApplicationDeployable}
 */
@Override
public void process(ApplicationDeployable input) throws Exception {
    Map<String, String> datasetModules = input.getSpecification().getDatasetModules();
    if (allowCustomModule) {
        KerberosPrincipalId ownerPrincipal = input.getOwnerPrincipal();
        // get the authorizing user
        String authorizingUser = AuthorizationUtil.getAppAuthorizingUser(ownerAdmin, authenticationContext, input.getApplicationId(), ownerPrincipal);
        EntityImpersonator classLoaderImpersonator = new EntityImpersonator(input.getArtifactId(), impersonator);
        try (CloseableClassLoader classLoader = artifactRepository.createArtifactClassLoader(new ArtifactDescriptor(input.getArtifactId().getNamespace(), input.getArtifactId().toApiArtifactId(), input.getArtifactLocation()), classLoaderImpersonator)) {
            deployer.deployModules(input.getApplicationId().getParent(), datasetModules, input.getArtifactLocation(), classLoader, authorizingUser);
        }
    } else if (deployer.hasNonSystemDatasetModules(datasetModules)) {
        throw new IllegalStateException("Custom dataset module is not supported. " + "One of the dataset module is a custom module: " + datasetModules);
    }
    // Emit the input to next stage.
    emit(input);
}
Also used : ArtifactDescriptor(io.cdap.cdap.internal.app.runtime.artifact.ArtifactDescriptor) EntityImpersonator(io.cdap.cdap.security.impersonation.EntityImpersonator) CloseableClassLoader(io.cdap.cdap.api.artifact.CloseableClassLoader) KerberosPrincipalId(io.cdap.cdap.proto.id.KerberosPrincipalId)

Example 4 with CloseableClassLoader

use of io.cdap.cdap.api.artifact.CloseableClassLoader in project cdap by caskdata.

the class ApplicationLifecycleService method updateApplicationInternal.

/**
 * Updates an application config by applying given update actions. The app should know how to apply these actions
 * to its config.
 */
private void updateApplicationInternal(ApplicationId appId, @Nullable String currentConfigStr, ProgramTerminator programTerminator, ArtifactDetail artifactDetail, List<ApplicationConfigUpdateAction> updateActions, Set<ArtifactScope> allowedArtifactScopes, boolean allowSnapshot, @Nullable KerberosPrincipalId ownerPrincipal, boolean updateSchedules) throws Exception {
    ApplicationClass appClass = Iterables.getFirst(artifactDetail.getMeta().getClasses().getApps(), null);
    if (appClass == null) {
        // This should never happen.
        throw new IllegalStateException(String.format("No application class found in artifact '%s' in namespace '%s'.", artifactDetail.getDescriptor().getArtifactId(), appId.getParent()));
    }
    io.cdap.cdap.proto.id.ArtifactId artifactId = Artifacts.toProtoArtifactId(appId.getParent(), artifactDetail.getDescriptor().getArtifactId());
    EntityImpersonator classLoaderImpersonator = new EntityImpersonator(artifactId, this.impersonator);
    String updatedAppConfig;
    DefaultApplicationUpdateContext updateContext = new DefaultApplicationUpdateContext(appId.getParent(), appId, artifactDetail.getDescriptor().getArtifactId(), artifactRepository, currentConfigStr, updateActions, allowedArtifactScopes, allowSnapshot);
    try (CloseableClassLoader artifactClassLoader = artifactRepository.createArtifactClassLoader(artifactDetail.getDescriptor(), classLoaderImpersonator)) {
        Object appMain = artifactClassLoader.loadClass(appClass.getClassName()).newInstance();
        // Run config update logic for the application to generate updated config.
        if (!(appMain instanceof Application)) {
            throw new IllegalStateException(String.format("Application main class is of invalid type: %s", appMain.getClass().getName()));
        }
        Application app = (Application) appMain;
        Type configType = Artifacts.getConfigType(app.getClass());
        if (!app.isUpdateSupported()) {
            String errorMessage = String.format("Application %s does not support update.", appId);
            throw new UnsupportedOperationException(errorMessage);
        }
        ApplicationUpdateResult<?> updateResult = app.updateConfig(updateContext);
        updatedAppConfig = GSON.toJson(updateResult.getNewConfig(), configType);
    }
    // Deploy application with with potentially new app config and new artifact.
    AppDeploymentInfo deploymentInfo = new AppDeploymentInfo(artifactId, artifactDetail.getDescriptor().getLocation(), appId.getParent(), appClass, appId.getApplication(), appId.getVersion(), updatedAppConfig, ownerPrincipal, updateSchedules, null);
    Manager<AppDeploymentInfo, ApplicationWithPrograms> manager = managerFactory.create(programTerminator);
    // TODO: (CDAP-3258) Manager needs MUCH better error handling.
    ApplicationWithPrograms applicationWithPrograms;
    try {
        applicationWithPrograms = manager.deploy(deploymentInfo).get();
    } catch (ExecutionException e) {
        Throwables.propagateIfPossible(e.getCause(), Exception.class);
        throw Throwables.propagate(e.getCause());
    }
    adminEventPublisher.publishAppCreation(applicationWithPrograms.getApplicationId(), applicationWithPrograms.getSpecification());
}
Also used : DefaultApplicationUpdateContext(io.cdap.cdap.internal.app.DefaultApplicationUpdateContext) EntityImpersonator(io.cdap.cdap.security.impersonation.EntityImpersonator) ApplicationClass(io.cdap.cdap.api.artifact.ApplicationClass) CloseableClassLoader(io.cdap.cdap.api.artifact.CloseableClassLoader) ApplicationNotFoundException(io.cdap.cdap.common.ApplicationNotFoundException) CapabilityNotAvailableException(io.cdap.cdap.internal.capability.CapabilityNotAvailableException) IOException(java.io.IOException) CannotBeDeletedException(io.cdap.cdap.common.CannotBeDeletedException) ExecutionException(java.util.concurrent.ExecutionException) AccessException(io.cdap.cdap.api.security.AccessException) JsonIOException(com.google.gson.JsonIOException) InvalidArtifactException(io.cdap.cdap.common.InvalidArtifactException) ArtifactAlreadyExistsException(io.cdap.cdap.common.ArtifactAlreadyExistsException) NotFoundException(io.cdap.cdap.common.NotFoundException) ArtifactNotFoundException(io.cdap.cdap.common.ArtifactNotFoundException) EntityType(io.cdap.cdap.proto.element.EntityType) Type(java.lang.reflect.Type) ProgramType(io.cdap.cdap.proto.ProgramType) AppDeploymentInfo(io.cdap.cdap.internal.app.deploy.pipeline.AppDeploymentInfo) ApplicationWithPrograms(io.cdap.cdap.internal.app.deploy.pipeline.ApplicationWithPrograms) ExecutionException(java.util.concurrent.ExecutionException) Application(io.cdap.cdap.api.app.Application)

Example 5 with CloseableClassLoader

use of io.cdap.cdap.api.artifact.CloseableClassLoader in project cdap by caskdata.

the class DefaultArtifactInspector 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 parentDescriptor {@link ArtifactDescriptor} of parent and grandparent (if any) artifacts.
 * @param additionalPlugins Additional plugin classes
 * @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.
 */
@Override
public ArtifactClassesWithMetadata inspectArtifact(Id.Artifact artifactId, File artifactFile, List<ArtifactDescriptor> parentDescriptor, Set<PluginClass> additionalPlugins) 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);
    EntityImpersonator entityImpersonator = new EntityImpersonator(artifactId.toEntityId(), impersonator);
    Path stageDir = Files.createTempDirectory(tmpDir, artifactFile.getName());
    try (ClassLoaderFolder clFolder = BundleJarUtil.prepareClassLoaderFolder(artifactLocation, () -> Files.createTempDirectory(stageDir, "unpacked-").toFile());
        CloseableClassLoader parentClassLoader = createParentClassLoader(parentDescriptor, entityImpersonator);
        CloseableClassLoader artifactClassLoader = artifactClassLoaderFactory.createClassLoader(clFolder.getDir());
        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);
        List<MetadataMutation> mutations = new ArrayList<>();
        inspectPlugins(builder, artifactFile, artifactId.toEntityId(), pluginInstantiator, additionalPlugins, mutations);
        return new ArtifactClassesWithMetadata(builder.build(), mutations);
    } 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) EntityImpersonator(io.cdap.cdap.security.impersonation.EntityImpersonator) ArrayList(java.util.ArrayList) ZipException(java.util.zip.ZipException) CloseableClassLoader(io.cdap.cdap.api.artifact.CloseableClassLoader) IOException(java.io.IOException) ClassLoaderFolder(io.cdap.cdap.common.lang.jar.ClassLoaderFolder) MetadataMutation(io.cdap.cdap.spi.metadata.MetadataMutation) ArtifactClasses(io.cdap.cdap.api.artifact.ArtifactClasses) EOFException(java.io.EOFException) PluginInstantiator(io.cdap.cdap.internal.app.runtime.plugin.PluginInstantiator) InvalidArtifactException(io.cdap.cdap.common.InvalidArtifactException) Location(org.apache.twill.filesystem.Location)

Aggregations

CloseableClassLoader (io.cdap.cdap.api.artifact.CloseableClassLoader)10 EntityImpersonator (io.cdap.cdap.security.impersonation.EntityImpersonator)6 ClassLoaderFolder (io.cdap.cdap.common.lang.jar.ClassLoaderFolder)4 DirectoryClassLoader (io.cdap.cdap.common.lang.DirectoryClassLoader)3 ArtifactDescriptor (io.cdap.cdap.internal.app.runtime.artifact.ArtifactDescriptor)3 Application (io.cdap.cdap.api.app.Application)2 InvalidArtifactException (io.cdap.cdap.common.InvalidArtifactException)2 IOException (java.io.IOException)2 JsonIOException (com.google.gson.JsonIOException)1 Injector (com.google.inject.Injector)1 ApplicationClass (io.cdap.cdap.api.artifact.ApplicationClass)1 ArtifactClasses (io.cdap.cdap.api.artifact.ArtifactClasses)1 ArtifactId (io.cdap.cdap.api.artifact.ArtifactId)1 ArtifactInfo (io.cdap.cdap.api.artifact.ArtifactInfo)1 AccessException (io.cdap.cdap.api.security.AccessException)1 RunnableTask (io.cdap.cdap.api.service.worker.RunnableTask)1 RunnableTaskContext (io.cdap.cdap.api.service.worker.RunnableTaskContext)1 RunnableTaskRequest (io.cdap.cdap.api.service.worker.RunnableTaskRequest)1 SystemAppTaskContext (io.cdap.cdap.api.service.worker.SystemAppTaskContext)1 ConfigResponse (io.cdap.cdap.app.deploy.ConfigResponse)1