/
os_to_os.rb
162 lines (126 loc) · 5.19 KB
/
os_to_os.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
require_relative 'base'
module TransactionChains
# Migrate VPS between two OpenVZ nodes
class Vps::Migrate::OsToOs < Vps::Migrate::Base
label 'Migrate'
def link_chain(vps, dst_node, opts = {})
self.userns_map = vps.userns_map
setup(vps, dst_node, opts)
# Mail notification
notify_begun
# Transfer resources if the destination node is in a different
# environment.
transfer_cluster_resources
# Prepare userns
use_chain(UserNamespaceMap::Use, args: [src_vps.userns_map, dst_node])
# Copy configs
append(
Transactions::Vps::SendConfig,
args: [src_vps, dst_node, network_interfaces: true],
)
# Handle dataset resources
datasets.each do |pair|
src, dst = pair
# Transfer resources
if environment_changed?
# This code expects that the datasets have just one cluster resource,
# which is diskspace.
changes = src.transfer_resources_to_env!(user, dst_node.location.environment)
changes[changes.keys.first][:row_id] = dst.id
resources_changes.update(changes)
else
::ClusterResourceUse.for_obj(src).each do |use|
resources_changes[use] = {row_id: dst.id}
end
end
end
# Transfer datasets
unless @opts[:outage_window]
# Reserve a slot in zfs_send queue
append(Transactions::Queue::Reserve, args: [src_node, :zfs_send])
end
append(Transactions::Vps::SendRootfs, args: [src_vps])
if @opts[:outage_window]
# Wait for the outage window to open
append(Transactions::OutageWindow::Wait, args: [src_vps, 15])
append(Transactions::Queue::Reserve, args: [src_node, :zfs_send])
append(Transactions::OutageWindow::InOrFail, args: [src_vps, 15])
append(Transactions::Vps::SendSync, args: [src_vps], urgent: true)
# Check if we're still inside the outage window. We're in if the window
# closes in not less than 5 minutes. Fail if not.
append(Transactions::OutageWindow::InOrFail, args: [src_vps, 5], urgent: true)
end
# Stop the VPS
use_chain(Vps::Stop, args: src_vps, urgent: true)
# Send it to the target node
append(
Transactions::Vps::SendState,
args: [src_vps, start: false],
urgent: true,
)
dst_ip_addresses = vps.ip_addresses
# Migration to different location - remove or replace IP addresses
migrate_network_interfaces
# Regenerate mount scripts of the migrated VPS
mounts = Vps::Migrate::MountMigrator.new(self, vps, dst_vps)
mounts.datasets = datasets
mounts.remount_mine
# Wait for routing to remove routes from the original system
append(Transactions::Utils::NoOp, args: [find_node_id, sleep: 20], urgent: true)
# Restore VPS state
call_hooks_for(:pre_start, self, args: [dst_vps, was_running?])
use_chain(Vps::Start, args: dst_vps, urgent: true) if was_running?
call_hooks_for(:post_start, self, args: [dst_vps, was_running?])
# Release reserved spot in the queue
append(Transactions::Queue::Release, args: [src_node, :zfs_send], urgent: true)
# Move the dataset in pool to the new pool in the database
append_t(Transactions::Utils::NoOp, args: dst_node.id, urgent: true) do |t|
t.edit(src_vps, dataset_in_pool_id: datasets.first[1].id)
t.edit(src_vps, node_id: dst_node.id)
# Transfer resources
resources_changes.each do |use, changes|
t.edit(use, changes) unless changes.empty?
end
# Transfer datasets and properties
datasets.each do |src, dst|
src.dataset_properties.all.each do |p|
t.edit(p, dataset_in_pool_id: dst.id)
end
migrate_dataset_plans(src, dst, t)
t.destroy(src)
t.create(dst)
end
t.just_create(src_vps.log(:node, {
src: {id: src_node.id, name: src_node.domain_name},
dst: {id: dst_node.id, name: dst_node.domain_name},
}))
end
# Call DatasetInPool.migrated hook
datasets.each do |src, dst|
src.call_hooks_for(:migrated, self, args: [src, dst])
end
# Setup firewall and shapers
# Unregister from firewall and remove shaper on source node
if @opts[:handle_ips]
use_chain(Vps::FirewallUnregister, args: src_vps, urgent: true)
use_chain(Vps::ShaperUnset, args: src_vps, urgent: true)
end
# Is is needed to register IP in fw and shaper when changing location,
# as IPs are removed or replaced sooner.
unless location_changed?
# Register to firewall and set shaper on destination node
use_chain(Vps::FirewallRegister, args: [dst_vps, dst_ip_addresses], urgent: true)
use_chain(Vps::ShaperSet, args: [dst_vps, dst_ip_addresses], urgent: true)
end
# Destroy old VPS
append(Transactions::Vps::SendCleanup, args: src_vps)
append(Transactions::Vps::RemoveConfig, args: src_vps)
# Free userns map
use_chain(UserNamespaceMap::Disuse, args: [src_vps])
# Mail notification
notify_finished
# fail 'ohnoes'
self
end
end
end