Files
ubicloud/migrate/20240121_move_fw_rules.rb
Furkan Sahin 2e8c29e474 Migrate firewall_rules from ps to firewall entity
This commit implements the migration of current firewall rules from a
private subnet specific form into a more structured form. First of all,
we create a new entity called `Firewall` which represents the sum of all
of the firewall rules per resource. Secondly, we are breaking the
firewall-private_subnet relationship and make it a part of the vm
resource. This way, we are able to apply different firewalls to
individual resources in the same subnet. Therefore, customers have a
more granular control over the accessibility of the resources. An
advantages use case would be, simply shutting down all of the access
into a database from public internet and allowing application VMs to be
accessible. Migration work consists of 4 individual steps;
1. Create the new `Firewall` entity.
2. Add a new column `firewall_id` to the firewall_rule entity.
3. Create new `firewall` entity for all of the VMs in the system.
4. Repopulate copies of the current firewall_rules per VM since in the
old system, there was only 1 copy for all of the resources in the same
subnet.
2024-02-01 11:30:43 +01:00

88 lines
2.4 KiB
Ruby

# frozen_string_literal: true
Sequel.migration do
up do
create_table(:firewall) do
column :id, :uuid, primary_key: true
column :name, :text, null: false, default: "Default"
column :description, :text, null: false, default: "Default firewall"
column :created_at, :timestamp, null: false, default: Sequel::CURRENT_TIMESTAMP
foreign_key :vm_id, :vm, type: :uuid, null: true
end
alter_table(:firewall_rule) do
add_foreign_key :firewall_id, :firewall, null: true, type: :uuid
rename_column :ip, :cidr
set_column_allow_null :private_subnet_id
add_unique_constraint [:cidr, :port_range, :firewall_id]
end
run <<~SQL
INSERT INTO firewall (id, name, description, vm_id)
SELECT id, 'Default', 'Default firewall', id FROM vm;
SQL
# populate firewall rules per vm
run <<~SQL
WITH vm_subnet_mapping AS (
SELECT
vm.id AS vm_id,
nic.private_subnet_id
FROM
vm
INNER JOIN
nic ON vm.id = nic.vm_id
),
new_firewall_rules AS (
SELECT
gen_random_uuid() AS id, -- Generate new UUIDs for the id
fwr.cidr as cidr,
fwr.port_range as port_range,
vm_subnet_mapping.vm_id AS firewall_id
FROM
firewall_rule fwr
INNER JOIN
vm_subnet_mapping ON vm_subnet_mapping.private_subnet_id = fwr.private_subnet_id
)
INSERT INTO firewall_rule (id, cidr, port_range, firewall_id)
SELECT id, cidr, port_range, firewall_id FROM new_firewall_rules;
SQL
end
down do
# Populate the private_subnet_id column
run <<~SQL
UPDATE firewall_rule fr
SET private_subnet_id = (
SELECT n.private_subnet_id
FROM nic n
INNER JOIN vm ON vm.id = n.vm_id
INNER JOIN firewall f ON f.vm_id = vm.id
WHERE f.id = fr.firewall_id
LIMIT 1
)
WHERE fr.firewall_id IS NOT NULL;
SQL
# Remove duplicates, keeping only one rule per subnet
run <<~SQL
DELETE FROM firewall_rule
WHERE ctid NOT IN (
SELECT MIN(ctid)
FROM firewall_rule
GROUP BY private_subnet_id, cidr, port_range
);
SQL
# Remove the firewall_id column from firewall_rule
alter_table(:firewall_rule) do
drop_column :firewall_id
set_column_not_null :private_subnet_id
add_unique_constraint [:cidr, :port_range, :private_subnet_id]
end
# Drop the firewall table
drop_table(:firewall)
end
end