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

Fixes 4741: associate snapshots to templates directly #836

Merged
merged 5 commits into from
Oct 21, 2024

Conversation

xbhouse
Copy link
Contributor

@xbhouse xbhouse commented Oct 1, 2024

Summary

  • Associates snapshots to templates by adding snapshot_uuid to the templates_repository_configurations table
  • Migrates any existing templates' snapshots to this table
  • Simplifies the query for listing a template's snapshots to use the template-snapshot association
  • Checks that repos added to a template have a snapshot and rejects request if they do not

Testing steps

To test the migration:

  1. In main, create 1 custom repo and 1 RH repo
  2. Change the URL of the custom repo so you have 2 snapshots, and update the snapshot's created_at dates to be on different days
  3. Change the URL one more time to get another snapshot and don't update this date
  4. Create 3 templates: 1 with a date set to be between the dates of the snapshots, 1 with a date before the snapshots, and 1 using latest content
  5. Check out this PR and run the migration. Verify the correct snapshot uuids were added to the templates_repository_configurations table (you can either check the table directly or check via the GET /templates/:uuid/snapshots/ endpoint)

To test a template's snapshots are updated correctly:

  1. Create a custom repo and a RH repo, let them snapshot, and create a template with these repos with use_latest set to true
  2. Listing the template's snapshots (GET /templates/:uuid/snapshots/) should still work as expected
  3. Add / remove one of the template's repos, listing the template's snapshots show updated snapshots
  4. Trigger another snapshot of one of the repos in template. Once this task completes you should see that latest snapshot when listing the template's snapshots

@xbhouse xbhouse force-pushed the 4741 branch 4 times, most recently from aca123c to 6255c8d Compare October 1, 2024 21:21
@xbhouse xbhouse marked this pull request as ready for review October 2, 2024 15:38
@xbhouse xbhouse force-pushed the 4741 branch 2 times, most recently from a5a308b to 76d1694 Compare October 2, 2024 17:11
@jlsherrill
Copy link
Member

DROP CONSTRAINT IF EXISTS fk_templates_repository_configurations_snapshots,
ADD CONSTRAINT fk_templates_repository_configurations_snapshots
FOREIGN KEY (snapshot_uuid) REFERENCES snapshots(uuid)
ON DELETE SET NULL;
Copy link
Member

@jlsherrill jlsherrill Oct 7, 2024

Choose a reason for hiding this comment

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

One question is whether it should restrict the deletion or set the column null. If we restricted the deletion, it would require all snapshots to be updated for the template prior to deleting the snapshot.

If we allow for null, we could potentially end up with a null value. What would be the ramifications of that?

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 restricting the deletion instead makes sense, especially if we don't allow the snapshot_uuid to be null (see reply further down). and before deleting snapshots we should be updating the snapshots in the template anyway (looking at the ticket for delete and bulk-delete)

Select("snapshots.*, STRING_AGG(repository_configurations.name, '') as repo_name").
Where("repository_configuration_uuid IN ?", template.RepositoryUUIDS).
Joins("JOIN templates_repository_configurations ON templates_repository_configurations.snapshot_uuid = snapshots.uuid").
Where("snapshots.repository_configuration_uuid IN ?", template.RepositoryUUIDS).
Where("repository_configurations.name ILIKE ?", fmt.Sprintf("%%%s%%", repositorySearch)).
Copy link
Member

Choose a reason for hiding this comment

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

It looks like these lines are repeated between the count query and the actual query:

readableSnapshots(sDao.db.WithContext(ctx), orgID).
		Joins("JOIN templates_repository_configurations ON templates_repository_configurations.snapshot_uuid = snapshots.uuid").
		Where("snapshots.repository_configuration_uuid IN ?", template.RepositoryUUIDS).
		Where("repository_configurations.name ILIKE ?", fmt.Sprintf("%%%s%%", repositorySearch))

you can build a base query struct and re-use it for both

@@ -0,0 +1,11 @@
BEGIN;

ALTER TABLE templates_repository_configurations ADD COLUMN IF NOT EXISTS snapshot_uuid UUID DEFAULT NULL;
Copy link
Member

Choose a reason for hiding this comment

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

This question kinda goes to the question below about the ramifications around a null value here.

Would it be possible to (eventually) have the column be not null? (it might take more than 1 PR to pull this off).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

good point! i made the default snapshot_uuid value null because in the API we allow template creation with repositories without snapshots. if we wanted to make this not null, we'd have to validate that all repositories have snapshots before they're added to a template i think

Copy link
Contributor

Choose a reason for hiding this comment

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

I think we'd also need to migrate any existing snapshots that are in templates to be included on the table

FOREIGN KEY (snapshot_uuid) REFERENCES snapshots(uuid)
ON DELETE RESTRICT;

COMMIT;
Copy link
Member

Choose a reason for hiding this comment

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

do we want to make the snapshot_uuid column not null?

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 so, do you think we should do that here or in a following PR?

to do that we'd need to make sure all repos have snapshots before they're added to a template (which i've added in here). we'd also need to set not null on the column and the model, and since there would be a few seconds where the column would be null until the update-template-content task runs and adds in the snapshot uuids, creating a template would fail. so we'd probably need to add a method to insert the snapshots before the template is created. (and there might be some additional steps that i'm missing)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

pushed up these changes!

@@ -620,33 +620,6 @@ func (s *SnapshotsSuite) TestListByTemplate() {
assert.Equal(t, repoConfig2.UUID, snapshots.Data[1].RepositoryUUID)
}

func (s *SnapshotsSuite) TestListByTemplateNoRepos() {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

removed this test because templates should now always have snapshots

@@ -1,6 +1,6 @@
BEGIN;

ALTER TABLE templates_repository_configurations ADD COLUMN IF NOT EXISTS snapshot_uuid UUID;
ALTER TABLE templates_repository_configurations ADD COLUMN IF NOT EXISTS snapshot_uuid UUID NOT NULL;
Copy link
Member

Choose a reason for hiding this comment

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

you'd have to set it to NOT NULL after the update below

in fact you may want to do the update to set the values, and then delete any null row to be safe and only then set it to NOT NULL.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ohhh right, makes sense! just pushed up that fix

@jlsherrill
Copy link
Member

overall this seemed to work fine. I did see one error though if i:

  1. create a repo
  2. create a template and add the repo
  3. delete the repo

i get an error:

1:46PM WRN [Finished Task] task failed error="ERROR: update or delete on table \"snapshots\" violates foreign key constraint \"fk_templates_repository_configurations_snapshots\" on table \"templates_repository_configurations\" (SQLSTATE 23503)" request_id=4c0220f1-94d8-44cf-819d-6ef213c4c11c task_id=5c876540-ea47-4703-813e-bcd312e7ff87 task_type=delete-repository-snapshots

@xbhouse
Copy link
Contributor Author

xbhouse commented Oct 18, 2024

overall this seemed to work fine. I did see one error though if i:

  1. create a repo
  2. create a template and add the repo
  3. delete the repo

i get an error:

1:46PM WRN [Finished Task] task failed error="ERROR: update or delete on table \"snapshots\" violates foreign key constraint \"fk_templates_repository_configurations_snapshots\" on table \"templates_repository_configurations\" (SQLSTATE 23503)" request_id=4c0220f1-94d8-44cf-819d-6ef213c4c11c task_id=5c876540-ea47-4703-813e-bcd312e7ff87 task_type=delete-repository-snapshots

ah good catch. because we're restricting deletion we'll need to delete any rows from template_repo_configs with that repo's snapshot uuids before the repo is deleted. then the snapshot integration test updates are probably not necessary. fixing!

Copy link
Member

@jlsherrill jlsherrill left a comment

Choose a reason for hiding this comment

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

ACK!

@swadeley swadeley merged commit 629a778 into content-services:main Oct 21, 2024
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants