Search in sources :

Example 11 with DatasetModuleConflictException

use of io.cdap.cdap.data2.datafabric.dataset.type.DatasetModuleConflictException in project cdap by caskdata.

the class DatasetTypeService method addModule.

/**
   * Adds a new {@link DatasetModule}.
   *
   * @param datasetModuleId the {@link DatasetModuleId} for the module to be added
   * @param className the module class name specified in the HTTP header
   * @param forceUpdate if true, an update will be allowed even if there are conflicts with other modules, or if
   *                     removal of a type would break other modules' dependencies
   * @return a {@link BodyConsumer} to upload the module jar in chunks
   * @throws NotFoundException if the namespace in which the module is being added is not found
   * @throws IOException if there are issues while performing I/O like creating temporary directories, moving/unpacking
   *                      module jar files
   * @throws DatasetModuleConflictException if #forceUpdate is {@code false}, and there are conflicts with other modules
   */
BodyConsumer addModule(final DatasetModuleId datasetModuleId, final String className, final boolean forceUpdate) throws Exception {
    NamespaceId namespaceId = datasetModuleId.getParent();
    final Principal principal = authenticationContext.getPrincipal();
    // enforce that the principal has WRITE access on the namespace
    authorizationEnforcer.enforce(namespaceId, principal, Action.WRITE);
    if (NamespaceId.SYSTEM.equals(namespaceId)) {
        throw new UnauthorizedException(String.format("Cannot add module '%s' to '%s' namespace.", datasetModuleId.getModule(), datasetModuleId.getNamespace()));
    }
    ensureNamespaceExists(namespaceId);
    // It is now determined that a new dataset module will be deployed. First grant privileges, then deploy the module.
    // If creation fails, revoke the granted privileges. This ensures that just like delete, there may be orphaned
    // privileges in rare scenarios, but there can never be orphaned datasets.
    // If the module previously existed and was deleted, but revoking privileges somehow failed, there may be orphaned
    // privileges for the module. Revoke them first, so no users unintentionally get privileges on the dataset.
    revokeAllPrivilegesOnModule(datasetModuleId);
    grantAllPrivilegesOnModule(datasetModuleId, principal);
    try {
        return createModuleConsumer(datasetModuleId, className, forceUpdate, principal);
    } catch (Exception e) {
        revokeAllPrivilegesOnModule(datasetModuleId);
        throw e;
    }
}
Also used : UnauthorizedException(co.cask.cdap.security.spi.authorization.UnauthorizedException) NamespaceId(co.cask.cdap.proto.id.NamespaceId) Principal(co.cask.cdap.proto.security.Principal) NamespaceNotFoundException(co.cask.cdap.common.NamespaceNotFoundException) ConflictException(co.cask.cdap.common.ConflictException) DatasetModuleConflictException(co.cask.cdap.data2.datafabric.dataset.type.DatasetModuleConflictException) DatasetTypeNotFoundException(co.cask.cdap.common.DatasetTypeNotFoundException) UnauthorizedException(co.cask.cdap.security.spi.authorization.UnauthorizedException) DatasetModuleNotFoundException(co.cask.cdap.common.DatasetModuleNotFoundException) IOException(java.io.IOException) DatasetModuleCannotBeDeletedException(co.cask.cdap.common.DatasetModuleCannotBeDeletedException) NotFoundException(co.cask.cdap.common.NotFoundException)

Example 12 with DatasetModuleConflictException

use of io.cdap.cdap.data2.datafabric.dataset.type.DatasetModuleConflictException in project cdap by caskdata.

the class DatasetTypeService method delete.

/**
   * Deletes the specified {@link DatasetModuleId}
   */
void delete(DatasetModuleId datasetModuleId) throws Exception {
    NamespaceId namespaceId = datasetModuleId.getParent();
    if (NamespaceId.SYSTEM.equals(namespaceId)) {
        throw new UnauthorizedException(String.format("Cannot delete module '%s' from '%s' namespace.", datasetModuleId.getModule(), datasetModuleId.getNamespace()));
    }
    ensureNamespaceExists(namespaceId);
    DatasetModuleMeta moduleMeta = typeManager.getModule(datasetModuleId);
    if (moduleMeta == null) {
        throw new DatasetModuleNotFoundException(datasetModuleId);
    }
    Principal principal = authenticationContext.getPrincipal();
    authorizationEnforcer.enforce(datasetModuleId, principal, Action.ADMIN);
    try {
        typeManager.deleteModule(datasetModuleId);
    } catch (DatasetModuleConflictException e) {
        throw new DatasetModuleCannotBeDeletedException(datasetModuleId, e.getMessage());
    }
    // revoke all privileges on the module to be deleted
    revokeAllPrivilegesOnModule(datasetModuleId, moduleMeta);
}
Also used : DatasetModuleNotFoundException(co.cask.cdap.common.DatasetModuleNotFoundException) DatasetModuleConflictException(co.cask.cdap.data2.datafabric.dataset.type.DatasetModuleConflictException) DatasetModuleMeta(co.cask.cdap.proto.DatasetModuleMeta) UnauthorizedException(co.cask.cdap.security.spi.authorization.UnauthorizedException) NamespaceId(co.cask.cdap.proto.id.NamespaceId) DatasetModuleCannotBeDeletedException(co.cask.cdap.common.DatasetModuleCannotBeDeletedException) Principal(co.cask.cdap.proto.security.Principal)

Example 13 with DatasetModuleConflictException

use of io.cdap.cdap.data2.datafabric.dataset.type.DatasetModuleConflictException in project cdap by caskdata.

the class DefaultDatasetTypeService method delete.

/**
 * Deletes the specified {@link DatasetModuleId}
 */
@Override
public void delete(DatasetModuleId datasetModuleId) throws Exception {
    NamespaceId namespaceId = datasetModuleId.getParent();
    if (NamespaceId.SYSTEM.equals(namespaceId)) {
        throw new UnsupportedOperationException(String.format("Cannot delete module '%s' from '%s' namespace.", datasetModuleId.getModule(), datasetModuleId.getNamespace()));
    }
    ensureNamespaceExists(namespaceId);
    DatasetModuleMeta moduleMeta = typeManager.getModule(datasetModuleId);
    if (moduleMeta == null) {
        throw new DatasetModuleNotFoundException(datasetModuleId);
    }
    try {
        typeManager.deleteModule(datasetModuleId);
    } catch (DatasetModuleConflictException e) {
        throw new DatasetModuleCannotBeDeletedException(datasetModuleId, e.getMessage());
    }
}
Also used : DatasetModuleNotFoundException(co.cask.cdap.common.DatasetModuleNotFoundException) DatasetModuleConflictException(co.cask.cdap.data2.datafabric.dataset.type.DatasetModuleConflictException) DatasetModuleMeta(co.cask.cdap.proto.DatasetModuleMeta) NamespaceId(co.cask.cdap.proto.id.NamespaceId) DatasetModuleCannotBeDeletedException(co.cask.cdap.common.DatasetModuleCannotBeDeletedException)

Example 14 with DatasetModuleConflictException

use of io.cdap.cdap.data2.datafabric.dataset.type.DatasetModuleConflictException in project cdap by caskdata.

the class DefaultDatasetTypeService method createModuleConsumer.

private AbstractBodyConsumer createModuleConsumer(final DatasetModuleId datasetModuleId, final String className, final boolean forceUpdate) throws IOException, NotFoundException {
    final NamespaceId namespaceId = datasetModuleId.getParent();
    final Location namespaceHomeLocation;
    try {
        namespaceHomeLocation = impersonator.doAs(namespaceId, new Callable<Location>() {

            @Override
            public Location call() throws Exception {
                return namespacedLocationFactory.get(namespaceId);
            }
        });
    } catch (Exception e) {
        // the only checked exception that the callable throws is IOException
        Throwables.propagateIfInstanceOf(e, IOException.class);
        throw Throwables.propagate(e);
    }
    // verify namespace directory exists
    if (!namespaceHomeLocation.exists()) {
        String msg = String.format("Home directory %s for namespace %s not found", namespaceHomeLocation, namespaceId);
        LOG.debug(msg);
        throw new NotFoundException(msg);
    }
    // Store uploaded content to a local temp file
    String namespacesDir = cConf.get(Constants.Namespace.NAMESPACES_DIR);
    File localDataDir = new File(cConf.get(Constants.CFG_LOCAL_DATA_DIR));
    File namespaceBase = new File(localDataDir, namespacesDir);
    File tempDir = new File(new File(namespaceBase, datasetModuleId.getNamespace()), cConf.get(Constants.AppFabric.TEMP_DIR)).getAbsoluteFile();
    if (!DirUtils.mkdirs(tempDir)) {
        throw new IOException("Could not create temporary directory at: " + tempDir);
    }
    return new AbstractBodyConsumer(File.createTempFile("dataset-", ".jar", tempDir)) {

        @Override
        protected void onFinish(HttpResponder responder, File uploadedFile) throws Exception {
            if (className == null) {
                // We have to delay until body upload is completed due to the fact that not all client is
                // requesting with "Expect: 100-continue" header and the client library we have cannot handle
                // connection close, and yet be able to read response reliably.
                // In longer term we should fix the client, as well as the netty-http server. However, since
                // this handler will be gone in near future, it's ok to have this workaround.
                responder.sendString(HttpResponseStatus.BAD_REQUEST, "Required header 'class-name' is absent.");
                return;
            }
            LOG.debug("Adding module {}, class name: {}", datasetModuleId, className);
            String dataFabricDir = cConf.get(Constants.Dataset.Manager.OUTPUT_DIR);
            String moduleName = datasetModuleId.getModule();
            Location archiveDir = namespaceHomeLocation.append(dataFabricDir).append(moduleName).append(Constants.ARCHIVE_DIR);
            String archiveName = moduleName + ".jar";
            Location archive = archiveDir.append(archiveName);
            // Copy uploaded content to a temporary location
            Location tmpLocation = archive.getTempFile(".tmp");
            try {
                Locations.mkdirsIfNotExists(archiveDir);
                LOG.debug("Copy from {} to {}", uploadedFile, tmpLocation);
                Files.copy(uploadedFile, Locations.newOutputSupplier(tmpLocation));
                // Finally, move archive to final location
                LOG.debug("Storing module {} jar at {}", datasetModuleId, archive);
                if (tmpLocation.renameTo(archive) == null) {
                    throw new IOException(String.format("Could not move archive from location: %s, to location: %s", tmpLocation, archive));
                }
                typeManager.addModule(datasetModuleId, className, archive, forceUpdate);
                // todo: response with DatasetModuleMeta of just added module (and log this info)
                // Ideally this should have been done before, but we cannot grant privileges on types until they've been
                // added to the type MDS. First revoke any orphaned privileges for types left behind by past failed revokes
                LOG.info("Added module {}", datasetModuleId);
                responder.sendStatus(HttpResponseStatus.OK);
            } catch (Exception e) {
                // In case copy to temporary file failed, or rename failed
                try {
                    tmpLocation.delete();
                } catch (IOException ex) {
                    LOG.warn("Failed to cleanup temporary location {}", tmpLocation);
                }
                if (e instanceof DatasetModuleConflictException) {
                    responder.sendString(HttpResponseStatus.CONFLICT, e.getMessage());
                } else {
                    throw e;
                }
            }
        }
    };
}
Also used : HttpResponder(co.cask.http.HttpResponder) DatasetModuleConflictException(co.cask.cdap.data2.datafabric.dataset.type.DatasetModuleConflictException) AbstractBodyConsumer(co.cask.cdap.common.http.AbstractBodyConsumer) NamespaceNotFoundException(co.cask.cdap.common.NamespaceNotFoundException) DatasetTypeNotFoundException(co.cask.cdap.common.DatasetTypeNotFoundException) DatasetModuleNotFoundException(co.cask.cdap.common.DatasetModuleNotFoundException) NotFoundException(co.cask.cdap.common.NotFoundException) NamespaceId(co.cask.cdap.proto.id.NamespaceId) IOException(java.io.IOException) File(java.io.File) Callable(java.util.concurrent.Callable) NamespaceNotFoundException(co.cask.cdap.common.NamespaceNotFoundException) ConflictException(co.cask.cdap.common.ConflictException) DatasetModuleConflictException(co.cask.cdap.data2.datafabric.dataset.type.DatasetModuleConflictException) DatasetTypeNotFoundException(co.cask.cdap.common.DatasetTypeNotFoundException) DatasetModuleNotFoundException(co.cask.cdap.common.DatasetModuleNotFoundException) IOException(java.io.IOException) DatasetModuleCannotBeDeletedException(co.cask.cdap.common.DatasetModuleCannotBeDeletedException) NotFoundException(co.cask.cdap.common.NotFoundException) Location(org.apache.twill.filesystem.Location)

Example 15 with DatasetModuleConflictException

use of io.cdap.cdap.data2.datafabric.dataset.type.DatasetModuleConflictException in project cdap by caskdata.

the class DefaultDatasetTypeService method deployExtensionModules.

private void deployExtensionModules() {
    // adding any defined extension modules to be available in dataset manager service
    for (Map.Entry<String, DatasetModule> module : extensionModules.entrySet()) {
        try {
            // NOTE: we assume extension modules are always in classpath, hence passing null for jar location
            // NOTE: we add extension modules in the system namespace
            DatasetModuleId theModule = NamespaceId.SYSTEM.datasetModule(module.getKey());
            typeManager.addModule(theModule, module.getValue().getClass().getName(), null, false);
        } catch (DatasetModuleConflictException e) {
            // perfectly fine: we need to add the modules only the very first time service is started
            LOG.debug("Not adding {} extension module: it already exists", module.getKey());
        } catch (Throwable th) {
            LOG.error("Failed to add {} extension module. Aborting.", module.getKey(), th);
            throw Throwables.propagate(th);
        }
    }
}
Also used : DatasetModuleId(co.cask.cdap.proto.id.DatasetModuleId) DatasetModuleConflictException(co.cask.cdap.data2.datafabric.dataset.type.DatasetModuleConflictException) Map(java.util.Map) ImmutableMap(com.google.common.collect.ImmutableMap) LinkedHashMap(java.util.LinkedHashMap) DatasetModule(co.cask.cdap.api.dataset.module.DatasetModule)

Aggregations

IOException (java.io.IOException)11 DatasetModuleConflictException (co.cask.cdap.data2.datafabric.dataset.type.DatasetModuleConflictException)10 Location (org.apache.twill.filesystem.Location)10 DatasetModuleConflictException (io.cdap.cdap.data2.datafabric.dataset.type.DatasetModuleConflictException)8 DatasetModuleMeta (io.cdap.cdap.proto.DatasetModuleMeta)8 DatasetModuleId (io.cdap.cdap.proto.id.DatasetModuleId)8 LinkedHashMap (java.util.LinkedHashMap)8 Map (java.util.Map)8 DatasetSpecification (io.cdap.cdap.api.dataset.DatasetSpecification)6 DatasetInstanceTable (io.cdap.cdap.data2.datafabric.dataset.service.mds.DatasetInstanceTable)6 DatasetTypeTable (io.cdap.cdap.data2.datafabric.dataset.service.mds.DatasetTypeTable)6 TypeConflictException (io.cdap.cdap.data2.dataset2.TypeConflictException)6 NamespaceId (io.cdap.cdap.proto.id.NamespaceId)6 Callable (java.util.concurrent.Callable)6 DatasetModuleCannotBeDeletedException (co.cask.cdap.common.DatasetModuleCannotBeDeletedException)5 DatasetModuleNotFoundException (co.cask.cdap.common.DatasetModuleNotFoundException)5 NamespaceId (co.cask.cdap.proto.id.NamespaceId)5 DatasetModule (co.cask.cdap.api.dataset.module.DatasetModule)4 ConflictException (co.cask.cdap.common.ConflictException)4 DatasetModuleId (co.cask.cdap.proto.id.DatasetModuleId)4