Search in sources :

Example 1 with ArtifactRange

use of io.cdap.cdap.api.artifact.ArtifactRange 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(io.cdap.cdap.api.artifact.ArtifactRange) InvalidArtifactException(io.cdap.cdap.common.InvalidArtifactException) HashSet(java.util.HashSet) VisibleForTesting(com.google.common.annotations.VisibleForTesting)

Example 2 with ArtifactRange

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

the class DefaultArtifactRepository method getParentArtifactDescriptors.

/**
 * Get {@link ArtifactDescriptor} of parent and grandparent (if any) artifacts for the given artifact.
 *
 * @param artifactId the id of the artifact for which to find its parent and grandparent {@link ArtifactDescriptor}
 * @param parentArtifacts the ranges of parents to find
 * @return {@link ArtifactDescriptor} of parent and grandparent (if any) artifacts, in that specific order
 * @throws ArtifactRangeNotFoundException if none of the parents could be found
 * @throws InvalidArtifactException       if one of the parents also has parents
 */
private List<ArtifactDescriptor> getParentArtifactDescriptors(Id.Artifact artifactId, Set<ArtifactRange> parentArtifacts) throws ArtifactRangeNotFoundException, InvalidArtifactException {
    List<ArtifactDetail> parents = new ArrayList<>();
    for (ArtifactRange parentRange : parentArtifacts) {
        parents.addAll(artifactStore.getArtifacts(parentRange, Integer.MAX_VALUE, ArtifactSortOrder.UNORDERED));
    }
    if (parents.isEmpty()) {
        throw new ArtifactRangeNotFoundException(String.format("Artifact %s extends artifacts '%s' that do not exist", artifactId, Joiner.on('/').join(parentArtifacts)));
    }
    ArtifactDescriptor parentArtifact = null;
    ArtifactDescriptor grandparentArtifact = null;
    // complicated dependency trees that are hard to manage.
    for (ArtifactDetail parent : parents) {
        Set<ArtifactRange> grandparentRanges = parent.getMeta().getUsableBy();
        for (ArtifactRange grandparentRange : grandparentRanges) {
            // if the parent as the child as a parent (cyclic dependency)
            if (grandparentRange.getNamespace().equals(artifactId.getNamespace().getId()) && grandparentRange.getName().equals(artifactId.getName()) && grandparentRange.versionIsInRange(artifactId.getVersion())) {
                throw new InvalidArtifactException(String.format("Invalid artifact '%s': cyclic dependency. Parent '%s' has artifact '%s' as a parent.", artifactId, parent.getDescriptor().getArtifactId(), artifactId));
            }
            List<ArtifactDetail> grandparents = artifactStore.getArtifacts(grandparentRange, Integer.MAX_VALUE, ArtifactSortOrder.UNORDERED);
            // check that no grandparent has parents
            for (ArtifactDetail grandparent : grandparents) {
                Set<ArtifactRange> greatGrandparents = grandparent.getMeta().getUsableBy();
                if (!greatGrandparents.isEmpty()) {
                    throw new InvalidArtifactException(String.format("Invalid artifact '%s'. Grandparents of artifacts cannot have parents. Grandparent '%s' has parents.", artifactId, grandparent.getDescriptor().getArtifactId()));
                }
                // assumes any grandparent will do
                if (parentArtifact == null && grandparentArtifact == null) {
                    grandparentArtifact = grandparent.getDescriptor();
                }
            }
        }
        // assumes any parent will do
        if (parentArtifact == null) {
            parentArtifact = parent.getDescriptor();
        }
    }
    List<ArtifactDescriptor> parentArtifactList = new ArrayList<>();
    parentArtifactList.add(parentArtifact);
    if (grandparentArtifact != null) {
        parentArtifactList.add(grandparentArtifact);
    }
    return parentArtifactList;
}
Also used : ArtifactRangeNotFoundException(io.cdap.cdap.common.ArtifactRangeNotFoundException) ArrayList(java.util.ArrayList) ArtifactRange(io.cdap.cdap.api.artifact.ArtifactRange) InvalidArtifactException(io.cdap.cdap.common.InvalidArtifactException)

Example 3 with ArtifactRange

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

the class ArtifactStore method deleteMeta.

private void deleteMeta(StructuredTableContext context, Id.Artifact artifactId, ArtifactData oldMeta) throws IOException {
    // delete old artifact data
    StructuredTable artifactTable = getTable(context, StoreDefinition.ArtifactStore.ARTIFACT_DATA_TABLE);
    ArtifactCell artifactCell = new ArtifactCell(artifactId);
    artifactTable.delete(artifactCell.keys);
    // delete old appclass metadata
    StructuredTable appClassTable = getTable(context, StoreDefinition.ArtifactStore.APP_DATA_TABLE);
    for (ApplicationClass appClass : oldMeta.meta.getClasses().getApps()) {
        AppClassKey appClassKey = new AppClassKey(artifactId.getNamespace().toEntityId(), appClass.getClassName());
        deleteRangeFromTable(appClassTable, Range.singleton(appClassKey.keys));
    }
    // delete old plugins, we loop twice to only access to one table at a time to prevent deadlock
    StructuredTable pluginDataTable = getTable(context, StoreDefinition.ArtifactStore.PLUGIN_DATA_TABLE);
    for (PluginClass pluginClass : oldMeta.meta.getClasses().getPlugins()) {
        // delete metadata for each artifact this plugin extends
        for (ArtifactRange artifactRange : oldMeta.meta.getUsableBy()) {
            // these four fields are prefixes of the plugin table primary keys
            PluginKeyPrefix pluginKey = new PluginKeyPrefix(artifactRange.getNamespace(), artifactRange.getName(), pluginClass.getType(), pluginClass.getName());
            pluginDataTable.delete(concatFields(pluginKey.keys, artifactCell.keys));
        }
    }
    // Delete the universal plugin row
    StructuredTable uniPluginTable = getTable(context, StoreDefinition.ArtifactStore.UNIV_PLUGIN_DATA_TABLE);
    for (PluginClass pluginClass : oldMeta.meta.getClasses().getPlugins()) {
        if (oldMeta.meta.getUsableBy().isEmpty()) {
            UniversalPluginKeyPrefix pluginKey = new UniversalPluginKeyPrefix(artifactId.getNamespace().getId(), pluginClass.getType(), pluginClass.getName());
            uniPluginTable.delete(concatFields(pluginKey.keys, artifactCell.keys));
        }
    }
    // delete the old jar file
    try {
        new EntityImpersonator(artifactId.toEntityId(), impersonator).impersonate(() -> {
            Locations.getLocationFromAbsolutePath(locationFactory, oldMeta.getLocationPath()).delete();
            return null;
        });
    } catch (IOException ioe) {
        throw ioe;
    } catch (Exception e) {
        // this should not happen
        throw Throwables.propagate(e);
    }
}
Also used : StructuredTable(io.cdap.cdap.spi.data.StructuredTable) EntityImpersonator(io.cdap.cdap.security.impersonation.EntityImpersonator) ArtifactRange(io.cdap.cdap.api.artifact.ArtifactRange) ApplicationClass(io.cdap.cdap.api.artifact.ApplicationClass) IOException(java.io.IOException) PluginClass(io.cdap.cdap.api.plugin.PluginClass) ArtifactAlreadyExistsException(io.cdap.cdap.common.ArtifactAlreadyExistsException) TransactionException(io.cdap.cdap.spi.data.transaction.TransactionException) PluginNotExistsException(io.cdap.cdap.internal.app.runtime.plugin.PluginNotExistsException) IOException(java.io.IOException) TableNotFoundException(io.cdap.cdap.spi.data.TableNotFoundException) ArtifactNotFoundException(io.cdap.cdap.common.ArtifactNotFoundException)

Example 4 with ArtifactRange

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

the class ArtifactStore method writeMeta.

// write a new artifact snapshot and clean up the old snapshot data
private void writeMeta(StructuredTableContext context, Id.Artifact artifactId, ArtifactData data) throws IOException {
    // write to artifact data table
    StructuredTable artifactDataTable = getTable(context, StoreDefinition.ArtifactStore.ARTIFACT_DATA_TABLE);
    ArtifactCell artifactCell = new ArtifactCell(artifactId);
    artifactDataTable.upsert(concatFields(artifactCell.keys, Collections.singleton(Fields.stringField(StoreDefinition.ArtifactStore.ARTIFACT_DATA_FIELD, GSON.toJson(data)))));
    ArtifactClasses classes = data.meta.getClasses();
    Location artifactLocation = Locations.getLocationFromAbsolutePath(locationFactory, data.getLocationPath());
    // write appClass metadata
    StructuredTable appTable = getTable(context, StoreDefinition.ArtifactStore.APP_DATA_TABLE);
    ArtifactCell artifactkeys = new ArtifactCell(artifactId);
    for (ApplicationClass appClass : classes.getApps()) {
        // a:{namespace}:{classname}
        AppClassKey appClassKey = new AppClassKey(artifactId.getNamespace().toEntityId(), appClass.getClassName());
        Field<String> appDataField = Fields.stringField(StoreDefinition.ArtifactStore.APP_DATA_FIELD, GSON.toJson(new AppData(appClass, artifactLocation)));
        appTable.upsert(concatFields(appClassKey.keys, artifactkeys.keys, Collections.singleton(appDataField)));
    }
    // write pluginClass metadata, we loop twice to only access to one table at a time to prevent deadlock
    StructuredTable pluginTable = getTable(context, StoreDefinition.ArtifactStore.PLUGIN_DATA_TABLE);
    for (PluginClass pluginClass : classes.getPlugins()) {
        // write metadata for each artifact this plugin extends
        for (ArtifactRange artifactRange : data.meta.getUsableBy()) {
            PluginKeyPrefix pluginKey = new PluginKeyPrefix(artifactRange.getNamespace(), artifactRange.getName(), pluginClass.getType(), pluginClass.getName());
            Field<String> pluginDataField = Fields.stringField(StoreDefinition.ArtifactStore.PLUGIN_DATA_FIELD, GSON.toJson(new PluginData(pluginClass, artifactLocation, artifactRange)));
            pluginTable.upsert(concatFields(pluginKey.keys, artifactkeys.keys, Collections.singleton(pluginDataField)));
        }
    }
    // write universal plugin class metadata
    StructuredTable uniPluginTable = getTable(context, StoreDefinition.ArtifactStore.UNIV_PLUGIN_DATA_TABLE);
    for (PluginClass pluginClass : classes.getPlugins()) {
        // by any other artifact in the same namespace.
        if (data.meta.getUsableBy().isEmpty()) {
            // Write a special entry for plugin that doesn't have parent, which means any artifact can use it
            UniversalPluginKeyPrefix pluginKey = new UniversalPluginKeyPrefix(artifactId.getNamespace().getId(), pluginClass.getType(), pluginClass.getName());
            Field<String> pluginDataField = Fields.stringField(StoreDefinition.ArtifactStore.PLUGIN_DATA_FIELD, GSON.toJson(new PluginData(pluginClass, artifactLocation, null)));
            uniPluginTable.upsert(concatFields(pluginKey.keys, artifactkeys.keys, Collections.singleton(pluginDataField)));
        }
    }
}
Also used : StructuredTable(io.cdap.cdap.spi.data.StructuredTable) ArtifactRange(io.cdap.cdap.api.artifact.ArtifactRange) ApplicationClass(io.cdap.cdap.api.artifact.ApplicationClass) ArtifactClasses(io.cdap.cdap.api.artifact.ArtifactClasses) PluginClass(io.cdap.cdap.api.plugin.PluginClass) Location(org.apache.twill.filesystem.Location)

Example 5 with ArtifactRange

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

the class ArtifactHttpHandler method getArtifactProperties.

@POST
@Path("/namespaces/{namespace-id}/artifactproperties")
public void getArtifactProperties(FullHttpRequest request, HttpResponder responder, @PathParam("namespace-id") String namespaceId, @QueryParam("order") @DefaultValue("DESC") String order) throws Exception {
    NamespaceId namespace = validateAndGetNamespace(namespaceId);
    ArtifactSortOrder sortOrder = ArtifactSortOrder.valueOf(order);
    List<ArtifactPropertiesRequest> propertyRequests;
    try (Reader reader = new InputStreamReader(new ByteBufInputStream(request.content()), StandardCharsets.UTF_8)) {
        propertyRequests = GSON.fromJson(reader, BATCH_ARTIFACT_PROPERTIES_REQUEST);
    } catch (JsonSyntaxException e) {
        throw new BadRequestException("Unable to parse request: " + e.getMessage(), e);
    }
    List<ArtifactSummaryProperties> result = new ArrayList<>(propertyRequests.size());
    for (ArtifactPropertiesRequest propertiesRequest : propertyRequests) {
        NamespaceId requestNamespace = propertiesRequest.getScope() == ArtifactScope.SYSTEM ? NamespaceId.SYSTEM : namespace;
        ArtifactRange range = new ArtifactRange(requestNamespace.getNamespace(), propertiesRequest.getName(), ArtifactVersionRange.parse(propertiesRequest.getVersion()));
        List<ArtifactDetail> artifactDetails = artifactRepository.getArtifactDetails(range, 1, sortOrder);
        for (ArtifactDetail artifactDetail : artifactDetails) {
            Map<String, String> properties = artifactDetail.getMeta().getProperties();
            Map<String, String> filteredProperties = new HashMap<>(propertiesRequest.getProperties().size());
            for (String propertyKey : propertiesRequest.getProperties()) {
                if (properties.containsKey(propertyKey)) {
                    filteredProperties.put(propertyKey, properties.get(propertyKey));
                }
            }
            String artifactVersion = artifactDetail.getDescriptor().getArtifactId().getVersion().getVersion();
            result.add(new ArtifactSummaryProperties(propertiesRequest.getName(), artifactVersion, propertiesRequest.getScope(), filteredProperties));
        }
    }
    responder.sendJson(HttpResponseStatus.OK, GSON.toJson(result, BATCH_ARTIFACT_PROPERTIES_RESPONSE));
}
Also used : InputStreamReader(java.io.InputStreamReader) HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) ArtifactRange(io.cdap.cdap.api.artifact.ArtifactRange) Reader(java.io.Reader) InputStreamReader(java.io.InputStreamReader) CapabilityReader(io.cdap.cdap.internal.capability.CapabilityReader) ByteBufInputStream(io.netty.buffer.ByteBufInputStream) ArtifactSortOrder(io.cdap.cdap.proto.artifact.ArtifactSortOrder) JsonSyntaxException(com.google.gson.JsonSyntaxException) ArtifactPropertiesRequest(io.cdap.cdap.proto.artifact.ArtifactPropertiesRequest) BadRequestException(io.cdap.cdap.common.BadRequestException) NamespaceId(io.cdap.cdap.proto.id.NamespaceId) ArtifactSummaryProperties(io.cdap.cdap.proto.artifact.ArtifactSummaryProperties) ArtifactDetail(io.cdap.cdap.internal.app.runtime.artifact.ArtifactDetail) Path(javax.ws.rs.Path) POST(javax.ws.rs.POST)

Aggregations

ArtifactRange (io.cdap.cdap.api.artifact.ArtifactRange)52 ArtifactVersion (io.cdap.cdap.api.artifact.ArtifactVersion)37 Test (org.junit.Test)34 NamespaceId (io.cdap.cdap.proto.id.NamespaceId)27 PluginClass (io.cdap.cdap.api.plugin.PluginClass)21 Id (io.cdap.cdap.common.id.Id)20 ArtifactId (io.cdap.cdap.proto.id.ArtifactId)18 File (java.io.File)14 ImmutableSet (com.google.common.collect.ImmutableSet)10 ArtifactNotFoundException (io.cdap.cdap.common.ArtifactNotFoundException)10 HashSet (java.util.HashSet)10 Set (java.util.Set)10 Manifest (java.util.jar.Manifest)10 ArtifactId (io.cdap.cdap.api.artifact.ArtifactId)8 PluginNotExistsException (io.cdap.cdap.internal.app.runtime.plugin.PluginNotExistsException)7 PluginId (io.cdap.cdap.proto.id.PluginId)7 ApplicationClass (io.cdap.cdap.api.artifact.ApplicationClass)6 PluginPropertyField (io.cdap.cdap.api.plugin.PluginPropertyField)6 IOException (java.io.IOException)6 ArtifactDetail (io.cdap.cdap.internal.app.runtime.artifact.ArtifactDetail)5