diff --git a/db/docs/batched_background_migrations/update_workspaces_config_version3.yml b/db/docs/batched_background_migrations/update_workspaces_config_version3.yml new file mode 100644 index 0000000000000000000000000000000000000000..253feea046911a4574dd9747f04bed6601b84e80 --- /dev/null +++ b/db/docs/batched_background_migrations/update_workspaces_config_version3.yml @@ -0,0 +1,9 @@ +--- +migration_job_name: UpdateWorkspacesConfigVersion3 +description: Update config_version to 3 and force_include_all_resources to true for existing workspaces +feature_category: remote_development +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/140972 +milestone: '16.8' +queued_migration_version: 20240104085448 +finalize_after: "2024-02-15" +finalized_by: # version of the migration that finalized this BBM diff --git a/db/post_migrate/20240104085448_queue_update_workspaces_config_version3.rb b/db/post_migrate/20240104085448_queue_update_workspaces_config_version3.rb new file mode 100644 index 0000000000000000000000000000000000000000..574b6cdb4c2672edff31c61dd4f05e22d3d48287 --- /dev/null +++ b/db/post_migrate/20240104085448_queue_update_workspaces_config_version3.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +class QueueUpdateWorkspacesConfigVersion3 < Gitlab::Database::Migration[2.2] + milestone '16.8' + + MIGRATION = "UpdateWorkspacesConfigVersion3" + DELAY_INTERVAL = 2.minutes + BATCH_SIZE = 1000 + SUB_BATCH_SIZE = 100 + + restrict_gitlab_migration gitlab_schema: :gitlab_main + disable_ddl_transaction! + + def up + queue_batched_background_migration( + MIGRATION, + :workspaces, + :config_version, + job_interval: DELAY_INTERVAL, + batch_size: BATCH_SIZE, + sub_batch_size: SUB_BATCH_SIZE + ) + end + + def down + delete_batched_background_migration(MIGRATION, :workspaces, :config_version, []) + end +end diff --git a/db/schema_migrations/20240104085448 b/db/schema_migrations/20240104085448 new file mode 100644 index 0000000000000000000000000000000000000000..a73b6a090a37b373c3ed8e294aa06efb117b33ea --- /dev/null +++ b/db/schema_migrations/20240104085448 @@ -0,0 +1 @@ +57e5c890ac0ebb837a5894b09717322c2053694cc4a91270508a652f091e457c \ No newline at end of file diff --git a/ee/lib/ee/gitlab/background_migration/update_workspaces_config_version3.rb b/ee/lib/ee/gitlab/background_migration/update_workspaces_config_version3.rb new file mode 100644 index 0000000000000000000000000000000000000000..6fb0c8e325f7e7fcaf7d0db6fbd8a655ce8500e1 --- /dev/null +++ b/ee/lib/ee/gitlab/background_migration/update_workspaces_config_version3.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +module EE + module Gitlab + module BackgroundMigration + # This class is responsible for updating workspaces config_version and force_include_all_resources. + module UpdateWorkspacesConfigVersion3 + extend ActiveSupport::Concern + extend ::Gitlab::Utils::Override + + VERSION_2 = 2 + VERSION_3 = 3 + STATE_TERMINATED = 'Terminated' + + prepended do + operation_name :update + scope_to ->(relation) { + relation.where(config_version: VERSION_2) + .where.not(actual_state: STATE_TERMINATED) + } + feature_category :remote_development + end + + override :perform + def perform + each_sub_batch do |sub_batch| + sub_batch.update_all(config_version: VERSION_3, + force_include_all_resources: true) + end + end + end + end + end +end diff --git a/ee/spec/lib/gitlab/background_migration/update_workspaces_config_version3_spec.rb b/ee/spec/lib/gitlab/background_migration/update_workspaces_config_version3_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..8becb845cdeadb2a3da42baa77ca21133f796384 --- /dev/null +++ b/ee/spec/lib/gitlab/background_migration/update_workspaces_config_version3_spec.rb @@ -0,0 +1,100 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Gitlab::BackgroundMigration::UpdateWorkspacesConfigVersion3, feature_category: :remote_development do + describe "#perform" do + let(:v2) { 2 } + let(:v3) { 3 } + let(:personal_access_tokens_table) { table(:personal_access_tokens) } + let(:pat) do + personal_access_tokens_table.create!(name: 'workspace1', user_id: user.id, scopes: "---\n- api\n", + expires_at: 4.days.from_now) + end + + let(:workspace_attrs) do + { + user_id: user.id, + project_id: project.id, + cluster_agent_id: cluster_agent.id, + personal_access_token_id: pat.id, + desired_state_updated_at: 2.seconds.ago, + max_hours_before_termination: 19, + namespace: 'ns', + desired_state: 'Running', + editor: 'e', + devfile_ref: 'dfr', + devfile_path: 'dev/path', + url: 'https://www.example.org', + force_include_all_resources: false + } + end + + let(:namespace) { table(:namespaces).create!(name: 'namespace', path: 'namespace') } + let(:project) do + table(:projects).create!(name: 'project', path: 'project', project_namespace_id: namespace.id, + namespace_id: namespace.id) + end + + let(:cluster_agent) { table(:cluster_agents).create!(name: 'cluster_agent', project_id: project.id) } + let(:user) { table(:users).create!(email: 'author@example.com', username: 'author', projects_limit: 10) } + let(:workspaces_table) { table(:workspaces) } + let!(:workspace_with_config_2_actual_state_terminated) do + workspaces_table.create!({ + name: 'workspace1', + config_version: v2, + actual_state: 'Terminated' + }.merge!(workspace_attrs)) + end + + let!(:workspace_with_config_2_actual_state_running) do + workspaces_table.create!({ + name: 'workspace2', + config_version: v2, + actual_state: 'Running' + }.merge!(workspace_attrs)) + end + + let!(:workspace_with_config_3_actual_state_running) do + workspaces_table.create!({ + name: 'workspace3', + config_version: v3, + actual_state: 'Running' + }.merge!(workspace_attrs)) + end + + let(:migration) do + described_class.new( + start_id: workspace_with_config_2_actual_state_terminated.id, + end_id: workspace_with_config_3_actual_state_running.id, + batch_table: :workspaces, + batch_column: :id, + sub_batch_size: 2, + pause_ms: 0, + connection: ApplicationRecord.connection + ) + end + + it "updates config_version and force_include_all_resources for existing non-terminated workspaces" do + migration.perform + + workspace_with_config_2_actual_state_running.reload + + expect(workspace_with_config_2_actual_state_running.config_version).to eq(v3) + expect(workspace_with_config_2_actual_state_running.force_include_all_resources).to eq(true) + end + + it "does not update workspaces with different config_version or actual_state" do + migration.perform + + workspace_with_config_2_actual_state_terminated.reload + workspace_with_config_3_actual_state_running.reload + + expect(workspace_with_config_2_actual_state_terminated.config_version).to eq(v2) + expect(workspace_with_config_2_actual_state_terminated.force_include_all_resources).to eq(false) + + expect(workspace_with_config_3_actual_state_running.config_version).to eq(v3) + expect(workspace_with_config_3_actual_state_running.force_include_all_resources).to eq(false) + end + end +end diff --git a/ee/spec/migrations/20240104085448_queue_update_workspaces_config_version3_spec.rb b/ee/spec/migrations/20240104085448_queue_update_workspaces_config_version3_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..b2f8fc1fa878c25e6838af405a8763d829c7657d --- /dev/null +++ b/ee/spec/migrations/20240104085448_queue_update_workspaces_config_version3_spec.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe QueueUpdateWorkspacesConfigVersion3, feature_category: :remote_development do + let!(:batched_migration) { described_class::MIGRATION } + + it 'schedules a new batched migration' do + reversible_migration do |migration| + migration.before -> { + expect(batched_migration).not_to have_scheduled_batched_migration + } + + migration.after -> { + expect(batched_migration).to have_scheduled_batched_migration( + table_name: :workspaces, + column_name: :config_version, + interval: described_class::DELAY_INTERVAL, + batch_size: described_class::BATCH_SIZE, + sub_batch_size: described_class::SUB_BATCH_SIZE + ) + } + end + end +end diff --git a/lib/gitlab/background_migration/update_workspaces_config_version3.rb b/lib/gitlab/background_migration/update_workspaces_config_version3.rb new file mode 100644 index 0000000000000000000000000000000000000000..8626f7f608de6ed178f8970912291bc716b41bd1 --- /dev/null +++ b/lib/gitlab/background_migration/update_workspaces_config_version3.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +module Gitlab + module BackgroundMigration + # No op on ce + class UpdateWorkspacesConfigVersion3 < BatchedMigrationJob + feature_category :remote_development + def perform; end + end + end +end + +Gitlab::BackgroundMigration::UpdateWorkspacesConfigVersion3.prepend_mod_with('Gitlab::BackgroundMigration::UpdateWorkspacesConfigVersion3') # rubocop:disable Layout/LineLength -- Injecting extension modules must be done on the last line of this file, outside of any class or module definitions