Skip to content

Create rake task to cleanup wrongly provisioned add-on purchases

What does this MR do and why?

Create rake task to cleanup wrongly provisioned add-on purchases. For more information see the related issue here. The one-time rake task will only be executed for gitlab-org (ID 9970) and gitlab-com (ID 6543).

This MR will be executed as part of the CR here.

MR acceptance checklist

Please evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.

Queries

Namespace

Namespace.find_by(id: 22)
SELECT "namespaces"."id", "namespaces"."name", "namespaces"."path", "namespaces"."owner_id", "namespaces"."created_at", "namespaces"."updated_at", "namespaces"."type", "namespaces"."description", "namespaces"."avatar", "namespaces"."membership_lock", "namespaces"."share_with_group_lock", "namespaces"."visibility_level", "namespaces"."request_access_enabled", "namespaces"."ldap_sync_status", "namespaces"."ldap_sync_error", "namespaces"."ldap_sync_last_update_at", "namespaces"."ldap_sync_last_successful_update_at", "namespaces"."ldap_sync_last_sync_at", "namespaces"."description_html", "namespaces"."lfs_enabled", "namespaces"."parent_id", "namespaces"."shared_runners_minutes_limit", "namespaces"."repository_size_limit", "namespaces"."require_two_factor_authentication", "namespaces"."two_factor_grace_period", "namespaces"."cached_markdown_version", "namespaces"."project_creation_level", "namespaces"."runners_token", "namespaces"."file_template_project_id", "namespaces"."saml_discovery_token", "namespaces"."runners_token_encrypted", "namespaces"."custom_project_templates_group_id", "namespaces"."auto_devops_enabled", "namespaces"."extra_shared_runners_minutes_limit", "namespaces"."last_ci_minutes_notification_at", "namespaces"."last_ci_minutes_usage_notification_level", "namespaces"."subgroup_creation_level", "namespaces"."max_pages_size", "namespaces"."max_artifacts_size", "namespaces"."mentions_disabled", "namespaces"."default_branch_protection", "namespaces"."max_personal_access_token_lifetime", "namespaces"."push_rule_id", "namespaces"."shared_runners_enabled", "namespaces"."allow_descendants_override_disabled_shared_runners", "namespaces"."traversal_ids", "namespaces"."organization_id" FROM "namespaces" WHERE "namespaces"."id" = 22 LIMIT 1
SELECT "feature_gates"."key", "feature_gates"."value" FROM "feature_gates" WHERE "feature_gates"."feature_key" = 'cached_route_lookups' 
SELECT "routes".* FROM "routes" WHERE "routes"."source_id" = 22 AND "routes"."source_type" = 'Namespace' LIMIT 1 

Add-on purchases

GitlabSubscriptions::AddOnPurchase.by_namespace(namespace).for_gitlab_duo_pro.first
SELECT "subscription_add_ons"."id" FROM "subscription_add_ons" WHERE "subscription_add_ons"."name" = 1 LIMIT 1
SELECT "subscription_add_on_purchases".* FROM "subscription_add_on_purchases" WHERE "subscription_add_on_purchases"."namespace_id" = 22 AND "subscription_add_on_purchases"."subscription_add_on_id" = 1 ORDER BY "subscription_add_on_purchases"."id" ASC LIMIT 1
GitlabSubscriptions::AddOnPurchase.by_namespace(namespace).for_duo_enterprise.first
SELECT "subscription_add_ons"."id" FROM "subscription_add_ons" WHERE "subscription_add_ons"."name" = 3 LIMIT 1
SELECT "subscription_add_on_purchases".* FROM "subscription_add_on_purchases" WHERE "subscription_add_on_purchases"."namespace_id" = 22 AND "subscription_add_on_purchases"."subscription_add_on_id" = 3 ORDER BY "subscription_add_on_purchases"."id" ASC LIMIT 1

Destroy redundant Duo Enterprise add-on purchase

duo_enterprise.destroy
SAVEPOINT active_record_1
DELETE FROM "subscription_add_on_purchases" WHERE "subscription_add_on_purchases"."id" = 232
RELEASE SAVEPOINT active_record_1

Upgrade Duo Pro add-on purchase to Duo Enterprise

duo_pro.update(add_on: GitlabSubscriptions::AddOn.find_by(name: "duo_enterprise"))
SELECT "subscription_add_ons".* FROM "subscription_add_ons" WHERE "subscription_add_ons"."name" = 3 LIMIT 1
SAVEPOINT active_record_1
SELECT 1 AS one FROM "subscription_add_on_purchases" WHERE "subscription_add_on_purchases"."subscription_add_on_id" = 232 AND "subscription_add_on_purchases"."id" != 231 AND "subscription_add_on_purchases"."namespace_id" = 166 LIMIT 1
UPDATE "subscription_add_on_purchases" SET "updated_at" = '2024-10-18 08:52:24.579714', "subscription_add_on_id" = 232 WHERE "subscription_add_on_purchases"."id" = 23
RELEASE SAVEPOINT active_record_1

Screenshots or screen recordings

Screenshots are required for UI changes, and strongly recommended for all other merge requests.

Before After

How to set up and validate locally

  1. Create a group with an Ultimate subscription with Duo Pro

  2. Assign Duo Pro seats to group users.

  3. Simulate the old version of the rake task with the sync service by manually creating a Duo Enterprise add-on purchase.

    GitlabSubscriptions::AddOnPurchase.create(
      expires_on: 1.year.from_now,
      started_at: Date.current,
      namespace: Group.first,
      quantity: 100,
      purchase_xid: "test-purchase-xid",
      subscription_add_on_id: GitlabSubscriptions::AddOn.find_or_create_by_name("duo_enterprise").id,
      organization_id: Organizations::Organization.first.id
    )
  4. Assign Duo Enterprise seats to others and also to the same group users.

  5. Execute the rake task with the namespace ID of your test group.

  6. Check the database to see if the Duo Enterprise add-on purchase got deleted.

  7. Check the database to see if Duo Pro was upgraded to Duo Enterprise.

  8. Check the GitLab Duo UI to see that all previously and newly assigned users are still assigned to the new Duo Enterprise add-on purchase

Resolves #499698

Edited by Lukas Wanko

Merge request reports

Loading