Properly handle native imports

🐇 Context

We're currently implement a data migration on the Container Registry. This migration is going to be driven by the rails backend.

We're not going to detail all the details here but basically the migration goes through different states. Those states are implemented as a state machine on the ContainerRepository model.

Under some conditions, we can hit situations where the image repository considered is already migrated on the Container Registry side. This can happen as new image repositories were incrementally created under the migrated data. This means that in the existing repositories that we need to migrate, we can pick up a repository that was actually already under the migrated data.

We need to take this into account and when the Container Registry answers: "hey, this image repository is already migrated", we need to update the state accordingly. This is issue #356562 (closed).

Last piece of context: this migration logic is gated behind a feature flag that is not enabled on gitlab.com.

The above issue was discovered during the testing we're conducting on staging.

🤔 What does this MR do and why?

  • In ContainerRepository#reconcile_import_status or ContainerRepository#try_import, when we hit an already migrated repository, we:
    • Update the migration status to import_done
    • Update the skip reason to native_import
  • Update the related specs

🖼 Screenshots or screen recordings

n / a

How to set up and validate locally

  1. Have a GDK ready with the registry enabled.
  2. Set up the feature flags:
    Feature.enable(:container_registry_migration_phase2_enabled)

We are ready to test things.

1️⃣ Reconcile status

  1. Create a dummy image that is importing:
    repo = FactoryBot.create(:container_repository, :importing, project: Project.first)
  2. Call the #reconcile_status method:
    repo.reconcile_import_status('native')
  3. Check the repo:
    repo.reload
    => #<ContainerRepository:0x00007fb46b680020
     id: 29,
     project_id: 1,
     name: "test_image_2",
     created_at: Tue, 22 Mar 2022 19:23:53.036852000 UTC +00:00,
     updated_at: Tue, 22 Mar 2022 19:24:17.252497000 UTC +00:00,
     status: nil,
     expiration_policy_started_at: nil,
     expiration_policy_cleanup_status: "cleanup_unscheduled",
     expiration_policy_completed_at: nil,
     migration_pre_import_started_at: Tue, 22 Mar 2022 19:23:53.034138000 UTC +00:00,
     migration_pre_import_done_at: Tue, 22 Mar 2022 19:23:53.034169000 UTC +00:00,
     migration_import_started_at: Tue, 22 Mar 2022 19:23:53.034181000 UTC +00:00,
     migration_import_done_at: Tue, 22 Mar 2022 19:24:17.249280000 UTC +00:00,
     migration_aborted_at: nil,
     migration_skipped_at: nil,
     migration_retries_count: 0,
     migration_skipped_reason: "native_import",
     migration_state: "import_done",
     migration_aborted_in_state: nil,
     migration_plan: nil>

The migration state is import_done and the skip reason is native_import

2️⃣ Starting pre import

  1. Create a dummy image:
    repo = FactoryBot.create(:container_repository, project: Project.first)
  2. Getting a registry set up with all the parts for the migration is quite involved. Instead we're going to "stub" the registry response from the pre import call. Replace ContainerRepository#migration_pre_import with:
    def migration_pre_import
       :already_imported
    end
  3. Reload the console if necessary:
    reload!
  4. Start the pre-import:
    repo.start_pre_import
  5. Inspect the repo:
    repo
    => #<ContainerRepository:0x00007fb44c0f57a0
     id: 31,
     project_id: 1,
     name: "test_image_4",
     created_at: Tue, 22 Mar 2022 19:34:01.161182000 UTC +00:00,
     updated_at: Tue, 22 Mar 2022 19:34:09.199468000 UTC +00:00,
     status: nil,
     expiration_policy_started_at: nil,
     expiration_policy_cleanup_status: "cleanup_unscheduled",
     expiration_policy_completed_at: nil,
     migration_pre_import_started_at: Tue, 22 Mar 2022 19:34:09.191250000 UTC +00:00,
     migration_pre_import_done_at: nil,
     migration_import_started_at: nil,
     migration_import_done_at: nil,
     migration_aborted_at: nil,
     migration_skipped_at: nil,
     migration_retries_count: 0,
     migration_skipped_reason: "native_import",
     migration_state: "import_done",
     migration_aborted_in_state: nil,
     migration_plan: nil>

The migration state is import_done and the skip reason is native_import

MR acceptance checklist

This checklist encourages us to confirm any changes have been analyzed to reduce risks in quality, performance, reliability, security, and maintainability.

Edited by David Fernandez

Merge request reports

Loading