Commit 79e52641 authored by Michał Zając's avatar Michał Zając

Change JiraTrackerData#deployment_type based on URL

We have around 90k records for this table where deployment_type is
unknown. Our logic for JIRA integration started to diverge depending on
whether the user is trying to integrate with JIRA Cloud or JIRA Server.

This migration will try determining what is the deployment type for
every entry in jira_tracker_data table based on the URL.

The logic is simple – if URL ends in `atlassian.net` then most likely
we're dealing with JIRA Cloud, otherwise it's JIRA Server.

Changelog: other
parent 749e732b
# frozen_string_literal: true
class ScheduleUpdateJiraTrackerDataDeploymentTypeBasedOnUrl < ActiveRecord::Migration[6.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
MIGRATION = 'UpdateJiraTrackerDataDeploymentTypeBasedOnUrl'
DELAY_INTERVAL = 2.minutes.to_i
BATCH_SIZE = 2_500
disable_ddl_transaction!
def up
say "Scheduling #{MIGRATION} jobs"
queue_background_migration_jobs_by_range_at_intervals(
define_batchable_model('jira_tracker_data'),
MIGRATION,
DELAY_INTERVAL,
batch_size: BATCH_SIZE
)
end
def down
# no-op
end
end
0f6019cc094481cafbf0c9bd42f53ae09034ea87e3f360b02f9ec03192caab9d
\ No newline at end of file
# frozen_string_literal: true
# rubocop: disable Style/Documentation
class Gitlab::BackgroundMigration::UpdateJiraTrackerDataDeploymentTypeBasedOnUrl
# rubocop: disable Gitlab/NamespacedClass
class JiraTrackerData < ActiveRecord::Base
self.table_name = "jira_tracker_data"
self.inheritance_column = :_type_disabled
include ::Integrations::BaseDataFields
attr_encrypted :url, encryption_options
attr_encrypted :api_url, encryption_options
enum deployment_type: { unknown: 0, server: 1, cloud: 2 }, _prefix: :deployment
end
# rubocop: enable Gitlab/NamespacedClass
# https://rubular.com/r/uwgK7k9KH23efa
JIRA_CLOUD_REGEX = %r{^https?://[A-Za-z0-9](?:[A-Za-z0-9\-]{0,61}[A-Za-z0-9])?\.atlassian\.net$}ix.freeze
# rubocop: disable CodeReuse/ActiveRecord
def perform(start_id, end_id)
trackers_data = JiraTrackerData
.where(deployment_type: 'unknown')
.where(id: start_id..end_id)
cloud, server = trackers_data.partition { |tracker_data| tracker_data.url.match?(JIRA_CLOUD_REGEX) }
cloud_mappings = cloud.each_with_object({}) do |tracker_data, hash|
hash[tracker_data] = { deployment_type: 2 }
end
server_mapppings = server.each_with_object({}) do |tracker_data, hash|
hash[tracker_data] = { deployment_type: 1 }
end
mappings = cloud_mappings.merge(server_mapppings)
::Gitlab::Database::BulkUpdate.execute(%i[deployment_type], mappings)
end
# rubocop: enable CodeReuse/ActiveRecord
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Gitlab::BackgroundMigration::UpdateJiraTrackerDataDeploymentTypeBasedOnUrl do
let(:services_table) { table(:services) }
let(:service_jira_cloud) { services_table.create!(id: 1, type: 'JiraService') }
let(:service_jira_server) { services_table.create!(id: 2, type: 'JiraService') }
before do
jira_tracker_data = Class.new(ApplicationRecord) do
self.table_name = 'jira_tracker_data'
def self.encryption_options
{
key: Settings.attr_encrypted_db_key_base_32,
encode: true,
mode: :per_attribute_iv,
algorithm: 'aes-256-gcm'
}
end
attr_encrypted :url, encryption_options
attr_encrypted :api_url, encryption_options
attr_encrypted :username, encryption_options
attr_encrypted :password, encryption_options
end
stub_const('JiraTrackerData', jira_tracker_data)
end
let!(:tracker_data_cloud) { JiraTrackerData.create!(id: 1, service_id: service_jira_cloud.id, url: "https://test-domain.atlassian.net", deployment_type: 0) }
let!(:tracker_data_server) { JiraTrackerData.create!(id: 2, service_id: service_jira_server.id, url: "http://totally-not-jira-server.company.org", deployment_type: 0) }
subject { described_class.new.perform(tracker_data_cloud.id, tracker_data_server.id) }
it "changes unknown deployment_types based on URL" do
expect(JiraTrackerData.pluck(:deployment_type)).to eq([0, 0])
subject
expect(JiraTrackerData.pluck(:deployment_type)).to eq([2, 1])
end
end
# frozen_string_literal: true
require 'spec_helper'
require Rails.root.join('db', 'post_migrate', '20210421163509_schedule_update_jira_tracker_data_deployment_type_based_on_url.rb')
RSpec.describe ScheduleUpdateJiraTrackerDataDeploymentTypeBasedOnUrl, :migration do
let(:services_table) { table(:services) }
let(:service_jira_cloud) { services_table.create!(id: 1, type: 'JiraService') }
let(:service_jira_server) { services_table.create!(id: 2, type: 'JiraService') }
before do
jira_tracker_data = Class.new(ApplicationRecord) do
self.table_name = 'jira_tracker_data'
def self.encryption_options
{
key: Settings.attr_encrypted_db_key_base_32,
encode: true,
mode: :per_attribute_iv,
algorithm: 'aes-256-gcm'
}
end
attr_encrypted :url, encryption_options
attr_encrypted :api_url, encryption_options
attr_encrypted :username, encryption_options
attr_encrypted :password, encryption_options
end
stub_const('JiraTrackerData', jira_tracker_data)
stub_const("#{described_class}::BATCH_SIZE", 1)
end
let!(:tracker_data_cloud) { JiraTrackerData.create!(id: 1, service_id: service_jira_cloud.id, url: "https://test-domain.atlassian.net", deployment_type: 0) }
let!(:tracker_data_server) { JiraTrackerData.create!(id: 2, service_id: service_jira_server.id, url: "http://totally-not-jira-server.company.org", deployment_type: 0) }
around do |example|
freeze_time { Sidekiq::Testing.fake! { example.run } }
end
it 'schedules background migration' do
migrate!
expect(BackgroundMigrationWorker.jobs.size).to eq(2)
expect(described_class::MIGRATION).to be_scheduled_migration(tracker_data_cloud.id, tracker_data_cloud.id)
expect(described_class::MIGRATION).to be_scheduled_migration(tracker_data_server.id, tracker_data_server.id)
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment