snapsync 0.1.5 → 0.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/Gemfile +3 -0
- data/lib/snapsync.rb +1 -0
- data/lib/snapsync/auto_sync.rb +88 -34
- data/lib/snapsync/cleanup.rb +4 -4
- data/lib/snapsync/cli.rb +57 -10
- data/lib/snapsync/default_sync_policy.rb +2 -2
- data/lib/snapsync/local_sync.rb +15 -4
- data/lib/snapsync/local_target.rb +2 -1
- data/lib/snapsync/sync.rb +50 -0
- data/lib/snapsync/sync_all.rb +21 -29
- data/lib/snapsync/sync_last_policy.rb +2 -2
- data/lib/snapsync/timeline_sync_policy.rb +8 -5
- data/lib/snapsync/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1f9224076ddb7de222c830cb7ad068742631d46b
|
4
|
+
data.tar.gz: b3ced85dbdc080938b61ec158e8d803f72ebeed1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c26502e714514d0d8f686c62a3d237ded6c85f0cd1a665b2d55d340d357c40aa139a36d5040f371fc719d80aa1c7010654199b6de47b3f2534bae1a3871bb56d
|
7
|
+
data.tar.gz: 0c67490d86f8ad9fc007e88a7c9054883be9f45ee94410ca18dd55dbc6e422620b90f33406693ff44817a13c70f262253cc9283f568035a50b2b029b2ae56aa8
|
data/.gitignore
CHANGED
data/Gemfile
CHANGED
data/lib/snapsync.rb
CHANGED
data/lib/snapsync/auto_sync.rb
CHANGED
@@ -11,13 +11,21 @@ module Snapsync
|
|
11
11
|
attr_reader :targets
|
12
12
|
attr_reader :partitions
|
13
13
|
|
14
|
+
DEFAULT_CONFIG_PATH = Pathname.new('/etc/snapsync.conf')
|
15
|
+
|
16
|
+
def self.load_default
|
17
|
+
result = new
|
18
|
+
result.load_config
|
19
|
+
result
|
20
|
+
end
|
21
|
+
|
14
22
|
def initialize(config_dir = SnapperConfig.default_config_dir)
|
15
23
|
@config_dir = config_dir
|
16
24
|
@targets = Hash.new
|
17
25
|
@partitions = PartitionsMonitor.new
|
18
26
|
end
|
19
27
|
|
20
|
-
def load_config(path)
|
28
|
+
def load_config(path = DEFAULT_CONFIG_PATH)
|
21
29
|
conf = YAML.load(path.read) || Array.new
|
22
30
|
parse_config(conf)
|
23
31
|
end
|
@@ -32,7 +40,7 @@ module Snapsync
|
|
32
40
|
end
|
33
41
|
|
34
42
|
def write_config(path)
|
35
|
-
data =
|
43
|
+
data = each_autosync_target.map do |target|
|
36
44
|
Hash['partition_uuid' => target.partition_uuid,
|
37
45
|
'path' => target.path.to_s,
|
38
46
|
'automount' => !!target.automount,
|
@@ -43,13 +51,86 @@ module Snapsync
|
|
43
51
|
end
|
44
52
|
end
|
45
53
|
|
46
|
-
|
54
|
+
# Enumerates the declared autosync targets
|
55
|
+
#
|
56
|
+
# @yieldparam [AutoSync] target
|
57
|
+
# @return [void]
|
58
|
+
def each_autosync_target
|
47
59
|
return enum_for(__method__) if !block_given?
|
48
60
|
targets.each_value do |targets|
|
49
61
|
targets.each { |t| yield(t) }
|
50
62
|
end
|
51
63
|
end
|
52
64
|
|
65
|
+
# Enumerates the available autosync targets
|
66
|
+
#
|
67
|
+
# It may mount partitions as needed
|
68
|
+
#
|
69
|
+
# @yieldparam [Pathname] path the path to the target's base dir
|
70
|
+
# (suitable to be processed by e.g. AutoSync)
|
71
|
+
# @yieldparam [AutoSyncTarget] target the target located at 'path'
|
72
|
+
# @return [void]
|
73
|
+
def each_available_autosync_target
|
74
|
+
return enum_for(__method__) if !block_given?
|
75
|
+
partitions.poll
|
76
|
+
|
77
|
+
partitions.known_partitions.each do |uuid, fs|
|
78
|
+
autosync_targets = targets[uuid]
|
79
|
+
next if autosync_targets.empty?
|
80
|
+
|
81
|
+
mp = fs['MountPoints'].first
|
82
|
+
if mp
|
83
|
+
mp = Pathname.new(mp[0..-2].pack("U*"))
|
84
|
+
end
|
85
|
+
|
86
|
+
begin
|
87
|
+
mounted = false
|
88
|
+
|
89
|
+
if !mp
|
90
|
+
if !autosync_targets.any?(&:automount)
|
91
|
+
Snapsync.info "partition #{uuid} is present, but not mounted and automount is false. Ignoring"
|
92
|
+
next
|
93
|
+
end
|
94
|
+
|
95
|
+
Snapsync.info "partition #{uuid} is present, but not mounted, automounting"
|
96
|
+
begin
|
97
|
+
mp = fs.Mount([]).first
|
98
|
+
rescue Exception => e
|
99
|
+
Snapsync.warn "failed to mount, ignoring this target"
|
100
|
+
next
|
101
|
+
end
|
102
|
+
mp = Pathname.new(mp)
|
103
|
+
mounted = true
|
104
|
+
end
|
105
|
+
|
106
|
+
autosync_targets.each do |target|
|
107
|
+
yield(mp + target.path, target)
|
108
|
+
end
|
109
|
+
|
110
|
+
ensure
|
111
|
+
if mounted
|
112
|
+
fs.Unmount([])
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
# Enumerates the available synchronization targets
|
119
|
+
#
|
120
|
+
# It may mount partitions as needed
|
121
|
+
#
|
122
|
+
# @yieldparam [LocalTarget] target the available target
|
123
|
+
# @return [void]
|
124
|
+
def each_available_target
|
125
|
+
return enum_for(__method__) if !block_given?
|
126
|
+
each_available_autosync_target do |path, t|
|
127
|
+
op = SyncAll.new(path, config_dir: config_dir)
|
128
|
+
op.each_target do |target|
|
129
|
+
yield(target)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
53
134
|
def add(target)
|
54
135
|
targets[target.partition_uuid] ||= Array.new
|
55
136
|
targets[target.partition_uuid] << target
|
@@ -67,37 +148,10 @@ module Snapsync
|
|
67
148
|
|
68
149
|
def run(period: 60)
|
69
150
|
while true
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
if !mp
|
75
|
-
if t.automount
|
76
|
-
Snapsync.info "partition #{t.partition_uuid} is present, but not mounted, automounting"
|
77
|
-
begin
|
78
|
-
mp = fs.Mount([]).first
|
79
|
-
rescue Exception => e
|
80
|
-
Snapsync.warn "failed to mount, ignoring this target"
|
81
|
-
next
|
82
|
-
end
|
83
|
-
mp = Pathname.new(mp)
|
84
|
-
mounted = true
|
85
|
-
else
|
86
|
-
Snapsync.info "partition #{t.partition_uuid} is present, but not mounted and automount is false. Ignoring"
|
87
|
-
next
|
88
|
-
end
|
89
|
-
else
|
90
|
-
mp = Pathname.new(mp[0..-2].pack("U*"))
|
91
|
-
end
|
92
|
-
|
93
|
-
full_path = mp + t.path
|
94
|
-
Snapsync.info "sync-all on #{mp + t.path} (partition #{t.partition_uuid})"
|
95
|
-
op = SyncAll.new(mp + t.path, config_dir: config_dir)
|
96
|
-
op.run
|
97
|
-
if mounted
|
98
|
-
fs.Unmount([])
|
99
|
-
end
|
100
|
-
end
|
151
|
+
each_available_autosync_target do |path, t|
|
152
|
+
Snapsync.info "sync-all on #{path} (partition #{t.partition_uuid})"
|
153
|
+
op = SyncAll.new(path, config_dir: config_dir)
|
154
|
+
op.run
|
101
155
|
end
|
102
156
|
Snapsync.info "done all declared autosync partitions, sleeping #{period}s"
|
103
157
|
sleep period
|
data/lib/snapsync/cleanup.rb
CHANGED
@@ -10,7 +10,7 @@ module Snapsync
|
|
10
10
|
|
11
11
|
def cleanup(target, dry_run: false)
|
12
12
|
snapshots = target.each_snapshot.to_a
|
13
|
-
filtered_snapshots = policy.
|
13
|
+
filtered_snapshots = policy.filter_snapshots(snapshots).to_set
|
14
14
|
|
15
15
|
if filtered_snapshots.any? { |s| s.synchronization_point? }
|
16
16
|
raise InvalidPolicy, "#{policy} returned a snapsync synchronization point in its results"
|
@@ -23,9 +23,6 @@ module Snapsync
|
|
23
23
|
last_sync_point = snapshots.
|
24
24
|
sort_by(&:num).reverse.
|
25
25
|
find { |s| s.synchronization_point_for?(target) }
|
26
|
-
if !last_sync_point
|
27
|
-
binding.pry
|
28
|
-
end
|
29
26
|
filtered_snapshots << last_sync_point
|
30
27
|
filtered_snapshots = filtered_snapshots.to_set
|
31
28
|
|
@@ -34,6 +31,9 @@ module Snapsync
|
|
34
31
|
target.delete(s, dry_run: dry_run)
|
35
32
|
end
|
36
33
|
end
|
34
|
+
|
35
|
+
Snapsync.info "Waiting for subvolumes to be deleted"
|
36
|
+
IO.popen(["btrfs", "subvolume", "sync", err: '/dev/null']).read
|
37
37
|
end
|
38
38
|
end
|
39
39
|
end
|
data/lib/snapsync/cli.rb
CHANGED
@@ -22,15 +22,48 @@ module Snapsync
|
|
22
22
|
Snapsync.logger.level = 'DEBUG'
|
23
23
|
end
|
24
24
|
end
|
25
|
+
|
26
|
+
# Resolves a path (or nil) into a list of snapsync targets and
|
27
|
+
# yields them
|
28
|
+
#
|
29
|
+
# @param [String,nil] dir the path the user gave, or nil if all
|
30
|
+
# available auto-sync paths should be processed. If the directory is
|
31
|
+
# a target, it is yield as-is. It can also be the root of a sync-all
|
32
|
+
# target (with proper snapsync target as subdirectories whose name
|
33
|
+
# matches the snapper configurations)
|
34
|
+
#
|
35
|
+
# @yieldparam [LocalTarget] target
|
36
|
+
def each_target(dir = nil)
|
37
|
+
return enum_for(__method__) if !block_given?
|
38
|
+
if dir
|
39
|
+
dir = Pathname.new(dir)
|
40
|
+
begin
|
41
|
+
return yield(LocalTarget.new(dir, create_if_needed: false))
|
42
|
+
rescue LocalTarget::InvalidTargetPath
|
43
|
+
end
|
44
|
+
|
45
|
+
SyncAll.new(dir).each_target do |target|
|
46
|
+
yield(target)
|
47
|
+
end
|
48
|
+
else
|
49
|
+
autosync = AutoSync.load_default
|
50
|
+
autosync.each_available_target do |target|
|
51
|
+
yield(target)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
25
55
|
end
|
26
56
|
|
27
57
|
desc 'sync CONFIG DIR', 'synchronizes the snapper configuration CONFIG with the snapsync target DIR'
|
58
|
+
option :autoclean, type: :boolean, default: nil,
|
59
|
+
desc: 'whether the target should be cleaned of obsolete snapshots',
|
60
|
+
long_desc: "The default is to use the value specified in the target's configuration file. This command line option allows to override the default"
|
28
61
|
def sync(config_name, dir)
|
29
62
|
handle_class_options
|
30
63
|
|
31
64
|
config = config_from_name(config_name)
|
32
65
|
target = LocalTarget.new(Pathname.new(dir))
|
33
|
-
|
66
|
+
Sync.new(config, target, autoclean: options[:autoclean]).run
|
34
67
|
end
|
35
68
|
|
36
69
|
desc 'sync-all DIR', 'synchronizes all snapper configurations into corresponding subdirectories of DIR'
|
@@ -120,7 +153,7 @@ policy for more information
|
|
120
153
|
|
121
154
|
autosync = AutoSync.new
|
122
155
|
autosync.load_config(conf_path)
|
123
|
-
exists = autosync.
|
156
|
+
exists = autosync.each_autosync_target.find do |t|
|
124
157
|
t.partition_uuid == uuid && t.path.cleanpath == relative.cleanpath
|
125
158
|
end
|
126
159
|
if exists
|
@@ -163,15 +196,10 @@ for 10 days). snapsync understands the following period names: year month day ho
|
|
163
196
|
EOD
|
164
197
|
def policy(dir, type, *options)
|
165
198
|
handle_class_options
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
dir.mkpath
|
199
|
+
each_target(dir) do |target|
|
200
|
+
target.change_policy(type, options)
|
201
|
+
target.write_config
|
170
202
|
end
|
171
|
-
|
172
|
-
target = LocalTarget.new(dir)
|
173
|
-
target.change_policy(type, options)
|
174
|
-
target.write_config
|
175
203
|
end
|
176
204
|
|
177
205
|
desc 'destroy DIR', 'destroys a snapsync target'
|
@@ -193,10 +221,29 @@ While it can easily be done manually, this command makes sure that the snapshots
|
|
193
221
|
option :config_file, desc: "path to the config file (defaults to /etc/snapsync.conf)",
|
194
222
|
default: '/etc/snapsync.conf'
|
195
223
|
def auto_sync
|
224
|
+
handle_class_options
|
196
225
|
auto = AutoSync.new(SnapperConfig.default_config_dir)
|
197
226
|
auto.load_config(Pathname.new(options[:config_file]))
|
198
227
|
auto.run
|
199
228
|
end
|
229
|
+
|
230
|
+
desc 'list [DIR]', 'list the snapshots present on DIR. If DIR is omitted, tries to access all targets defined as auto-sync targets'
|
231
|
+
def list(dir = nil)
|
232
|
+
handle_class_options
|
233
|
+
each_target(dir) do |target|
|
234
|
+
puts "== #{target.dir}"
|
235
|
+
puts "UUID: #{target.uuid}"
|
236
|
+
puts "Enabled: #{target.enabled?}"
|
237
|
+
puts "Autoclean: #{target.autoclean?}"
|
238
|
+
print "Policy: "
|
239
|
+
pp target.sync_policy
|
240
|
+
|
241
|
+
puts "Snapshots:"
|
242
|
+
target.each_snapshot do |s|
|
243
|
+
puts " #{s.num} #{s.to_time}"
|
244
|
+
end
|
245
|
+
end
|
246
|
+
end
|
200
247
|
end
|
201
248
|
end
|
202
249
|
|
@@ -8,7 +8,7 @@ module Snapsync
|
|
8
8
|
#
|
9
9
|
# Synchronization policy objects are used by the synchronization passes to
|
10
10
|
# decide which snapshots to copy and which to not copy. They have to provide
|
11
|
-
# {#
|
11
|
+
# {#filter_snapshots}.
|
12
12
|
#
|
13
13
|
# This default policy is to copy everything but the snapsync-created
|
14
14
|
# synchronization points that are not involving the current target
|
@@ -27,7 +27,7 @@ module Snapsync
|
|
27
27
|
# @param [#uuid] target the target object
|
28
28
|
# @param [Array<Snapshot>] the snapshot candidates
|
29
29
|
# @return [Array<Snapshot>] the snapshots that should be copied
|
30
|
-
def
|
30
|
+
def filter_snapshots(snapshots)
|
31
31
|
# Filter out any snapsync-generated snapshot
|
32
32
|
snapshots.find_all { |s| !s.synchronization_point? }
|
33
33
|
end
|
data/lib/snapsync/local_sync.rb
CHANGED
@@ -179,17 +179,28 @@ module Snapsync
|
|
179
179
|
sync_snapshot ||= create_synchronization_point
|
180
180
|
|
181
181
|
target_snapshots = target.each_snapshot.sort_by(&:num)
|
182
|
+
nums_on_target = target_snapshots.map(&:num).to_set
|
182
183
|
|
183
184
|
last_common_snapshot = source_snapshots.find do |s|
|
184
|
-
|
185
|
+
nums_on_target.include?(s.num)
|
185
186
|
end
|
186
187
|
if !last_common_snapshot
|
187
188
|
Snapsync.warn "no common snapshot found, will have to synchronize the first snapshot fully"
|
188
189
|
end
|
189
190
|
|
190
|
-
|
191
|
-
|
192
|
-
|
191
|
+
# Merge source and target snapshots to find out which are needed on
|
192
|
+
# the target, and then remove the ones that are already present.
|
193
|
+
all_snapshots = source_snapshots.find_all { |s| !nums_on_target.include?(s.num) } +
|
194
|
+
target_snapshots
|
195
|
+
nums_required = target.sync_policy.filter_snapshots(all_snapshots).
|
196
|
+
map(&:num).to_set
|
197
|
+
source_snapshots.each do |src|
|
198
|
+
if !nums_required.include?(src.num)
|
199
|
+
if nums_on_target.include?(src.num)
|
200
|
+
last_common_snapshot = src
|
201
|
+
end
|
202
|
+
next
|
203
|
+
elsif synchronize_snapshot(target.dir + src.num.to_s, src, parent: last_common_snapshot)
|
193
204
|
last_common_snapshot = src
|
194
205
|
end
|
195
206
|
end
|
@@ -30,7 +30,8 @@ module Snapsync
|
|
30
30
|
# Defaults to true
|
31
31
|
def autoclean?; !!@autoclean end
|
32
32
|
|
33
|
-
class
|
33
|
+
class InvalidTargetPath < RuntimeError; end
|
34
|
+
class InvalidUUIDError < InvalidTargetPath; end
|
34
35
|
class NoUUIDError < InvalidUUIDError; end
|
35
36
|
|
36
37
|
def initialize(dir, create_if_needed: true)
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Snapsync
|
2
|
+
# Single-target synchronization
|
3
|
+
class Sync
|
4
|
+
attr_reader :config
|
5
|
+
|
6
|
+
attr_reader :target
|
7
|
+
|
8
|
+
def initialize(config, target, autoclean: nil)
|
9
|
+
@config = config
|
10
|
+
@target = target
|
11
|
+
@autoclean =
|
12
|
+
if autoclean.nil? then target.autoclean?
|
13
|
+
else autoclean
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# Whether the target should be cleaned after synchronization.
|
18
|
+
#
|
19
|
+
# This is determined either by {#autoclean?} if {.new} was called with
|
20
|
+
# true or false, or by the target's own autoclean flag if {.new} was
|
21
|
+
# called with nil
|
22
|
+
def autoclean?
|
23
|
+
@autoclean
|
24
|
+
end
|
25
|
+
|
26
|
+
# The method that performs synchronization
|
27
|
+
#
|
28
|
+
# One usually wants to call {#run}, which also takes care of running
|
29
|
+
# cleanup if {#autoclean?} is true
|
30
|
+
def sync
|
31
|
+
LocalSync.new(config, target).sync
|
32
|
+
end
|
33
|
+
|
34
|
+
def run
|
35
|
+
sync
|
36
|
+
|
37
|
+
if autoclean?
|
38
|
+
if target.cleanup
|
39
|
+
Snapsync.info "running cleanup for #{target.dir}"
|
40
|
+
target.cleanup.cleanup(target)
|
41
|
+
else
|
42
|
+
Snapsync.info "#{target.sync_policy.class.name} policy set, no cleanup to do for #{target.dir}"
|
43
|
+
end
|
44
|
+
else
|
45
|
+
Snapsync.info "autoclean not set on #{target.dir}"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
data/lib/snapsync/sync_all.rb
CHANGED
@@ -23,43 +23,35 @@ module Snapsync
|
|
23
23
|
@autoclean = autoclean
|
24
24
|
end
|
25
25
|
|
26
|
-
# Whether the
|
27
|
-
#
|
28
|
-
#
|
29
|
-
#
|
30
|
-
#
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
else
|
35
|
-
@autoclean
|
36
|
-
end
|
26
|
+
# Whether the target should be forced to autoclean(true), force to not
|
27
|
+
# run cleanup (false) or use their own config file to decide (nil)
|
28
|
+
#
|
29
|
+
# The default is nil
|
30
|
+
#
|
31
|
+
# @return [Boolean,nil]
|
32
|
+
def autoclean?
|
33
|
+
@autoclean
|
37
34
|
end
|
38
35
|
|
39
|
-
|
36
|
+
# Enumerate the targets available under {#target_dir}
|
37
|
+
def each_target
|
40
38
|
SnapperConfig.each_in_dir(config_dir) do |config|
|
41
39
|
dir = target_dir + config.name
|
42
40
|
if !dir.exist?
|
43
|
-
Snapsync.warn "
|
41
|
+
Snapsync.warn "no directory for configuration #{config.name} in #{target_dir}"
|
44
42
|
else
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
end
|
43
|
+
yield(LocalTarget.new(dir))
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
50
47
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
else
|
57
|
-
Snapsync.info "#{target.sync_policy.class.name} policy set, no cleanup to do for #{config.name}"
|
58
|
-
end
|
59
|
-
else
|
60
|
-
Snapsync.info "autoclean not set on #{config.name}"
|
61
|
-
end
|
48
|
+
def run
|
49
|
+
each_target do |target|
|
50
|
+
if !target.enabled?
|
51
|
+
Snapsync.warn "not synchronizing to #{target.dir}, it is disabled"
|
52
|
+
next
|
62
53
|
end
|
54
|
+
Sync.new(config, target, autoclean: autoclean?).run
|
63
55
|
end
|
64
56
|
end
|
65
57
|
end
|
@@ -14,8 +14,8 @@ module Snapsync
|
|
14
14
|
pp.text "will keep only the latest snapshot"
|
15
15
|
end
|
16
16
|
|
17
|
-
# (see DefaultSyncPolicy#
|
18
|
-
def
|
17
|
+
# (see DefaultSyncPolicy#filter_snapshots)
|
18
|
+
def filter_snapshots(snapshots)
|
19
19
|
last = snapshots.sort_by(&:num).reverse.
|
20
20
|
find { |s| !s.synchronization_point? }
|
21
21
|
[last]
|
@@ -91,6 +91,8 @@ module Snapsync
|
|
91
91
|
def compute_required_snapshots(target_snapshots)
|
92
92
|
keep_flags = Hash.new { |h,k| h[k] = [false, []] }
|
93
93
|
|
94
|
+
target_snapshots = target_snapshots.sort_by(&:num)
|
95
|
+
|
94
96
|
# Mark all important snapshots as kept
|
95
97
|
target_snapshots.each do |s|
|
96
98
|
if s.user_data['important'] == 'yes'
|
@@ -122,7 +124,7 @@ module Snapsync
|
|
122
124
|
|
123
125
|
# Finally, guard against race conditions. Always keep all snapshots
|
124
126
|
# between the last-to-keep and the last
|
125
|
-
target_snapshots.
|
127
|
+
target_snapshots.reverse.each do |s|
|
126
128
|
break if keep_flags[s.num][0]
|
127
129
|
keep_flags[s.num][0] = true
|
128
130
|
keep_flags[s.num][1] << "last snapshot"
|
@@ -130,9 +132,10 @@ module Snapsync
|
|
130
132
|
keep_flags
|
131
133
|
end
|
132
134
|
|
133
|
-
def
|
135
|
+
def filter_snapshots(snapshots)
|
134
136
|
Snapsync.debug do
|
135
137
|
Snapsync.debug "Filtering snapshots according to timeline"
|
138
|
+
Snapsync.debug "Snapshots: #{snapshots.map(&:num).sort.join(", ")}"
|
136
139
|
timeline.each do |t|
|
137
140
|
Snapsync.debug " #{t}"
|
138
141
|
end
|
@@ -140,10 +143,10 @@ module Snapsync
|
|
140
143
|
end
|
141
144
|
|
142
145
|
default_policy = DefaultSyncPolicy.new
|
143
|
-
|
146
|
+
snapshots = default_policy.filter_snapshots(snapshots)
|
144
147
|
|
145
|
-
keep_flags = compute_required_snapshots(
|
146
|
-
|
148
|
+
keep_flags = compute_required_snapshots(snapshots)
|
149
|
+
snapshots.sort_by(&:num).find_all do |s|
|
147
150
|
keep, reason = keep_flags.fetch(s.num, nil)
|
148
151
|
if keep
|
149
152
|
Snapsync.debug "Timeline: selected snapshot #{s.num} #{s.date.to_time}"
|
data/lib/snapsync/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: snapsync
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sylvain Joyeux
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-08-
|
11
|
+
date: 2015-08-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: logging
|
@@ -186,6 +186,7 @@ files:
|
|
186
186
|
- lib/snapsync/partitions_monitor.rb
|
187
187
|
- lib/snapsync/snapper_config.rb
|
188
188
|
- lib/snapsync/snapshot.rb
|
189
|
+
- lib/snapsync/sync.rb
|
189
190
|
- lib/snapsync/sync_all.rb
|
190
191
|
- lib/snapsync/sync_last_policy.rb
|
191
192
|
- lib/snapsync/test.rb
|