Search in sources :

Example 1 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(HttpRequest 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 ChannelBufferInputStream(request.getContent()), Charsets.UTF_8)) {
        appRequest = 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) 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) 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) ChannelBufferInputStream(org.jboss.netty.buffer.ChannelBufferInputStream) 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 2 with InvalidArtifactException

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

the class ArtifactInspector method inspectPlugins.

/**
 * Inspects the plugin file and extracts plugin classes information.
 */
private ArtifactClasses.Builder inspectPlugins(ArtifactClasses.Builder builder, File artifactFile, ArtifactId artifactId, PluginInstantiator pluginInstantiator) throws IOException, InvalidArtifactException {
    // See if there are export packages. Plugins should be in those packages
    Set<String> exportPackages = getExportPackages(artifactFile);
    if (exportPackages.isEmpty()) {
        return builder;
    }
    try {
        ClassLoader pluginClassLoader = pluginInstantiator.getArtifactClassLoader(artifactId);
        for (Class<?> cls : getPluginClasses(exportPackages, pluginClassLoader)) {
            Plugin pluginAnnotation = cls.getAnnotation(Plugin.class);
            if (pluginAnnotation == null) {
                continue;
            }
            Map<String, PluginPropertyField> pluginProperties = Maps.newHashMap();
            try {
                String configField = getProperties(TypeToken.of(cls), pluginProperties);
                Set<String> pluginEndpoints = getPluginEndpoints(cls);
                PluginClass pluginClass = new PluginClass(pluginAnnotation.type(), getPluginName(cls), getPluginDescription(cls), cls.getName(), configField, pluginProperties, pluginEndpoints);
                builder.addPlugin(pluginClass);
            } catch (UnsupportedTypeException e) {
                LOG.warn("Plugin configuration type not supported. Plugin ignored. {}", cls, e);
            }
        }
    } catch (Throwable t) {
        throw new InvalidArtifactException(String.format("Class could not be found while inspecting artifact for plugins. " + "Please check dependencies are available, and that the correct parent artifact was specified. " + "Error class: %s, message: %s.", t.getClass(), t.getMessage()), t);
    }
    return builder;
}
Also used : CloseableClassLoader(co.cask.cdap.api.artifact.CloseableClassLoader) UnsupportedTypeException(co.cask.cdap.api.data.schema.UnsupportedTypeException) PluginClass(co.cask.cdap.api.plugin.PluginClass) PluginPropertyField(co.cask.cdap.api.plugin.PluginPropertyField) InvalidArtifactException(co.cask.cdap.common.InvalidArtifactException) Plugin(co.cask.cdap.api.annotation.Plugin)

Example 3 with InvalidArtifactException

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

the class ArtifactInspector method inspectApplications.

private ArtifactClasses.Builder inspectApplications(Id.Artifact artifactId, ArtifactClasses.Builder builder, Location artifactLocation, ClassLoader artifactClassLoader) throws IOException, InvalidArtifactException {
    // right now we force users to include the application main class as an attribute in their manifest,
    // which forces them to have a single application class.
    // in the future, we may want to let users do this or maybe specify a list of classes or
    // a package that will be searched for applications, to allow multiple applications in a single artifact.
    String mainClassName;
    try {
        Manifest manifest = BundleJarUtil.getManifest(artifactLocation);
        if (manifest == null) {
            return builder;
        }
        Attributes manifestAttributes = manifest.getMainAttributes();
        if (manifestAttributes == null) {
            return builder;
        }
        mainClassName = manifestAttributes.getValue(ManifestFields.MAIN_CLASS);
    } catch (ZipException e) {
        throw new InvalidArtifactException(String.format("Couldn't unzip artifact %s, please check it is a valid jar file.", artifactId), e);
    }
    if (mainClassName == null) {
        return builder;
    }
    try {
        Object appMain = artifactClassLoader.loadClass(mainClassName).newInstance();
        if (!(appMain instanceof Application)) {
            // possible for 3rd party plugin artifacts to have the main class set
            return builder;
        }
        Application app = (Application) appMain;
        java.lang.reflect.Type configType;
        // we can deserialize the config into that object. Otherwise it'll just be a Config
        try {
            configType = Artifacts.getConfigType(app.getClass());
        } catch (Exception e) {
            throw new InvalidArtifactException(String.format("Could not resolve config type for Application class %s in artifact %s. " + "The type must extend Config and cannot be parameterized.", mainClassName, artifactId));
        }
        Schema configSchema = configType == Config.class ? null : schemaGenerator.generate(configType);
        builder.addApp(new ApplicationClass(mainClassName, "", configSchema));
    } catch (ClassNotFoundException e) {
        throw new InvalidArtifactException(String.format("Could not find Application main class %s in artifact %s.", mainClassName, artifactId));
    } catch (UnsupportedTypeException e) {
        throw new InvalidArtifactException(String.format("Config for Application %s in artifact %s has an unsupported schema. " + "The type must extend Config and cannot be parameterized.", mainClassName, artifactId));
    } catch (InstantiationException | IllegalAccessException e) {
        throw new InvalidArtifactException(String.format("Could not instantiate Application class %s in artifact %s.", mainClassName, artifactId), e);
    }
    return builder;
}
Also used : Config(co.cask.cdap.api.Config) PluginConfig(co.cask.cdap.api.plugin.PluginConfig) Schema(co.cask.cdap.api.data.schema.Schema) Attributes(java.util.jar.Attributes) ApplicationClass(co.cask.cdap.api.artifact.ApplicationClass) ZipException(java.util.zip.ZipException) Manifest(java.util.jar.Manifest) ZipException(java.util.zip.ZipException) EOFException(java.io.EOFException) UnsupportedTypeException(co.cask.cdap.api.data.schema.UnsupportedTypeException) IOException(java.io.IOException) InvalidArtifactException(co.cask.cdap.common.InvalidArtifactException) UnsupportedTypeException(co.cask.cdap.api.data.schema.UnsupportedTypeException) Application(co.cask.cdap.api.app.Application) InvalidArtifactException(co.cask.cdap.common.InvalidArtifactException)

Example 4 with InvalidArtifactException

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

the class DefaultArtifactRepository method validateParentSet.

/**
 * Validates the parents of an artifact. Checks that each artifact only appears with a single version range.
 *
 * @param parents the set of parent ranges to validate
 * @throws InvalidArtifactException if there is more than one version range for an artifact
 */
@VisibleForTesting
static void validateParentSet(Id.Artifact artifactId, Set<ArtifactRange> parents) throws InvalidArtifactException {
    boolean isInvalid = false;
    StringBuilder errMsg = new StringBuilder("Invalid parents field.");
    // check for multiple version ranges for the same artifact.
    // ex: "parents": [ "etlbatch[1.0.0,2.0.0)", "etlbatch[3.0.0,4.0.0)" ]
    Set<String> parentNames = new HashSet<>();
    // keep track of dupes so that we don't have repeat error messages if there are more than 2 ranges for a name
    Set<String> dupes = new HashSet<>();
    for (ArtifactRange parent : parents) {
        String parentName = parent.getName();
        if (!parentNames.add(parentName) && !dupes.contains(parentName)) {
            errMsg.append(" Only one version range for parent '");
            errMsg.append(parentName);
            errMsg.append("' can be present.");
            dupes.add(parentName);
            isInvalid = true;
        }
        if (artifactId.getName().equals(parentName) && artifactId.getNamespace().toEntityId().getNamespace().equals(parent.getNamespace())) {
            throw new InvalidArtifactException(String.format("Invalid parent '%s' for artifact '%s'. An artifact cannot extend itself.", parent, artifactId));
        }
    }
    // "Invalid parents. Only one version range for parent 'etlbatch' can be present."
    if (isInvalid) {
        throw new InvalidArtifactException(errMsg.toString());
    }
}
Also used : ArtifactRange(co.cask.cdap.api.artifact.ArtifactRange) InvalidArtifactException(co.cask.cdap.common.InvalidArtifactException) HashSet(java.util.HashSet) VisibleForTesting(com.google.common.annotations.VisibleForTesting)

Example 5 with InvalidArtifactException

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

the class DefaultArtifactRepository method addSystemArtifacts.

@Override
public void addSystemArtifacts() throws Exception {
    // scan the directory for artifact .jar files and config files for those artifacts
    Map<Id.Artifact, SystemArtifactInfo> systemArtifacts = new HashMap<>();
    for (File systemArtifactDir : systemArtifactDirs) {
        for (File jarFile : DirUtils.listFiles(systemArtifactDir, "jar")) {
            // parse id from filename
            Id.Artifact artifactId;
            try {
                artifactId = Id.Artifact.parse(Id.Namespace.SYSTEM, jarFile.getName());
            } catch (IllegalArgumentException e) {
                LOG.warn(String.format("Skipping system artifact '%s' because the name is invalid: ", e.getMessage()));
                continue;
            }
            // check for a corresponding .json config file
            String artifactFileName = jarFile.getName();
            String configFileName = artifactFileName.substring(0, artifactFileName.length() - ".jar".length()) + ".json";
            File configFile = new File(systemArtifactDir, configFileName);
            try {
                // read and parse the config file if it exists. Otherwise use an empty config with the artifact filename
                ArtifactConfig artifactConfig = configFile.isFile() ? configReader.read(artifactId.getNamespace(), configFile) : new ArtifactConfig();
                validateParentSet(artifactId, artifactConfig.getParents());
                validatePluginSet(artifactConfig.getPlugins());
                systemArtifacts.put(artifactId, new SystemArtifactInfo(artifactId, jarFile, artifactConfig));
            } catch (InvalidArtifactException e) {
                LOG.warn(String.format("Could not add system artifact '%s' because it is invalid.", artifactFileName), e);
            }
        }
    }
    // child -> parents
    Multimap<Id.Artifact, Id.Artifact> childToParents = HashMultimap.create();
    // parent -> children
    Multimap<Id.Artifact, Id.Artifact> parentToChildren = HashMultimap.create();
    Set<Id.Artifact> remainingArtifacts = new HashSet<>();
    // build mapping from child to parents and from parents to children
    for (SystemArtifactInfo child : systemArtifacts.values()) {
        Id.Artifact childId = child.getArtifactId();
        remainingArtifacts.add(childId);
        for (SystemArtifactInfo potentialParent : systemArtifacts.values()) {
            Id.Artifact potentialParentId = potentialParent.getArtifactId();
            // skip if we're looking at ourselves
            if (childId.equals(potentialParentId)) {
                continue;
            }
            if (child.getConfig().hasParent(potentialParentId)) {
                childToParents.put(childId, potentialParentId);
                parentToChildren.put(potentialParentId, childId);
            }
        }
    }
    // loop until there is no change
    boolean nochange = false;
    while (!remainingArtifacts.isEmpty() && !nochange) {
        // add all artifacts that don't have any more parents
        Set<Id.Artifact> addedArtifacts = new HashSet<>();
        for (Id.Artifact remainingArtifact : remainingArtifacts) {
            if (!childToParents.containsKey(remainingArtifact)) {
                addSystemArtifact(systemArtifacts.get(remainingArtifact));
                addedArtifacts.add(remainingArtifact);
                for (Id.Artifact child : parentToChildren.get(remainingArtifact)) {
                    childToParents.remove(child, remainingArtifact);
                }
            }
        }
        remainingArtifacts.removeAll(addedArtifacts);
        nochange = addedArtifacts.isEmpty();
    }
    if (!remainingArtifacts.isEmpty()) {
        LOG.warn("Unable to add system artifacts {} due to cyclic dependencies", Joiner.on(",").join(remainingArtifacts));
    }
}
Also used : HashMap(java.util.HashMap) ArtifactConfig(co.cask.cdap.common.conf.ArtifactConfig) ArtifactId(co.cask.cdap.api.artifact.ArtifactId) Id(co.cask.cdap.common.id.Id) NamespaceId(co.cask.cdap.proto.id.NamespaceId) File(java.io.File) InvalidArtifactException(co.cask.cdap.common.InvalidArtifactException) HashSet(java.util.HashSet)

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