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;
}
}
use of co.cask.cdap.common.InvalidArtifactException in project cdap by caskdata.
the class ArtifactRepository 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());
}
}
use of co.cask.cdap.common.InvalidArtifactException in project cdap by caskdata.
the class ArtifactRepository method addSystemArtifacts.
/**
* Scan all files in the local system artifact directory, looking for jar files and adding them as system artifacts.
* If the artifact already exists it will not be added again unless it is a snapshot version.
*
* @throws IOException if there was some IO error adding the system artifacts
*/
public void addSystemArtifacts() throws Exception {
// to add system artifacts, users should have write privileges on the system namespace
Principal principal = authenticationContext.getPrincipal();
authorizationEnforcer.enforce(NamespaceId.SYSTEM, principal, Action.WRITE);
// scan the directory for artifact .jar files and config files for those artifacts
List<SystemArtifactInfo> systemArtifacts = new ArrayList<>();
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;
}
// first revoke any orphane privileges
co.cask.cdap.proto.id.ArtifactId artifact = artifactId.toEntityId();
privilegesManager.revoke(artifact);
// then grant all on the artifact
privilegesManager.grant(artifact, principal, EnumSet.allOf(Action.class));
// 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.add(new SystemArtifactInfo(artifactId, jarFile, artifactConfig));
} catch (InvalidArtifactException e) {
LOG.warn(String.format("Could not add system artifact '%s' because it is invalid.", artifactFileName), e);
// since adding artifact failed, revoke privileges, since they may be orphane now
privilegesManager.revoke(artifact);
}
}
}
// taking advantage of the fact that we only have 1 level of dependencies
// so we can add all the parents first, then we know its safe to add everything else
// add all parents
Set<Id.Artifact> parents = new HashSet<>();
for (SystemArtifactInfo child : systemArtifacts) {
Id.Artifact childId = child.getArtifactId();
for (SystemArtifactInfo potentialParent : systemArtifacts) {
Id.Artifact potentialParentId = potentialParent.getArtifactId();
// skip if we're looking at ourselves
if (childId.equals(potentialParentId)) {
continue;
}
if (child.getConfig().hasParent(potentialParentId)) {
parents.add(potentialParentId);
}
}
}
// add all parents first
for (SystemArtifactInfo systemArtifact : systemArtifacts) {
if (parents.contains(systemArtifact.getArtifactId())) {
addSystemArtifact(systemArtifact);
}
}
// add children next
for (SystemArtifactInfo systemArtifact : systemArtifacts) {
if (!parents.contains(systemArtifact.getArtifactId())) {
addSystemArtifact(systemArtifact);
}
}
}
use of co.cask.cdap.common.InvalidArtifactException in project cdap by caskdata.
the class ArtifactRepository method validatePluginSet.
/**
* Validates the set of plugins for an artifact. Checks that the pair of plugin type and name are unique among
* all plugins in an artifact.
*
* @param plugins the set of plugins to validate
* @throws InvalidArtifactException if there is more than one class with the same type and name
*/
@VisibleForTesting
static void validatePluginSet(Set<PluginClass> plugins) throws InvalidArtifactException {
boolean isInvalid = false;
StringBuilder errMsg = new StringBuilder("Invalid plugins field.");
Set<ImmutablePair<String, String>> existingPlugins = new HashSet<>();
Set<ImmutablePair<String, String>> dupes = new HashSet<>();
for (PluginClass plugin : plugins) {
ImmutablePair<String, String> typeAndName = ImmutablePair.of(plugin.getType(), plugin.getName());
if (!existingPlugins.add(typeAndName) && !dupes.contains(typeAndName)) {
errMsg.append(" Only one plugin with type '");
errMsg.append(typeAndName.getFirst());
errMsg.append("' and name '");
errMsg.append(typeAndName.getSecond());
errMsg.append("' can be present.");
dupes.add(typeAndName);
isInvalid = true;
}
}
// "Invalid plugins. Only one plugin with type 'source' and name 'table' can be present."
if (isInvalid) {
throw new InvalidArtifactException(errMsg.toString());
}
}
Aggregations