forked from datahub-project/datahub
-
Notifications
You must be signed in to change notification settings - Fork 12
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'datahub-project:master' into master
- Loading branch information
Showing
180 changed files
with
9,807 additions
and
311 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
443 changes: 259 additions & 184 deletions
443
datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/GmsGraphQLEngine.java
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
109 changes: 109 additions & 0 deletions
109
...om/linkedin/datahub/graphql/resolvers/businessattribute/AddBusinessAttributeResolver.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
package com.linkedin.datahub.graphql.resolvers.businessattribute; | ||
|
||
import static com.linkedin.datahub.graphql.resolvers.ResolverUtils.bindArgument; | ||
import static com.linkedin.datahub.graphql.resolvers.mutate.MutationUtils.buildMetadataChangeProposalWithUrn; | ||
import static com.linkedin.metadata.Constants.BUSINESS_ATTRIBUTE_ASPECT; | ||
|
||
import com.linkedin.businessattribute.BusinessAttributeAssociation; | ||
import com.linkedin.businessattribute.BusinessAttributes; | ||
import com.linkedin.common.urn.BusinessAttributeUrn; | ||
import com.linkedin.common.urn.Urn; | ||
import com.linkedin.common.urn.UrnUtils; | ||
import com.linkedin.datahub.graphql.QueryContext; | ||
import com.linkedin.datahub.graphql.generated.AddBusinessAttributeInput; | ||
import com.linkedin.datahub.graphql.generated.ResourceRefInput; | ||
import com.linkedin.metadata.entity.EntityService; | ||
import com.linkedin.metadata.entity.EntityUtils; | ||
import com.linkedin.mxe.MetadataChangeProposal; | ||
import graphql.schema.DataFetcher; | ||
import graphql.schema.DataFetchingEnvironment; | ||
import java.net.URISyntaxException; | ||
import java.util.ArrayList; | ||
import java.util.List; | ||
import java.util.concurrent.CompletableFuture; | ||
import lombok.RequiredArgsConstructor; | ||
import lombok.extern.slf4j.Slf4j; | ||
|
||
@Slf4j | ||
@RequiredArgsConstructor | ||
public class AddBusinessAttributeResolver implements DataFetcher<CompletableFuture<Boolean>> { | ||
private final EntityService entityService; | ||
|
||
@Override | ||
public CompletableFuture<Boolean> get(DataFetchingEnvironment environment) throws Exception { | ||
final QueryContext context = environment.getContext(); | ||
final AddBusinessAttributeInput input = | ||
bindArgument(environment.getArgument("input"), AddBusinessAttributeInput.class); | ||
final Urn businessAttributeUrn = UrnUtils.getUrn(input.getBusinessAttributeUrn()); | ||
final List<ResourceRefInput> resourceRefInputs = input.getResourceUrn(); | ||
validateBusinessAttribute(businessAttributeUrn); | ||
return CompletableFuture.supplyAsync( | ||
() -> { | ||
try { | ||
addBusinessAttributeToResource( | ||
businessAttributeUrn, | ||
resourceRefInputs, | ||
UrnUtils.getUrn(context.getActorUrn()), | ||
entityService); | ||
return true; | ||
} catch (Exception e) { | ||
log.error( | ||
String.format( | ||
"Failed to add Business Attribute %s to resources %s", | ||
businessAttributeUrn, resourceRefInputs)); | ||
throw new RuntimeException( | ||
String.format( | ||
"Failed to add Business Attribute %s to resources %s", | ||
businessAttributeUrn, resourceRefInputs), | ||
e); | ||
} | ||
}); | ||
} | ||
|
||
private void validateBusinessAttribute(Urn businessAttributeUrn) { | ||
if (!entityService.exists(businessAttributeUrn, true)) { | ||
throw new IllegalArgumentException( | ||
String.format("This urn does not exist: %s", businessAttributeUrn)); | ||
} | ||
} | ||
|
||
private void addBusinessAttributeToResource( | ||
Urn businessAttributeUrn, | ||
List<ResourceRefInput> resourceRefInputs, | ||
Urn actorUrn, | ||
EntityService entityService) | ||
throws URISyntaxException { | ||
List<MetadataChangeProposal> proposals = new ArrayList<>(); | ||
for (ResourceRefInput resourceRefInput : resourceRefInputs) { | ||
proposals.add( | ||
buildAddBusinessAttributeToEntityProposal( | ||
businessAttributeUrn, resourceRefInput, entityService, actorUrn)); | ||
} | ||
EntityUtils.ingestChangeProposals(proposals, entityService, actorUrn, false); | ||
} | ||
|
||
private MetadataChangeProposal buildAddBusinessAttributeToEntityProposal( | ||
Urn businessAttributeUrn, | ||
ResourceRefInput resource, | ||
EntityService entityService, | ||
Urn actorUrn) | ||
throws URISyntaxException { | ||
BusinessAttributes businessAttributes = | ||
(BusinessAttributes) | ||
EntityUtils.getAspectFromEntity( | ||
resource.getResourceUrn(), | ||
BUSINESS_ATTRIBUTE_ASPECT, | ||
entityService, | ||
new BusinessAttributes()); | ||
if (!businessAttributes.hasBusinessAttribute()) { | ||
businessAttributes.setBusinessAttribute(new BusinessAttributeAssociation()); | ||
} | ||
BusinessAttributeAssociation businessAttributeAssociation = | ||
businessAttributes.getBusinessAttribute(); | ||
businessAttributeAssociation.setBusinessAttributeUrn( | ||
BusinessAttributeUrn.createFromUrn(businessAttributeUrn)); | ||
businessAttributes.setBusinessAttribute(businessAttributeAssociation); | ||
return buildMetadataChangeProposalWithUrn( | ||
UrnUtils.getUrn(resource.getResourceUrn()), BUSINESS_ATTRIBUTE_ASPECT, businessAttributes); | ||
} | ||
} |
37 changes: 37 additions & 0 deletions
37
...edin/datahub/graphql/resolvers/businessattribute/BusinessAttributeAuthorizationUtils.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
package com.linkedin.datahub.graphql.resolvers.businessattribute; | ||
|
||
import com.datahub.authorization.AuthUtil; | ||
import com.datahub.authorization.ConjunctivePrivilegeGroup; | ||
import com.datahub.authorization.DisjunctivePrivilegeGroup; | ||
import com.google.common.collect.ImmutableList; | ||
import com.linkedin.datahub.graphql.QueryContext; | ||
import com.linkedin.metadata.authorization.PoliciesConfig; | ||
import javax.annotation.Nonnull; | ||
|
||
public class BusinessAttributeAuthorizationUtils { | ||
private BusinessAttributeAuthorizationUtils() {} | ||
|
||
public static boolean canCreateBusinessAttribute(@Nonnull QueryContext context) { | ||
final DisjunctivePrivilegeGroup orPrivilegeGroups = | ||
new DisjunctivePrivilegeGroup( | ||
ImmutableList.of( | ||
new ConjunctivePrivilegeGroup( | ||
ImmutableList.of(PoliciesConfig.CREATE_BUSINESS_ATTRIBUTE_PRIVILEGE.getType())), | ||
new ConjunctivePrivilegeGroup( | ||
ImmutableList.of( | ||
PoliciesConfig.MANAGE_BUSINESS_ATTRIBUTE_PRIVILEGE.getType())))); | ||
return AuthUtil.isAuthorized( | ||
context.getAuthorizer(), context.getActorUrn(), orPrivilegeGroups, null); | ||
} | ||
|
||
public static boolean canManageBusinessAttribute(@Nonnull QueryContext context) { | ||
final DisjunctivePrivilegeGroup orPrivilegeGroups = | ||
new DisjunctivePrivilegeGroup( | ||
ImmutableList.of( | ||
new ConjunctivePrivilegeGroup( | ||
ImmutableList.of( | ||
PoliciesConfig.MANAGE_BUSINESS_ATTRIBUTE_PRIVILEGE.getType())))); | ||
return AuthUtil.isAuthorized( | ||
context.getAuthorizer(), context.getActorUrn(), orPrivilegeGroups, null); | ||
} | ||
} |
130 changes: 130 additions & 0 deletions
130
...linkedin/datahub/graphql/resolvers/businessattribute/CreateBusinessAttributeResolver.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
package com.linkedin.datahub.graphql.resolvers.businessattribute; | ||
|
||
import static com.linkedin.datahub.graphql.resolvers.ResolverUtils.bindArgument; | ||
import static com.linkedin.datahub.graphql.resolvers.mutate.MutationUtils.buildMetadataChangeProposalWithKey; | ||
import static com.linkedin.metadata.Constants.BUSINESS_ATTRIBUTE_ENTITY_NAME; | ||
import static com.linkedin.metadata.Constants.BUSINESS_ATTRIBUTE_INFO_ASPECT_NAME; | ||
|
||
import com.linkedin.businessattribute.BusinessAttributeInfo; | ||
import com.linkedin.businessattribute.BusinessAttributeKey; | ||
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.exception.AuthorizationException; | ||
import com.linkedin.datahub.graphql.exception.DataHubGraphQLErrorCode; | ||
import com.linkedin.datahub.graphql.exception.DataHubGraphQLException; | ||
import com.linkedin.datahub.graphql.generated.BusinessAttribute; | ||
import com.linkedin.datahub.graphql.generated.CreateBusinessAttributeInput; | ||
import com.linkedin.datahub.graphql.generated.OwnerEntityType; | ||
import com.linkedin.datahub.graphql.resolvers.mutate.util.BusinessAttributeUtils; | ||
import com.linkedin.datahub.graphql.resolvers.mutate.util.OwnerUtils; | ||
import com.linkedin.datahub.graphql.types.businessattribute.mappers.BusinessAttributeMapper; | ||
import com.linkedin.entity.client.EntityClient; | ||
import com.linkedin.metadata.entity.EntityService; | ||
import com.linkedin.metadata.service.BusinessAttributeService; | ||
import com.linkedin.metadata.utils.EntityKeyUtils; | ||
import com.linkedin.mxe.MetadataChangeProposal; | ||
import graphql.schema.DataFetcher; | ||
import graphql.schema.DataFetchingEnvironment; | ||
import java.util.UUID; | ||
import java.util.concurrent.CompletableFuture; | ||
import lombok.RequiredArgsConstructor; | ||
import lombok.extern.slf4j.Slf4j; | ||
|
||
@Slf4j | ||
@RequiredArgsConstructor | ||
public class CreateBusinessAttributeResolver | ||
implements DataFetcher<CompletableFuture<BusinessAttribute>> { | ||
private final EntityClient _entityClient; | ||
private final EntityService _entityService; | ||
private final BusinessAttributeService businessAttributeService; | ||
|
||
@Override | ||
public CompletableFuture<BusinessAttribute> get(DataFetchingEnvironment environment) | ||
throws Exception { | ||
final QueryContext context = environment.getContext(); | ||
CreateBusinessAttributeInput input = | ||
bindArgument(environment.getArgument("input"), CreateBusinessAttributeInput.class); | ||
if (!BusinessAttributeAuthorizationUtils.canCreateBusinessAttribute(context)) { | ||
throw new AuthorizationException( | ||
"Unauthorized to perform this action. Please contact your DataHub administrator."); | ||
} | ||
return CompletableFuture.supplyAsync( | ||
() -> { | ||
try { | ||
final BusinessAttributeKey businessAttributeKey = new BusinessAttributeKey(); | ||
String id = input.getId() != null ? input.getId() : UUID.randomUUID().toString(); | ||
businessAttributeKey.setId(id); | ||
|
||
if (_entityClient.exists( | ||
EntityKeyUtils.convertEntityKeyToUrn( | ||
businessAttributeKey, BUSINESS_ATTRIBUTE_ENTITY_NAME), | ||
context.getAuthentication())) { | ||
throw new IllegalArgumentException("This Business Attribute already exists!"); | ||
} | ||
|
||
if (BusinessAttributeUtils.hasNameConflict(input.getName(), context, _entityClient)) { | ||
throw new DataHubGraphQLException( | ||
String.format( | ||
"\"%s\" already exists as Business Attribute. Please pick a unique name.", | ||
input.getName()), | ||
DataHubGraphQLErrorCode.CONFLICT); | ||
} | ||
|
||
// Create the MCP | ||
final MetadataChangeProposal changeProposal = | ||
buildMetadataChangeProposalWithKey( | ||
businessAttributeKey, | ||
BUSINESS_ATTRIBUTE_ENTITY_NAME, | ||
BUSINESS_ATTRIBUTE_INFO_ASPECT_NAME, | ||
mapBusinessAttributeInfo(input, context)); | ||
|
||
// Ingest the MCP | ||
Urn businessAttributeUrn = | ||
UrnUtils.getUrn( | ||
_entityClient.ingestProposal(changeProposal, context.getAuthentication())); | ||
OwnerUtils.addCreatorAsOwner( | ||
context, | ||
businessAttributeUrn.toString(), | ||
OwnerEntityType.CORP_USER, | ||
_entityService); | ||
return BusinessAttributeMapper.map( | ||
context, | ||
businessAttributeService.getBusinessAttributeEntityResponse( | ||
businessAttributeUrn, context.getAuthentication())); | ||
|
||
} catch (DataHubGraphQLException e) { | ||
throw e; | ||
} catch (Exception e) { | ||
log.error( | ||
"Failed to create Business Attribute with name: {}: {}", | ||
input.getName(), | ||
e.getMessage()); | ||
throw new RuntimeException( | ||
String.format("Failed to create Business Attribute with name: %s", input.getName()), | ||
e); | ||
} | ||
}); | ||
} | ||
|
||
private BusinessAttributeInfo mapBusinessAttributeInfo( | ||
CreateBusinessAttributeInput input, QueryContext context) { | ||
final BusinessAttributeInfo info = new BusinessAttributeInfo(); | ||
info.setFieldPath(input.getName(), SetMode.DISALLOW_NULL); | ||
info.setName(input.getName(), SetMode.DISALLOW_NULL); | ||
info.setDescription(input.getDescription(), SetMode.IGNORE_NULL); | ||
info.setType( | ||
BusinessAttributeUtils.mapSchemaFieldDataType(input.getType()), SetMode.IGNORE_NULL); | ||
info.setCreated( | ||
new AuditStamp() | ||
.setActor(UrnUtils.getUrn(context.getActorUrn())) | ||
.setTime(System.currentTimeMillis())); | ||
info.setLastModified( | ||
new AuditStamp() | ||
.setActor(UrnUtils.getUrn(context.getActorUrn())) | ||
.setTime(System.currentTimeMillis())); | ||
return info; | ||
} | ||
} |
58 changes: 58 additions & 0 deletions
58
...linkedin/datahub/graphql/resolvers/businessattribute/DeleteBusinessAttributeResolver.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
package com.linkedin.datahub.graphql.resolvers.businessattribute; | ||
|
||
import com.linkedin.common.urn.Urn; | ||
import com.linkedin.common.urn.UrnUtils; | ||
import com.linkedin.datahub.graphql.QueryContext; | ||
import com.linkedin.datahub.graphql.exception.AuthorizationException; | ||
import com.linkedin.entity.client.EntityClient; | ||
import graphql.schema.DataFetcher; | ||
import graphql.schema.DataFetchingEnvironment; | ||
import java.util.concurrent.CompletableFuture; | ||
import lombok.RequiredArgsConstructor; | ||
import lombok.extern.slf4j.Slf4j; | ||
|
||
/** Resolver responsible for hard deleting a particular Business Attribute */ | ||
@Slf4j | ||
@RequiredArgsConstructor | ||
public class DeleteBusinessAttributeResolver implements DataFetcher<CompletableFuture<Boolean>> { | ||
private final EntityClient _entityClient; | ||
|
||
@Override | ||
public CompletableFuture<Boolean> get(DataFetchingEnvironment environment) throws Exception { | ||
final QueryContext context = environment.getContext(); | ||
final Urn businessAttributeUrn = UrnUtils.getUrn(environment.getArgument("urn")); | ||
if (!BusinessAttributeAuthorizationUtils.canManageBusinessAttribute(context)) { | ||
throw new AuthorizationException( | ||
"Unauthorized to perform this action. Please contact your DataHub administrator."); | ||
} | ||
if (!_entityClient.exists(businessAttributeUrn, context.getAuthentication())) { | ||
throw new RuntimeException( | ||
String.format("This urn does not exist: %s", businessAttributeUrn)); | ||
} | ||
return CompletableFuture.supplyAsync( | ||
() -> { | ||
try { | ||
_entityClient.deleteEntity(businessAttributeUrn, context.getAuthentication()); | ||
CompletableFuture.runAsync( | ||
() -> { | ||
try { | ||
_entityClient.deleteEntityReferences( | ||
businessAttributeUrn, context.getAuthentication()); | ||
} catch (Exception e) { | ||
log.error( | ||
String.format( | ||
"Exception while attempting to clear all entity references for Business Attribute with urn %s", | ||
businessAttributeUrn), | ||
e); | ||
} | ||
}); | ||
return true; | ||
} catch (Exception e) { | ||
throw new RuntimeException( | ||
String.format( | ||
"Failed to delete Business Attribute with urn %s", businessAttributeUrn), | ||
e); | ||
} | ||
}); | ||
} | ||
} |
Oops, something went wrong.