diff --git a/db/docs/batched_background_migrations/update_workspaces_config_version.yml b/db/docs/batched_background_migrations/update_workspaces_config_version.yml new file mode 100644 index 0000000000000000000000000000000000000000..50cdfe1f2e9243438ca4bfd475c8cfb692939e4e --- /dev/null +++ b/db/docs/batched_background_migrations/update_workspaces_config_version.yml @@ -0,0 +1,5 @@ +migration_job_name: UpdateWorkspacesConfigVersion +description: Update config_version to 2 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/131402 +milestone: 16.5 diff --git a/db/post_migrate/20230910120000_queue_update_workspaces_config_version.rb b/db/post_migrate/20230910120000_queue_update_workspaces_config_version.rb new file mode 100644 index 0000000000000000000000000000000000000000..499e5cec11c09e1610b1af4212993c0bee7848f7 --- /dev/null +++ b/db/post_migrate/20230910120000_queue_update_workspaces_config_version.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +class QueueUpdateWorkspacesConfigVersion < Gitlab::Database::Migration[2.1] + MIGRATION = "UpdateWorkspacesConfigVersion" + DELAY_INTERVAL = 2.minutes + BATCH_SIZE = 100 + SUB_BATCH_SIZE = 20 + + restrict_gitlab_migration gitlab_schema: :gitlab_main + disable_ddl_transaction! + + def up + queue_batched_background_migration( + MIGRATION, + :workspaces, + :id, + job_interval: DELAY_INTERVAL, + batch_size: BATCH_SIZE, + sub_batch_size: SUB_BATCH_SIZE + ) + end + + def down + delete_batched_background_migration(MIGRATION, :workspaces, :id, []) + end +end diff --git a/db/schema_migrations/20230910120000 b/db/schema_migrations/20230910120000 new file mode 100644 index 0000000000000000000000000000000000000000..ffef50b3e9ef2d8ed4d17d05abf554a413b6e4e6 --- /dev/null +++ b/db/schema_migrations/20230910120000 @@ -0,0 +1 @@ +a57042e0086761ca054dd8272024f1f086ae3932930e57126c64033e7a688cbd \ No newline at end of file diff --git a/ee/lib/ee/gitlab/background_migration/update_workspaces_config_version.rb b/ee/lib/ee/gitlab/background_migration/update_workspaces_config_version.rb new file mode 100644 index 0000000000000000000000000000000000000000..930b8866cc178897716c6112a6ab79d02dc0e295 --- /dev/null +++ b/ee/lib/ee/gitlab/background_migration/update_workspaces_config_version.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 UpdateWorkspacesConfigVersion + extend ActiveSupport::Concern + extend ::Gitlab::Utils::Override + + VERSION_1 = 1 + VERSION_2 = 2 + STATE_TERMINATED = 'Terminated' + + prepended do + operation_name :update + scope_to ->(relation) { + relation.where(config_version: VERSION_1) + .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_2, + force_include_all_resources: true) + end + end + end + end + end +end diff --git a/ee/spec/lib/gitlab/background_migration/update_workspaces_config_version_spec.rb b/ee/spec/lib/gitlab/background_migration/update_workspaces_config_version_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..c2351e69a331b8de50b5164fbf4e1c11b2965246 --- /dev/null +++ b/ee/spec/lib/gitlab/background_migration/update_workspaces_config_version_spec.rb @@ -0,0 +1,99 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Gitlab::BackgroundMigration::UpdateWorkspacesConfigVersion, feature_category: :remote_development do + describe "#perform" do + let(:v1) { RemoteDevelopment::Workspaces::ConfigVersion::VERSION_1 } + let(:v2) { RemoteDevelopment::Workspaces::ConfigVersion::VERSION_2 } + 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: ::RemoteDevelopment::Workspaces::States::RUNNING, + editor: 'e', + devfile_ref: 'dfr', + devfile_path: 'dev/path', + url: 'https://www.example.org' + } + 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_1_actual_state_terminated) do + workspaces_table.create!({ + name: 'workspace1', + config_version: v1, + actual_state: ::RemoteDevelopment::Workspaces::States::TERMINATED + }.merge!(workspace_attrs)) + end + + let!(:workspace_with_config_1_actual_state_running) do + workspaces_table.create!({ + name: 'workspace2', + config_version: v1, + actual_state: ::RemoteDevelopment::Workspaces::States::RUNNING + }.merge!(workspace_attrs)) + end + + let!(:workspace_with_config_2_actual_state_running) do + workspaces_table.create!({ + name: 'workspace3', + config_version: v2, + actual_state: ::RemoteDevelopment::Workspaces::States::RUNNING + }.merge!(workspace_attrs)) + end + + let(:migration) do + described_class.new( + start_id: workspace_with_config_1_actual_state_terminated.id, + end_id: workspace_with_config_2_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_1_actual_state_running.reload + + expect(workspace_with_config_1_actual_state_running.config_version).to eq(v2) + expect(workspace_with_config_1_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_1_actual_state_terminated.reload + workspace_with_config_2_actual_state_running.reload + + expect(workspace_with_config_1_actual_state_terminated.config_version).to eq(v1) + expect(workspace_with_config_1_actual_state_terminated.force_include_all_resources).to eq(false) + + expect(workspace_with_config_2_actual_state_running.config_version).to eq(v2) + expect(workspace_with_config_2_actual_state_running.force_include_all_resources).to eq(false) + end + end +end diff --git a/ee/spec/migrations/20230901120000_queue_update_workspaces_config_version_spec.rb b/ee/spec/migrations/20230901120000_queue_update_workspaces_config_version_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..93b59bdacf14d1594dd3eb5f152691b8304a195b --- /dev/null +++ b/ee/spec/migrations/20230901120000_queue_update_workspaces_config_version_spec.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe QueueUpdateWorkspacesConfigVersion, 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: :id, + interval: described_class::DELAY_INTERVAL.to_i, + 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_version.rb b/lib/gitlab/background_migration/update_workspaces_config_version.rb new file mode 100644 index 0000000000000000000000000000000000000000..77a7fc1bccaaa36cd8eeaa8700f0d9e08540958b --- /dev/null +++ b/lib/gitlab/background_migration/update_workspaces_config_version.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +module Gitlab + module BackgroundMigration + # No op on ce + class UpdateWorkspacesConfigVersion < BatchedMigrationJob + feature_category :remote_development + def perform; end + end + end +end + +Gitlab::BackgroundMigration::UpdateWorkspacesConfigVersion.prepend_mod_with('Gitlab::BackgroundMigration::UpdateWorkspacesConfigVersion') # rubocop:disable Layout/LineLength