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
38 changed files
with
2,126 additions
and
375 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
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
104 changes: 104 additions & 0 deletions
104
...ore/src/main/java/com/linkedin/datahub/graphql/resolvers/connection/ConnectionMapper.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,104 @@ | ||
package com.linkedin.datahub.graphql.resolvers.connection; | ||
|
||
import com.linkedin.common.DataPlatformInstance; | ||
import com.linkedin.common.urn.Urn; | ||
import com.linkedin.data.DataMap; | ||
import com.linkedin.datahub.graphql.QueryContext; | ||
import com.linkedin.datahub.graphql.generated.DataHubConnection; | ||
import com.linkedin.datahub.graphql.generated.DataHubConnectionDetails; | ||
import com.linkedin.datahub.graphql.generated.DataHubJsonConnection; | ||
import com.linkedin.datahub.graphql.generated.DataPlatform; | ||
import com.linkedin.datahub.graphql.generated.EntityType; | ||
import com.linkedin.entity.EntityResponse; | ||
import com.linkedin.entity.EnvelopedAspect; | ||
import com.linkedin.entity.EnvelopedAspectMap; | ||
import com.linkedin.metadata.Constants; | ||
import io.datahubproject.metadata.services.SecretService; | ||
import javax.annotation.Nonnull; | ||
import javax.annotation.Nullable; | ||
|
||
public class ConnectionMapper { | ||
/** | ||
* Maps a GMS encrypted connection details object into the decrypted form returned by the GraphQL | ||
* API. | ||
* | ||
* <p>Returns null if the Entity does not have the required aspects: dataHubConnectionDetails or | ||
* dataPlatformInstance. | ||
*/ | ||
@Nullable | ||
public static DataHubConnection map( | ||
@Nonnull final QueryContext context, | ||
@Nonnull final EntityResponse entityResponse, | ||
@Nonnull final SecretService secretService) { | ||
// If the connection does not exist, simply return null | ||
if (!hasAspects(entityResponse)) { | ||
return null; | ||
} | ||
|
||
final DataHubConnection result = new DataHubConnection(); | ||
final Urn entityUrn = entityResponse.getUrn(); | ||
final EnvelopedAspectMap aspects = entityResponse.getAspects(); | ||
|
||
result.setUrn(entityUrn.toString()); | ||
result.setType(EntityType.DATAHUB_CONNECTION); | ||
|
||
final EnvelopedAspect envelopedAssertionInfo = | ||
aspects.get(Constants.DATAHUB_CONNECTION_DETAILS_ASPECT_NAME); | ||
if (envelopedAssertionInfo != null) { | ||
result.setDetails( | ||
mapConnectionDetails( | ||
context, | ||
new com.linkedin.connection.DataHubConnectionDetails( | ||
envelopedAssertionInfo.getValue().data()), | ||
secretService)); | ||
} | ||
final EnvelopedAspect envelopedPlatformInstance = | ||
aspects.get(Constants.DATA_PLATFORM_INSTANCE_ASPECT_NAME); | ||
if (envelopedPlatformInstance != null) { | ||
final DataMap data = envelopedPlatformInstance.getValue().data(); | ||
result.setPlatform(mapPlatform(new DataPlatformInstance(data))); | ||
} | ||
return result; | ||
} | ||
|
||
private static DataHubConnectionDetails mapConnectionDetails( | ||
@Nonnull final QueryContext context, | ||
@Nonnull final com.linkedin.connection.DataHubConnectionDetails gmsDetails, | ||
@Nonnull final SecretService secretService) { | ||
final DataHubConnectionDetails result = new DataHubConnectionDetails(); | ||
result.setType( | ||
com.linkedin.datahub.graphql.generated.DataHubConnectionDetailsType.valueOf( | ||
gmsDetails.getType().toString())); | ||
if (gmsDetails.hasJson() && ConnectionUtils.canManageConnections(context)) { | ||
result.setJson(mapJsonConnectionDetails(gmsDetails.getJson(), secretService)); | ||
} | ||
if (gmsDetails.hasName()) { | ||
result.setName(gmsDetails.getName()); | ||
} | ||
return result; | ||
} | ||
|
||
private static DataHubJsonConnection mapJsonConnectionDetails( | ||
@Nonnull final com.linkedin.connection.DataHubJsonConnection gmsJsonConnection, | ||
@Nonnull final SecretService secretService) { | ||
final DataHubJsonConnection result = new DataHubJsonConnection(); | ||
// Decrypt the BLOB! | ||
result.setBlob(secretService.decrypt(gmsJsonConnection.getEncryptedBlob())); | ||
return result; | ||
} | ||
|
||
private static DataPlatform mapPlatform(final DataPlatformInstance platformInstance) { | ||
// Set dummy platform to be resolved. | ||
final DataPlatform partialPlatform = new DataPlatform(); | ||
partialPlatform.setUrn(platformInstance.getPlatform().toString()); | ||
return partialPlatform; | ||
} | ||
|
||
private static boolean hasAspects(@Nonnull final EntityResponse response) { | ||
return response.hasAspects() | ||
&& response.getAspects().containsKey(Constants.DATAHUB_CONNECTION_DETAILS_ASPECT_NAME) | ||
&& response.getAspects().containsKey(Constants.DATA_PLATFORM_INSTANCE_ASPECT_NAME); | ||
} | ||
|
||
private ConnectionMapper() {} | ||
} |
23 changes: 23 additions & 0 deletions
23
...core/src/main/java/com/linkedin/datahub/graphql/resolvers/connection/ConnectionUtils.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,23 @@ | ||
package com.linkedin.datahub.graphql.resolvers.connection; | ||
|
||
import com.datahub.authorization.AuthUtil; | ||
import com.linkedin.datahub.graphql.QueryContext; | ||
import com.linkedin.metadata.authorization.PoliciesConfig; | ||
import javax.annotation.Nonnull; | ||
|
||
/** Utilities for working with DataHub Connections. */ | ||
public class ConnectionUtils { | ||
|
||
/** | ||
* Returns true if the user is able to read and or write connection between DataHub and external | ||
* platforms. | ||
*/ | ||
public static boolean canManageConnections(@Nonnull QueryContext context) { | ||
return AuthUtil.isAuthorized( | ||
context.getAuthorizer(), | ||
context.getActorUrn(), | ||
PoliciesConfig.MANAGE_CONNECTIONS_PRIVILEGE); | ||
} | ||
|
||
private ConnectionUtils() {} | ||
} |
78 changes: 78 additions & 0 deletions
78
...main/java/com/linkedin/datahub/graphql/resolvers/connection/UpsertConnectionResolver.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,78 @@ | ||
package com.linkedin.datahub.graphql.resolvers.connection; | ||
|
||
import static com.linkedin.datahub.graphql.resolvers.ResolverUtils.*; | ||
|
||
import com.datahub.authentication.Authentication; | ||
import com.linkedin.common.urn.Urn; | ||
import com.linkedin.common.urn.UrnUtils; | ||
import com.linkedin.connection.DataHubConnectionDetailsType; | ||
import com.linkedin.connection.DataHubJsonConnection; | ||
import com.linkedin.datahub.graphql.QueryContext; | ||
import com.linkedin.datahub.graphql.exception.AuthorizationException; | ||
import com.linkedin.datahub.graphql.generated.DataHubConnection; | ||
import com.linkedin.datahub.graphql.generated.UpsertDataHubConnectionInput; | ||
import com.linkedin.entity.EntityResponse; | ||
import com.linkedin.metadata.connection.ConnectionService; | ||
import graphql.schema.DataFetcher; | ||
import graphql.schema.DataFetchingEnvironment; | ||
import io.datahubproject.metadata.services.SecretService; | ||
import java.util.Objects; | ||
import java.util.concurrent.CompletableFuture; | ||
import javax.annotation.Nonnull; | ||
import lombok.extern.slf4j.Slf4j; | ||
|
||
@Slf4j | ||
public class UpsertConnectionResolver implements DataFetcher<CompletableFuture<DataHubConnection>> { | ||
|
||
private final ConnectionService _connectionService; | ||
private final SecretService _secretService; | ||
|
||
public UpsertConnectionResolver( | ||
@Nonnull final ConnectionService connectionService, | ||
@Nonnull final SecretService secretService) { | ||
_connectionService = | ||
Objects.requireNonNull(connectionService, "connectionService cannot be null"); | ||
_secretService = Objects.requireNonNull(secretService, "secretService cannot be null"); | ||
} | ||
|
||
@Override | ||
public CompletableFuture<DataHubConnection> get(final DataFetchingEnvironment environment) | ||
throws Exception { | ||
|
||
final QueryContext context = environment.getContext(); | ||
final UpsertDataHubConnectionInput input = | ||
bindArgument(environment.getArgument("input"), UpsertDataHubConnectionInput.class); | ||
final Authentication authentication = context.getAuthentication(); | ||
|
||
return CompletableFuture.supplyAsync( | ||
() -> { | ||
if (!ConnectionUtils.canManageConnections(context)) { | ||
throw new AuthorizationException( | ||
"Unauthorized to upsert Connection. Please contact your DataHub administrator for more information."); | ||
} | ||
|
||
try { | ||
final Urn connectionUrn = | ||
_connectionService.upsertConnection( | ||
context.getOperationContext(), | ||
input.getId(), | ||
UrnUtils.getUrn(input.getPlatformUrn()), | ||
DataHubConnectionDetailsType.valueOf(input.getType().toString()), | ||
input.getJson() != null | ||
// Encrypt payload | ||
? new DataHubJsonConnection() | ||
.setEncryptedBlob(_secretService.encrypt(input.getJson().getBlob())) | ||
: null, | ||
input.getName()); | ||
|
||
final EntityResponse connectionResponse = | ||
_connectionService.getConnectionEntityResponse( | ||
context.getOperationContext(), connectionUrn); | ||
return ConnectionMapper.map(context, connectionResponse, _secretService); | ||
} catch (Exception e) { | ||
throw new RuntimeException( | ||
String.format("Failed to upsert a Connection from input %s", input), e); | ||
} | ||
}); | ||
} | ||
} |
Oops, something went wrong.