Skip to content

Commit

Permalink
Merge branch 'datahub-project:master' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
hsheth2 authored Sep 20, 2023
2 parents 77fc3dc + bf92092 commit 2d856d3
Show file tree
Hide file tree
Showing 156 changed files with 6,538 additions and 1,916 deletions.
2 changes: 0 additions & 2 deletions .github/workflows/docker-ingestion-smoke.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ on:
release:
types: [published]
push:
branches:
- master
paths:
- "docker/datahub-ingestion-base/**"
- "smoke-test/**"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@
import com.linkedin.datahub.graphql.generated.Notebook;
import com.linkedin.datahub.graphql.generated.Owner;
import com.linkedin.datahub.graphql.generated.OwnershipTypeEntity;
import com.linkedin.datahub.graphql.generated.ParentDomainsResult;
import com.linkedin.datahub.graphql.generated.PolicyMatchCriterionValue;
import com.linkedin.datahub.graphql.generated.QueryEntity;
import com.linkedin.datahub.graphql.generated.QuerySubject;
Expand Down Expand Up @@ -124,6 +125,7 @@
import com.linkedin.datahub.graphql.resolvers.domain.DeleteDomainResolver;
import com.linkedin.datahub.graphql.resolvers.domain.DomainEntitiesResolver;
import com.linkedin.datahub.graphql.resolvers.domain.ListDomainsResolver;
import com.linkedin.datahub.graphql.resolvers.domain.ParentDomainsResolver;
import com.linkedin.datahub.graphql.resolvers.domain.SetDomainResolver;
import com.linkedin.datahub.graphql.resolvers.domain.UnsetDomainResolver;
import com.linkedin.datahub.graphql.resolvers.embed.UpdateEmbedResolver;
Expand Down Expand Up @@ -186,6 +188,7 @@
import com.linkedin.datahub.graphql.resolvers.mutate.BatchSetDomainResolver;
import com.linkedin.datahub.graphql.resolvers.mutate.BatchUpdateDeprecationResolver;
import com.linkedin.datahub.graphql.resolvers.mutate.BatchUpdateSoftDeletedResolver;
import com.linkedin.datahub.graphql.resolvers.mutate.MoveDomainResolver;
import com.linkedin.datahub.graphql.resolvers.mutate.MutableTypeBatchResolver;
import com.linkedin.datahub.graphql.resolvers.mutate.MutableTypeResolver;
import com.linkedin.datahub.graphql.resolvers.mutate.RemoveLinkResolver;
Expand Down Expand Up @@ -944,6 +947,7 @@ private void configureMutationResolvers(final RuntimeWiring.Builder builder) {
.dataFetcher("removeGroup", new RemoveGroupResolver(this.entityClient))
.dataFetcher("updateUserStatus", new UpdateUserStatusResolver(this.entityClient))
.dataFetcher("createDomain", new CreateDomainResolver(this.entityClient, this.entityService))
.dataFetcher("moveDomain", new MoveDomainResolver(this.entityService, this.entityClient))
.dataFetcher("deleteDomain", new DeleteDomainResolver(entityClient))
.dataFetcher("setDomain", new SetDomainResolver(this.entityClient, this.entityService))
.dataFetcher("batchSetDomain", new BatchSetDomainResolver(this.entityService))
Expand Down Expand Up @@ -1029,6 +1033,13 @@ private void configureGenericEntityResolvers(final RuntimeWiring.Builder builder
.dataFetcher("entities", new EntityTypeBatchResolver(entityTypes,
(env) -> ((BrowseResults) env.getSource()).getEntities()))
)
.type("ParentDomainsResult", typeWiring -> typeWiring
.dataFetcher("domains", new EntityTypeBatchResolver(entityTypes,
(env) -> {
final ParentDomainsResult result = env.getSource();
return result != null ? result.getDomains() : null;
}))
)
.type("EntityRelationshipLegacy", typeWiring -> typeWiring
.dataFetcher("entity", new EntityTypeResolver(entityTypes,
(env) -> ((EntityRelationshipLegacy) env.getSource()).getEntity()))
Expand Down Expand Up @@ -1675,8 +1686,8 @@ private void configureGlossaryRelationshipResolvers(final RuntimeWiring.Builder
private void configureDomainResolvers(final RuntimeWiring.Builder builder) {
builder.type("Domain", typeWiring -> typeWiring
.dataFetcher("entities", new DomainEntitiesResolver(this.entityClient))
.dataFetcher("relationships", new EntityRelationshipsResultResolver(graphClient)
)
.dataFetcher("parentDomains", new ParentDomainsResolver(this.entityClient))
.dataFetcher("relationships", new EntityRelationshipsResultResolver(graphClient))
);
builder.type("DomainAssociation", typeWiring -> typeWiring
.dataFetcher("domain",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ public enum DataHubGraphQLErrorCode {
BAD_REQUEST(400),
UNAUTHORIZED(403),
NOT_FOUND(404),
CONFLICT(409),
SERVER_ERROR(500);

private final int _code;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,5 @@ public class FeatureFlags {
private PreProcessHooks preProcessHooks;
private boolean showAcrylInfo = false;
private boolean showAccessManagement = false;
private boolean nestedDomainsEnabled = false;
}
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ public CompletableFuture<AppConfig> get(final DataFetchingEnvironment environmen
.setShowBrowseV2(_featureFlags.isShowBrowseV2())
.setShowAcrylInfo(_featureFlags.isShowAcrylInfo())
.setShowAccessManagement(_featureFlags.isShowAccessManagement())
.setNestedDomainsEnabled(_featureFlags.isNestedDomainsEnabled())
.build();

appConfig.setFeatureFlags(featureFlagsConfig);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
package com.linkedin.datahub.graphql.resolvers.domain;

import com.linkedin.common.AuditStamp;
import com.linkedin.common.urn.Urn;
import com.linkedin.common.urn.UrnUtils;
import com.linkedin.data.template.SetMode;
import com.linkedin.datahub.graphql.QueryContext;
import com.linkedin.datahub.graphql.authorization.AuthorizationUtils;
import com.linkedin.datahub.graphql.exception.AuthorizationException;
import com.linkedin.datahub.graphql.exception.DataHubGraphQLErrorCode;
import com.linkedin.datahub.graphql.exception.DataHubGraphQLException;
import com.linkedin.datahub.graphql.generated.CreateDomainInput;
import com.linkedin.datahub.graphql.generated.OwnerEntityType;
import com.linkedin.datahub.graphql.generated.OwnershipType;
import com.linkedin.datahub.graphql.resolvers.mutate.util.DomainUtils;
import com.linkedin.datahub.graphql.resolvers.mutate.util.OwnerUtils;
import com.linkedin.domain.DomainProperties;
import com.linkedin.entity.client.EntityClient;
Expand All @@ -19,8 +23,11 @@
import com.linkedin.mxe.MetadataChangeProposal;
import graphql.schema.DataFetcher;
import graphql.schema.DataFetchingEnvironment;

import java.net.URISyntaxException;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

Expand All @@ -45,9 +52,9 @@ public CompletableFuture<String> get(DataFetchingEnvironment environment) throws

final QueryContext context = environment.getContext();
final CreateDomainInput input = bindArgument(environment.getArgument("input"), CreateDomainInput.class);
final Urn parentDomain = input.getParentDomain() != null ? UrnUtils.getUrn(input.getParentDomain()) : null;

return CompletableFuture.supplyAsync(() -> {

if (!AuthorizationUtils.canCreateDomains(context)) {
throw new AuthorizationException("Unauthorized to perform this action. Please contact your DataHub administrator.");
}
Expand All @@ -64,6 +71,17 @@ public CompletableFuture<String> get(DataFetchingEnvironment environment) throws
throw new IllegalArgumentException("This Domain already exists!");
}

if (parentDomain != null && !_entityClient.exists(parentDomain, context.getAuthentication())) {
throw new IllegalArgumentException("Parent Domain does not exist!");
}

if (DomainUtils.hasNameConflict(input.getName(), parentDomain, context, _entityClient)) {
throw new DataHubGraphQLException(
String.format("\"%s\" already exists in this domain. Please pick a unique name.", input.getName()),
DataHubGraphQLErrorCode.CONFLICT
);
}

// Create the MCP
final MetadataChangeProposal proposal = buildMetadataChangeProposalWithKey(key, DOMAIN_ENTITY_NAME,
DOMAIN_PROPERTIES_ASPECT_NAME, mapDomainProperties(input, context));
Expand All @@ -77,6 +95,8 @@ public CompletableFuture<String> get(DataFetchingEnvironment environment) throws
}
OwnerUtils.addCreatorAsOwner(context, domainUrn, OwnerEntityType.CORP_USER, ownershipType, _entityService);
return domainUrn;
} catch (DataHubGraphQLException e) {
throw e;
} catch (Exception e) {
log.error("Failed to create Domain with id: {}, name: {}: {}", input.getId(), input.getName(), e.getMessage());
throw new RuntimeException(String.format("Failed to create Domain with id: %s, name: %s", input.getId(), input.getName()), e);
Expand All @@ -89,6 +109,13 @@ private DomainProperties mapDomainProperties(final CreateDomainInput input, fina
result.setName(input.getName());
result.setDescription(input.getDescription(), SetMode.IGNORE_NULL);
result.setCreated(new AuditStamp().setActor(UrnUtils.getUrn(context.getActorUrn())).setTime(System.currentTimeMillis()));
if (input.getParentDomain() != null) {
try {
result.setParentDomain(Urn.createFromString(input.getParentDomain()));
} catch (URISyntaxException e) {
throw new RuntimeException(String.format("Failed to create Domain Urn from string: %s", input.getParentDomain()), e);
}
}
return result;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import com.linkedin.datahub.graphql.QueryContext;
import com.linkedin.datahub.graphql.authorization.AuthorizationUtils;
import com.linkedin.datahub.graphql.exception.AuthorizationException;
import com.linkedin.datahub.graphql.resolvers.mutate.util.DomainUtils;
import com.linkedin.entity.client.EntityClient;
import graphql.schema.DataFetcher;
import graphql.schema.DataFetchingEnvironment;
Expand Down Expand Up @@ -32,6 +33,11 @@ public CompletableFuture<Boolean> get(final DataFetchingEnvironment environment)

if (AuthorizationUtils.canManageDomains(context) || AuthorizationUtils.canDeleteEntity(urn, context)) {
try {
// Make sure there are no child domains
if (DomainUtils.hasChildDomains(urn, context, _entityClient)) {
throw new RuntimeException(String.format("Cannot delete domain %s which has child domains", domainUrn));
}

_entityClient.deleteEntity(urn, context.getAuthentication());
log.info(String.format("I've successfully deleted the entity %s with urn", domainUrn));

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.linkedin.datahub.graphql.resolvers.domain;

import com.google.common.collect.ImmutableList;
import com.linkedin.datahub.graphql.QueryContext;
import com.linkedin.datahub.graphql.generated.Domain;
import com.linkedin.datahub.graphql.generated.DomainEntitiesInput;
Expand Down Expand Up @@ -67,17 +66,22 @@ public CompletableFuture<SearchResults> get(final DataFetchingEnvironment enviro

try {

final CriterionArray criteria = new CriterionArray();
final Criterion filterCriterion = new Criterion()
.setField(DOMAINS_FIELD_NAME + ".keyword")
.setCondition(Condition.EQUAL)
.setValue(urn);
criteria.add(filterCriterion);
if (input.getFilters() != null) {
input.getFilters().forEach(filter -> {
criteria.add(new Criterion().setField(filter.getField()).setValue(filter.getValue()));
});
}

return UrnSearchResultsMapper.map(_entityClient.searchAcrossEntities(
SEARCHABLE_ENTITY_TYPES.stream().map(EntityTypeMapper::getName).collect(Collectors.toList()),
query,
new Filter().setOr(new ConjunctiveCriterionArray(
new ConjunctiveCriterion().setAnd(new CriterionArray(ImmutableList.of(filterCriterion)))
)),
new Filter().setOr(new ConjunctiveCriterionArray(new ConjunctiveCriterion().setAnd(criteria))),
start,
count,
null,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,24 @@
package com.linkedin.datahub.graphql.resolvers.domain;

import com.linkedin.common.urn.Urn;
import com.linkedin.common.urn.UrnUtils;
import com.linkedin.datahub.graphql.QueryContext;
import com.linkedin.datahub.graphql.authorization.AuthorizationUtils;
import com.linkedin.datahub.graphql.exception.AuthorizationException;
import com.linkedin.datahub.graphql.generated.Domain;
import com.linkedin.datahub.graphql.generated.EntityType;
import com.linkedin.datahub.graphql.generated.ListDomainsInput;
import com.linkedin.datahub.graphql.generated.ListDomainsResult;
import com.linkedin.datahub.graphql.resolvers.mutate.util.DomainUtils;
import com.linkedin.entity.client.EntityClient;
import com.linkedin.metadata.Constants;
import com.linkedin.metadata.query.SearchFlags;
import com.linkedin.metadata.query.filter.Filter;
import com.linkedin.metadata.query.filter.SortCriterion;
import com.linkedin.metadata.query.filter.SortOrder;
import com.linkedin.metadata.search.SearchEntity;
import com.linkedin.metadata.search.SearchResult;
import graphql.schema.DataFetcher;
import graphql.schema.DataFetchingEnvironment;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
Expand All @@ -30,7 +32,6 @@
* Resolver used for listing all Domains defined within DataHub. Requires the MANAGE_DOMAINS platform privilege.
*/
public class ListDomainsResolver implements DataFetcher<CompletableFuture<ListDomainsResult>> {

private static final Integer DEFAULT_START = 0;
private static final Integer DEFAULT_COUNT = 20;
private static final String DEFAULT_QUERY = "";
Expand All @@ -48,18 +49,19 @@ public CompletableFuture<ListDomainsResult> get(final DataFetchingEnvironment en

return CompletableFuture.supplyAsync(() -> {

if (AuthorizationUtils.canCreateDomains(context)) {
final ListDomainsInput input = bindArgument(environment.getArgument("input"), ListDomainsInput.class);
final Integer start = input.getStart() == null ? DEFAULT_START : input.getStart();
final Integer count = input.getCount() == null ? DEFAULT_COUNT : input.getCount();
final String query = input.getQuery() == null ? DEFAULT_QUERY : input.getQuery();
final Urn parentDomainUrn = input.getParentDomain() != null ? UrnUtils.getUrn(input.getParentDomain()) : null;
final Filter filter = DomainUtils.buildParentDomainFilter(parentDomainUrn);

try {
// First, get all group Urns.
// First, get all domain Urns.
final SearchResult gmsResult = _entityClient.search(
Constants.DOMAIN_ENTITY_NAME,
query,
null,
filter,
new SortCriterion().setField(DOMAIN_CREATED_TIME_INDEX_FIELD_NAME).setOrder(SortOrder.DESCENDING),
start,
count,
Expand All @@ -78,8 +80,6 @@ public CompletableFuture<ListDomainsResult> get(final DataFetchingEnvironment en
} catch (Exception e) {
throw new RuntimeException("Failed to list domains", e);
}
}
throw new AuthorizationException("Unauthorized to perform this action. Please contact your DataHub administrator.");
});
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package com.linkedin.datahub.graphql.resolvers.domain;

import com.linkedin.common.urn.Urn;
import com.linkedin.common.urn.UrnUtils;
import com.linkedin.datahub.graphql.QueryContext;
import com.linkedin.datahub.graphql.generated.Entity;
import com.linkedin.datahub.graphql.generated.ParentDomainsResult;
import com.linkedin.datahub.graphql.resolvers.mutate.util.DomainUtils;
import com.linkedin.entity.client.EntityClient;
import graphql.schema.DataFetcher;
import graphql.schema.DataFetchingEnvironment;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CompletableFuture;

import static com.linkedin.metadata.Constants.DOMAIN_ENTITY_NAME;

public class ParentDomainsResolver implements DataFetcher<CompletableFuture<ParentDomainsResult>> {

private final EntityClient _entityClient;

public ParentDomainsResolver(final EntityClient entityClient) {
_entityClient = entityClient;
}

@Override
public CompletableFuture<ParentDomainsResult> get(DataFetchingEnvironment environment) {
final QueryContext context = environment.getContext();
final Urn urn = UrnUtils.getUrn(((Entity) environment.getSource()).getUrn());
final List<Entity> parentDomains = new ArrayList<>();
final Set<String> visitedParentUrns = new HashSet<>();

if (!DOMAIN_ENTITY_NAME.equals(urn.getEntityType())) {
throw new IllegalArgumentException(String.format("Failed to resolve parents for entity type %s", urn));
}

return CompletableFuture.supplyAsync(() -> {
try {
Entity parentDomain = DomainUtils.getParentDomain(urn, context, _entityClient);

while (parentDomain != null && !visitedParentUrns.contains(parentDomain.getUrn())) {
parentDomains.add(parentDomain);
visitedParentUrns.add(parentDomain.getUrn());
parentDomain = DomainUtils.getParentDomain(Urn.createFromString(parentDomain.getUrn()), context, _entityClient);
}

final ParentDomainsResult result = new ParentDomainsResult();
result.setCount(parentDomains.size());
result.setDomains(parentDomains);
return result;
} catch (Exception e) {
throw new RuntimeException(String.format("Failed to load parent domains for entity %s", urn), e);
}
});
}
}
Loading

0 comments on commit 2d856d3

Please sign in to comment.