Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DC-1205]Store TDR owned Sam Group info in database #1788

Merged
merged 21 commits into from
Aug 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
bddeff0
update database snapshot_request table to contain 3 new columns repre…
raejohanek Aug 15, 2024
e305ccd
update SnapshotAccessRequestModel and SnapshotAccessRequestResponse t…
raejohanek Aug 19, 2024
1ec7888
update SnapshotCreateFlight to record sam group information for by re…
raejohanek Aug 19, 2024
86ebc67
refactor AddCreatedSnapshotIdToSnapshotRequestStep to AddCreatedSnaps…
raejohanek Aug 20, 2024
ee583f6
update DeleteSnapshotDeleteSamGroupStep to use the sam group name sav…
raejohanek Aug 20, 2024
49018b3
combine updateCreatedSnapshotId and updateSamGroup into one method
raejohanek Aug 21, 2024
fd9022c
delete sam group email from database and models
raejohanek Aug 21, 2024
cc710b1
Merge branch 'develop' into rj/dc-1205-add-collaborators-1
raejohanek Aug 21, 2024
247c994
minor updates after merge conflicts
raejohanek Aug 21, 2024
d6cba79
rename tests
raejohanek Aug 21, 2024
22ee075
rename test data constant to reflect the data more precisely
raejohanek Aug 21, 2024
cbc9818
PR feedback, add tests for DeleteSnapshotPopAndLockDatasetStep
raejohanek Aug 21, 2024
62aa63a
remove unused snapshot working map key
raejohanek Aug 21, 2024
d45f934
update test data, test helpers, and a comment
raejohanek Aug 21, 2024
0dab3b2
minor changes, mostly naming and testing
raejohanek Aug 22, 2024
f781f42
test refactor
raejohanek Aug 22, 2024
4fd729f
fix unit test
raejohanek Aug 22, 2024
5258850
Merge branch 'develop' into rj/dc-1205-add-collaborators-1
raejohanek Aug 26, 2024
01a6429
add try catch for getByCreatedSnapshotId call
raejohanek Aug 26, 2024
878afc8
minor changes to steps and tests
raejohanek Aug 26, 2024
3dffe87
update expected error in one test, remove one test for case that no l…
raejohanek Aug 26, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ private SnapshotWorkingMapKeys() {}
public static final String SNAPSHOT_EXISTS = "snapshotExists";
public static final String SNAPSHOT_HAS_GOOGLE_PROJECT = "snapshotHasGoogleProject";
public static final String SNAPSHOT_HAS_AZURE_STORAGE_ACCOUNT = "snapshotHasStorageAccount";
public static final String SNAPSHOT_AUTH_DOMAIN_GROUPS = "snapshotAuthDomainGroups";
public static final String DATASET_EXISTS = "datasetExists";
public static final String STORAGE_ACCOUNT_RESOURCE_NAME = "storageAccountResourceName";
public static final String STORAGE_ACCOUNT_RESOURCE_TLC = "storageAccountResourceTlc";
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package bio.terra.service.snapshot.flight.create;

import bio.terra.service.snapshot.flight.SnapshotWorkingMapKeys;
import bio.terra.service.snapshotbuilder.SnapshotRequestDao;
import bio.terra.stairway.FlightContext;
import bio.terra.stairway.Step;
import bio.terra.stairway.StepResult;
import bio.terra.stairway.exception.RetryException;
import java.util.UUID;

public class AddCreatedInfoToSnapshotRequestStep implements Step {
private final SnapshotRequestDao snapshotRequestDao;
private final UUID snapshotRequestId;
private final UUID createdSnapshotId;
private final String samGroupCreatedBy;

public AddCreatedInfoToSnapshotRequestStep(
SnapshotRequestDao snapshotRequestDao,
UUID snapshotRequestId,
UUID snapshotId,
String samGroupCreatedBy) {
this.snapshotRequestDao = snapshotRequestDao;
this.snapshotRequestId = snapshotRequestId;
this.createdSnapshotId = snapshotId;
this.samGroupCreatedBy = samGroupCreatedBy;
}

@Override
public StepResult doStep(FlightContext context) throws InterruptedException, RetryException {
var workingMap = context.getWorkingMap();
String samGroupName =
workingMap.get(SnapshotWorkingMapKeys.SNAPSHOT_FIRECLOUD_GROUP_NAME, String.class);

snapshotRequestDao.updateCreatedInfo(
snapshotRequestId, createdSnapshotId, samGroupName, samGroupCreatedBy);
return StepResult.getStepResultSuccess();
}

@Override
public StepResult undoStep(FlightContext context) throws InterruptedException {
// remove the written information if the flight fails
snapshotRequestDao.updateCreatedInfo(snapshotRequestId, null, null, null);
return StepResult.getStepResultSuccess();
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -434,10 +434,11 @@ public SnapshotCreateFlight(FlightMap inputParameters, Object applicationContext

if (mode == SnapshotRequestContentsModel.ModeEnum.BYREQUESTID) {
UUID snapshotRequestId = contents.getRequestIdSpec().getSnapshotRequestId();
// Add created snapshot id to the snapshot request.
// On the snapshot access request, save information about the created snapshot and about
// the Sam group that was added as a DAC.
addStep(
new AddCreatedSnapshotIdToSnapshotRequestStep(
snapshotRequestDao, snapshotRequestId, snapshotId));
new AddCreatedInfoToSnapshotRequestStep(
snapshotRequestDao, snapshotRequestId, snapshotId, tdrServiceAccountEmail));
// Notify user that snapshot is ready to use.
addStep(
new NotifyUserOfSnapshotCreationStep(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
package bio.terra.service.snapshot.flight.delete;

import bio.terra.common.exception.NotFoundException;
import bio.terra.service.auth.iam.IamService;
import bio.terra.service.auth.iam.exception.IamNotFoundException;
import bio.terra.service.job.DefaultUndoStep;
import bio.terra.service.snapshot.flight.SnapshotWorkingMapKeys;
import bio.terra.service.snapshotbuilder.SnapshotAccessRequestModel;
import bio.terra.service.snapshotbuilder.SnapshotRequestDao;
import bio.terra.stairway.FlightContext;
import bio.terra.stairway.StepResult;
import bio.terra.stairway.exception.RetryException;
import com.fasterxml.jackson.core.type.TypeReference;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class DeleteSnapshotDeleteSamGroupStep extends DefaultUndoStep {
private static Logger logger = LoggerFactory.getLogger(DeleteSnapshotDeleteSamGroupStep.class);
private final IamService iamService;
private final SnapshotRequestDao snapshotRequestDao;
private final UUID snapshotId;

/**
Expand All @@ -27,28 +27,35 @@ public class DeleteSnapshotDeleteSamGroupStep extends DefaultUndoStep {
* @param iamService
* @param snapshotId
*/
public DeleteSnapshotDeleteSamGroupStep(IamService iamService, UUID snapshotId) {
public DeleteSnapshotDeleteSamGroupStep(
IamService iamService, SnapshotRequestDao snapshotRequestDao, UUID snapshotId) {
this.iamService = iamService;
this.snapshotRequestDao = snapshotRequestDao;
this.snapshotId = snapshotId;
}

@Override
public StepResult doStep(FlightContext context) throws InterruptedException, RetryException {
List<String> authDomains =
context
.getWorkingMap()
.get(SnapshotWorkingMapKeys.SNAPSHOT_AUTH_DOMAIN_GROUPS, new TypeReference<>() {});
// Only delete the Sam group if it matches the expected naming pattern
var expectedName = IamService.constructSamGroupName(snapshotId.toString());
if (Objects.nonNull(authDomains) && authDomains.contains(expectedName)) {
try {
iamService.deleteGroup(expectedName);
} catch (IamNotFoundException ex) {
// if group does not exist, nothing to delete)
} catch (Exception ex) {
logger.error("Error deleting Sam group: {}", expectedName, ex);
}
// The request will only exist if the snapshot was created with byRequestId mode
// If it exists, the request will have the sam group name to be deleted for this snapshot
SnapshotAccessRequestModel request;
try {
request = snapshotRequestDao.getByCreatedSnapshotId(snapshotId);
} catch (NotFoundException ex) {
// If the request does not exist, nothing to delete
return StepResult.getStepResultSuccess();
}

var samGroupName = request.samGroupName();
try {
iamService.deleteGroup(samGroupName);
} catch (IamNotFoundException ex) {
// If group does not exist, nothing to delete
} catch (Exception ex) {
// If there is some other error, log and continue
logger.error("Error deleting Sam group: {}", samGroupName, ex);
}

return StepResult.getStepResultSuccess();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@
import bio.terra.stairway.Step;
import bio.terra.stairway.StepResult;
import bio.terra.stairway.StepStatus;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

public class DeleteSnapshotPopAndLockDatasetStep implements Step {
Expand Down Expand Up @@ -64,16 +62,6 @@ public StepResult doStep(FlightContext context) {
return StepResult.getStepResultSuccess();
}

try {
List<String> authDomains =
new ArrayList<>(
snapshotService.retrieveAuthDomains(snapshot.getId(), authenticatedUserRequest));
map.put(SnapshotWorkingMapKeys.SNAPSHOT_AUTH_DOMAIN_GROUPS, authDomains);
} catch (Exception ex) {
// Do nothing if we can't retrieve the auth domains
// No Sam groups will be deleted
}

// Now we've confirmed the snapshot exists, let's check on the source dataset
UUID datasetId = snapshot.getSourceDataset().getId();
map.put(DatasetWorkingMapKeys.DATASET_ID, datasetId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import bio.terra.service.snapshot.flight.LockSnapshotStep;
import bio.terra.service.snapshot.flight.UnlockSnapshotStep;
import bio.terra.service.snapshotbuilder.SnapshotBuilderService;
import bio.terra.service.snapshotbuilder.SnapshotRequestDao;
import bio.terra.service.tabulardata.google.bigquery.BigQuerySnapshotPdao;
import bio.terra.stairway.Flight;
import bio.terra.stairway.FlightMap;
Expand All @@ -45,6 +46,7 @@ public SnapshotDeleteFlight(FlightMap inputParameters, Object applicationContext
SnapshotService snapshotService = appContext.getBean(SnapshotService.class);
SnapshotBuilderService snapshotBuilderService =
appContext.getBean(SnapshotBuilderService.class);
SnapshotRequestDao snapshotRequestDao = appContext.getBean(SnapshotRequestDao.class);
FireStoreDependencyDao dependencyDao = appContext.getBean(FireStoreDependencyDao.class);
FireStoreDao fileDao = appContext.getBean(FireStoreDao.class);
BigQuerySnapshotPdao bigQuerySnapshotPdao = appContext.getBean(BigQuerySnapshotPdao.class);
Expand Down Expand Up @@ -113,7 +115,7 @@ public SnapshotDeleteFlight(FlightMap inputParameters, Object applicationContext

// Now that we no longer have the resources in SAM, we can delete the underlying Sam group
// that was created for snapshots byRequestId
addStep(new DeleteSnapshotDeleteSamGroupStep(iamClient, snapshotId));
addStep(new DeleteSnapshotDeleteSamGroupStep(iamClient, snapshotRequestDao, snapshotId));

// Primary Data Deletion
// Note: Must delete primary data before metadata; it relies on being able to retrieve the
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ public record SnapshotAccessRequestModel(
Instant statusUpdatedDate,
SnapshotAccessRequestStatus status,
UUID createdSnapshotId,
String flightid) {
String flightid,
String samGroupName,
String samGroupCreatedByTerraId) {

@VisibleForTesting
static String generateSummaryForCriteria(
Expand Down Expand Up @@ -137,6 +139,7 @@ public SnapshotAccessRequestResponse toApiResponse(SnapshotBuilderSettings setti
.createdDate(createdDate != null ? createdDate.toString() : null)
.statusUpdatedDate(statusUpdatedDate != null ? statusUpdatedDate.toString() : null)
.createdSnapshotId(createdSnapshotId)
.summary(generateSummaryFromSnapshotSpecification(settings));
.summary(generateSummaryFromSnapshotSpecification(settings))
.authGroupName(samGroupName);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,9 @@ public class SnapshotRequestDao {
private static final String STATUS_UPDATED_DATE = "status_updated_date";
private static final String STATUS = "status";
private static final String FLIGHT_ID = "flightid";
private static final String CREATED_SNAPSHOT_ID = "created_snapshot_id";
public static final String CREATED_SNAPSHOT_ID = "created_snapshot_id";
public static final String SAM_GROUP_NAME = "sam_group_name";
public static final String SAM_GROUP_CREATED_BY = "sam_group_created_by";
private static final String AUTHORIZED_RESOURCES = "authorized_resources";
private static final String NOT_FOUND_MESSAGE =
"Snapshot Access Request with given id does not exist.";
Expand All @@ -55,7 +57,9 @@ public class SnapshotRequestDao {
DaoUtils.getInstant(rs, STATUS_UPDATED_DATE),
SnapshotAccessRequestStatus.valueOf(rs.getString(STATUS)),
rs.getObject(CREATED_SNAPSHOT_ID, UUID.class),
rs.getString(FLIGHT_ID));
rs.getString(FLIGHT_ID),
rs.getString(SAM_GROUP_NAME),
rs.getString(SAM_GROUP_CREATED_BY));

public SnapshotRequestDao(
NamedParameterJdbcTemplate jdbcTemplate,
Expand Down Expand Up @@ -89,6 +93,24 @@ public SnapshotAccessRequestModel getById(UUID requestId) {
}
}

/**
* Get the Snapshot Request associated with the given created snapshot id.
*
* @param createdSnapshotId associated with one snapshot request.
* @return the specified snapshot request or exception if it does not exist.
*/
public SnapshotAccessRequestModel getByCreatedSnapshotId(UUID createdSnapshotId) {
String sql = "SELECT * FROM snapshot_request WHERE created_snapshot_id = :created_snapshot_id";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you want to exclude DELETED here too? That's what other get() methods do.

Copy link
Contributor Author

@rjohanek rjohanek Aug 22, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm the getById for SnapshotRequestDao doesn't do this. Maybe I should update both methods

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think actually we do want to return deleted requests for the getByCreatedId call. Because when a source snapshot is deleted, all of the snapshot access requests on that snapshot are deleted. However, created snapshots from those requests will still exist as will the sam groups associated with them, stored on the snapshot access request. So, when one of those created snapshots is deleted, we still want to be able to find the request that created it (even if it has been deleted) so that we can delete the sam group stored on it. Also, for the getById endpoint I think we might also want to return deleted requests as well for auditing purposes, but not as sure on this one.

Copy link
Member

@pshapiro4broad pshapiro4broad Aug 26, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the getById for SnapshotRequestDao doesn't do this

Yes, that's a case where we can't exclude deleted as the caller may want to see a deleted record.

when one of those created snapshots is deleted, we still want to be able to find the request that created it (even if it has been deleted) so that we can delete the sam group stored on it

OK, that seems reasonable to me. Since this is an internal API (vs a web API) it's OK to return deleted elements. I wonder if the filtering of deleted items for the API call should be done outside the DAO layer and in the service or API layer. 🤔

MapSqlParameterSource params =
new MapSqlParameterSource().addValue(CREATED_SNAPSHOT_ID, createdSnapshotId);
try {
return jdbcTemplate.queryForObject(sql, params, modelMapper);
} catch (EmptyResultDataAccessException ex) {
throw new NotFoundException(
"No snapshot access requests found for given created snapshot id", ex);
}
}

/**
* Return the list of Snapshot Requests associated with the given snapshot id.
*
Expand Down Expand Up @@ -198,16 +220,21 @@ public void updateFlightId(UUID requestId, String flightId) {
}

@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.SERIALIZABLE)
public void updateCreatedSnapshotId(UUID requestId, UUID snapshotId) {
public void updateCreatedInfo(
UUID requestId, UUID snapshotId, String samGroupName, String groupCreatedByEmail) {
String sql =
"""
UPDATE snapshot_request SET
created_snapshot_id = :created_snapshot_id
created_snapshot_id = :created_snapshot_id,
sam_group_name = :sam_group_name,
sam_group_created_by = :sam_group_created_by
WHERE id = :id
""";
MapSqlParameterSource params =
new MapSqlParameterSource()
.addValue(CREATED_SNAPSHOT_ID, snapshotId)
.addValue(SAM_GROUP_NAME, samGroupName)
.addValue(SAM_GROUP_CREATED_BY, groupCreatedByEmail)
.addValue(ID, requestId);
if (jdbcTemplate.update(sql, params) == 0) {
throw new NotFoundException(NOT_FOUND_MESSAGE);
Expand Down
2 changes: 2 additions & 0 deletions src/main/resources/api/data-repository-openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7543,6 +7543,8 @@ components:
$ref: '#/components/schemas/UniqueIdProperty'
summary:
type: string
authGroupName:
type: string


SnapshotAccessRequestStatus:
Expand Down
1 change: 1 addition & 0 deletions src/main/resources/db/changelog.xml
Original file line number Diff line number Diff line change
Expand Up @@ -88,4 +88,5 @@
<include file="changesets/20240731_updatespecificationsagain.yaml" relativeToChangelogFile="true" />
<include file="changesets/20240816_load_datasetid.yaml" relativeToChangelogFile="true" />
<include file="changesets/20240822_load_rename_to_load_lock.yaml" relativeToChangelogFile="true" />
<include file="changesets/20240816_addsamgrouptorequest.yaml" relativeToChangelogFile="true" />
</databaseChangeLog>
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
databaseChangeLog:
- changeSet:
id: add_sam_group_to_request
author: rjohanek
changes:
- addColumn:
tableName: snapshot_request
columns:
- column:
name: sam_group_name
type: varchar(100)
- column:
name: sam_group_created_by
type: varchar(256)

Loading
Loading