snapsync 0.3.8 → 0.4.0

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.
data/lib/snapsync/sync.rb CHANGED
@@ -3,6 +3,7 @@ module Snapsync
3
3
  class Sync
4
4
  attr_reader :config
5
5
 
6
+ # @return [SyncTarget]
6
7
  attr_reader :target
7
8
 
8
9
  def initialize(config, target, autoclean: nil)
@@ -28,19 +29,21 @@ module Snapsync
28
29
  # One usually wants to call {#run}, which also takes care of running
29
30
  # cleanup if {#autoclean?} is true
30
31
  def sync
31
- LocalSync.new(config, target).sync
32
+ SnapshotTransfer.new(config, target).sync
32
33
  end
33
34
 
34
35
  def remove_partially_synchronized_snapshots
36
+ btrfs_target = Btrfs.get(@target.dir)
37
+
35
38
  target.each_snapshot_raw do |path, snapshot, error|
36
39
  next if !error && !snapshot.partial?
37
40
 
38
41
  Snapsync.info "Removing partial snapshot at #{path}"
39
42
  begin
40
43
  if (path + "snapshot").exist?
41
- Btrfs.run("subvolume", "delete", (path + "snapshot").to_s)
44
+ btrfs_target.run("subvolume", "delete", (path + "snapshot").path_part)
42
45
  elsif (path + "snapshot.partial").exist?
43
- Btrfs.run("subvolume", "delete", (path + "snapshot.partial").to_s)
46
+ btrfs_target.run("subvolume", "delete", (path + "snapshot.partial").path_part)
44
47
  end
45
48
  rescue Btrfs::Error => e
46
49
  Snapsync.warn "failed to remove snapshot at #{path}, keeping the rest of the snapshot"
@@ -51,8 +54,9 @@ module Snapsync
51
54
  path.rmtree
52
55
  Snapsync.info "Flushing data to disk"
53
56
  begin
54
- Btrfs.run("subvolume", "sync", path.to_s)
57
+ btrfs_target.run("subvolume", "sync", path.path_part)
55
58
  rescue Btrfs::Error
59
+ # Ignored
56
60
  end
57
61
  end
58
62
  end
@@ -40,7 +40,7 @@ module Snapsync
40
40
  if !dir.exist?
41
41
  Snapsync.warn "no directory for configuration #{config.name} in #{target_dir}"
42
42
  else
43
- yield(config, LocalTarget.new(dir))
43
+ yield(config, SyncTarget.new(dir))
44
44
  end
45
45
  end
46
46
  end
@@ -1,5 +1,5 @@
1
1
  module Snapsync
2
- class LocalTarget
2
+ class SyncTarget
3
3
  # The target's UUID
4
4
  #
5
5
  # @return [String]
@@ -9,9 +9,11 @@ module Snapsync
9
9
  attr_reader :dir
10
10
 
11
11
  # The target sync policy
12
+ # @return [DefaultSyncPolicy]
12
13
  attr_reader :sync_policy
13
14
 
14
15
  # The cleanup object
16
+ # @return [Cleanup]
15
17
  attr_reader :cleanup
16
18
 
17
19
  # Whether this target is enabled or not
@@ -38,6 +40,7 @@ module Snapsync
38
40
  "local:#{dir}"
39
41
  end
40
42
 
43
+ # @param [AgnosticPath] dir
41
44
  def initialize(dir, create_if_needed: true)
42
45
  if !dir.directory?
43
46
  raise ArgumentError, "#{dir} does not exist"
@@ -55,18 +58,21 @@ module Snapsync
55
58
  @cleanup = nil
56
59
  @enabled = true
57
60
  @autoclean = true
61
+ write_config
58
62
  end
59
- write_config
60
63
  end
61
64
 
62
65
  def each_snapshot_raw(&block)
63
66
  Snapshot.each_snapshot_raw(dir, &block)
64
67
  end
68
+
69
+ # @yieldparam snapshot [Snapshot]
65
70
  def each_snapshot(&block)
66
71
  Snapshot.each(dir, &block)
67
72
  end
68
73
 
69
74
  def write_config
75
+ Snapsync.debug "SyncTarget #{dir} write_config"
70
76
  config = Hash['uuid' => uuid, 'policy' => Hash.new]
71
77
  config['policy']['type'] =
72
78
  case sync_policy
@@ -85,6 +91,7 @@ module Snapsync
85
91
  end
86
92
 
87
93
  def read_config
94
+ Snapsync.debug "SyncTarget #{dir} read_config"
88
95
  begin
89
96
  if !(raw_config = YAML.load(config_path.read))
90
97
  raise NoUUIDError, "empty configuration file found in #{config_path}"
@@ -167,12 +174,15 @@ module Snapsync
167
174
  self.class.parse_policy(type, options)
168
175
  end
169
176
 
177
+ # @param [Snapshot] s
170
178
  def delete(s, dry_run: false)
179
+ btrfs = Btrfs.get(s.subvolume_dir)
180
+
171
181
  Snapsync.info "Removing snapshot #{s.num} #{s.date.to_time} at #{s.subvolume_dir}"
172
182
  return if dry_run
173
183
 
174
184
  begin
175
- Btrfs.run("subvolume", "delete", '--commit-each', s.subvolume_dir.to_s)
185
+ btrfs.run("subvolume", "delete", s.subvolume_dir.path_part)
176
186
  rescue Btrfs::Error
177
187
  Snapsync.warn "failed to remove snapshot at #{s.subvolume_dir}, keeping the rest of the snapshot"
178
188
  return
@@ -180,7 +190,7 @@ module Snapsync
180
190
 
181
191
  Snapsync.info "Flushing data to disk"
182
192
  begin
183
- Btrfs.run("subvolume", "sync", self.dir.to_s)
193
+ btrfs.run("subvolume", "sync", self.dir.to_s)
184
194
  rescue Btrfs::Error
185
195
  end
186
196
 
data/lib/snapsync/test.rb CHANGED
@@ -28,18 +28,11 @@ end
28
28
 
29
29
  module Snapsync
30
30
  # This module is the common setup for all tests
31
- #
32
- # It should be included in the toplevel describe blocks
33
- #
34
- # @example
35
- # require 'snapsync/test'
36
- # describe Snapsync do
37
- # include Snapsync::SelfTest
38
- # end
39
- #
40
31
  module SelfTest
41
32
  def setup
42
33
  @tempdirs = Array.new
34
+ Snapsync._mountpointCache = {}
35
+ Snapsync::Btrfs._mountpointCache = {}
43
36
  super
44
37
  # Setup code for all the tests
45
38
  end
@@ -0,0 +1,18 @@
1
+ module Kernel
2
+ def human_readable_time(time)
3
+ hrs = time / 3600
4
+ min = (time / 60) % 60
5
+ sec = time % 60
6
+ "%02i:%02i:%02i" % [hrs, min, sec]
7
+ end
8
+
9
+ def human_readable_size(size, digits: 1)
10
+ order = ['B', 'kB', 'MB', 'GB']
11
+ magnitude =
12
+ if size > 0
13
+ Integer(Math.log2(size) / 10)
14
+ else 0
15
+ end
16
+ "%.#{digits}f#{order[magnitude]}" % [Float(size) / (1024 ** magnitude)]
17
+ end
18
+ end
@@ -1,3 +1,3 @@
1
1
  module Snapsync
2
- VERSION = "0.3.8"
2
+ VERSION = "0.4.0"
3
3
  end
data/lib/snapsync.rb CHANGED
@@ -1,3 +1,7 @@
1
+ require 'uri/ssh_git'
2
+ require 'net/ssh'
3
+ require 'net/sftp'
4
+
1
5
  require 'pathname'
2
6
  require 'logging'
3
7
  require 'pp'
@@ -8,14 +12,19 @@ require 'date'
8
12
  require 'concurrent'
9
13
 
10
14
  require "snapsync/version"
15
+ require "snapsync/util"
11
16
  require "snapsync/exceptions"
12
17
  require 'snapsync/btrfs'
18
+ require 'snapsync/btrfs_subvolume'
13
19
  require "snapsync/snapper_config"
14
20
  require "snapsync/snapshot"
15
- require "snapsync/local_target"
16
- require "snapsync/local_sync"
21
+ require "snapsync/sync_target"
22
+ require "snapsync/snapshot_transfer"
17
23
  require 'snapsync/cleanup'
18
24
 
25
+ require 'snapsync/remote_pathname'
26
+ require 'snapsync/ssh_popen'
27
+
19
28
  require 'snapsync/default_sync_policy'
20
29
  require 'snapsync/timeline_sync_policy'
21
30
  require 'snapsync/sync_last_policy'
@@ -91,5 +100,25 @@ end
91
100
 
92
101
  module Snapsync
93
102
  install_root_logging(forward: true)
103
+
104
+ class << self
105
+ attr_accessor :SSH_DEBUG
106
+ end
107
+ Snapsync.SSH_DEBUG = false
108
+
109
+ # @param [String] dir
110
+ # @return [AgnosticPath]
111
+ def self.path(dir)
112
+ raise "Nil dir" if dir.nil?
113
+ if dir.instance_of? RemotePathname or dir.include? ':'
114
+ begin
115
+ RemotePathname.new(dir)
116
+ rescue URI::InvalidComponentError
117
+ LocalPathname.new(dir)
118
+ end
119
+ else
120
+ LocalPathname.new dir
121
+ end
122
+ end
94
123
  end
95
124
 
data/snapsync.gemspec CHANGED
@@ -14,7 +14,7 @@ Gem::Specification.new do |spec|
14
14
  spec.license = "MIT"
15
15
  spec.description =<<-EOD
16
16
  Snapsync is a tool that automates transferring snapper snapshots to
17
- external media (USB drives ...) and managing these snapshots (e.g.
17
+ external media (USB drives ...), remote filesystems [experimental] and managing these snapshots (e.g.
18
18
  timeline cleanup)
19
19
  EOD
20
20
 
@@ -23,14 +23,21 @@ EOD
23
23
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
24
24
  spec.require_paths = ["lib"]
25
25
 
26
+ spec.add_dependency 'rexml', '~> 3.2.0'
26
27
  spec.add_dependency 'logging', '~> 2.0', ">= 2.0.0"
27
- spec.add_dependency 'concurrent-ruby', '~> 0.9.0', '>= 0.9'
28
- spec.add_dependency 'ruby-dbus', "~> 0.11.0", ">= 0.11"
29
- spec.add_dependency 'thor', "~> 0.19.0", ">= 0.19.1"
28
+ spec.add_dependency 'concurrent-ruby', '~> 1.1'
29
+ spec.add_dependency 'ruby-dbus', "~> 0.16.0"
30
+ spec.add_dependency 'thor', "~> 1.1"
31
+ spec.add_dependency 'uri-ssh_git', "~> 2.0.0"
32
+ spec.add_dependency 'net-ssh', ">= 6.3.1"
33
+ spec.add_dependency 'net-sftp', "~> 3.0.0"
34
+ spec.add_dependency 'ed25519', ">= 1.2"
35
+ spec.add_dependency 'bcrypt_pbkdf', ">= 1.0"
30
36
 
31
- spec.add_development_dependency "bundler", "~> 1.10"
32
- spec.add_development_dependency "rake", "~> 10.0"
37
+ spec.add_development_dependency "bundler", "~> 2"
38
+ spec.add_development_dependency "rake", "~> 13"
33
39
  spec.add_development_dependency "minitest", "~> 5.0", ">= 5.7"
34
40
  spec.add_development_dependency "flexmock", "~> 2.0", ">= 2.0"
35
41
  spec.add_development_dependency "fakefs"
42
+ spec.add_development_dependency "irb"
36
43
  end
data/snapsync.service CHANGED
@@ -4,7 +4,10 @@ Wants=udisks2.service
4
4
 
5
5
  [Service]
6
6
  Type=simple
7
- ExecStart=/opt/snapsync/bin/snapsync auto-sync
7
+ ExecStart=/usr/bin/snapsync auto-sync --one-shot
8
+ Nice=19
9
+ IOSchedulingClass=idle
10
+ KillSignal=SIGINT
8
11
 
9
12
  [Install]
10
13
  WantedBy=default.target
data/snapsync.timer ADDED
@@ -0,0 +1,10 @@
1
+ [Unit]
2
+ Description=Run snapsync
3
+
4
+ [Timer]
5
+ OnCalendar=*-*-* 20:00:00
6
+ RandomizedDelaySec=5min
7
+ Persistent=true
8
+
9
+ [Install]
10
+ WantedBy=timers.target
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: snapsync
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.8
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sylvain Joyeux
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-02-14 00:00:00.000000000 Z
11
+ date: 2022-04-21 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rexml
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 3.2.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 3.2.0
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: logging
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -36,88 +50,140 @@ dependencies:
36
50
  requirements:
37
51
  - - "~>"
38
52
  - !ruby/object:Gem::Version
39
- version: 0.9.0
40
- - - ">="
41
- - !ruby/object:Gem::Version
42
- version: '0.9'
53
+ version: '1.1'
43
54
  type: :runtime
44
55
  prerelease: false
45
56
  version_requirements: !ruby/object:Gem::Requirement
46
57
  requirements:
47
58
  - - "~>"
48
59
  - !ruby/object:Gem::Version
49
- version: 0.9.0
50
- - - ">="
51
- - !ruby/object:Gem::Version
52
- version: '0.9'
60
+ version: '1.1'
53
61
  - !ruby/object:Gem::Dependency
54
62
  name: ruby-dbus
55
63
  requirement: !ruby/object:Gem::Requirement
56
64
  requirements:
57
65
  - - "~>"
58
66
  - !ruby/object:Gem::Version
59
- version: 0.11.0
60
- - - ">="
67
+ version: 0.16.0
68
+ type: :runtime
69
+ prerelease: false
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
61
73
  - !ruby/object:Gem::Version
62
- version: '0.11'
74
+ version: 0.16.0
75
+ - !ruby/object:Gem::Dependency
76
+ name: thor
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: '1.1'
63
82
  type: :runtime
64
83
  prerelease: false
65
84
  version_requirements: !ruby/object:Gem::Requirement
66
85
  requirements:
67
86
  - - "~>"
68
87
  - !ruby/object:Gem::Version
69
- version: 0.11.0
88
+ version: '1.1'
89
+ - !ruby/object:Gem::Dependency
90
+ name: uri-ssh_git
91
+ requirement: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - "~>"
94
+ - !ruby/object:Gem::Version
95
+ version: 2.0.0
96
+ type: :runtime
97
+ prerelease: false
98
+ version_requirements: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - "~>"
101
+ - !ruby/object:Gem::Version
102
+ version: 2.0.0
103
+ - !ruby/object:Gem::Dependency
104
+ name: net-ssh
105
+ requirement: !ruby/object:Gem::Requirement
106
+ requirements:
70
107
  - - ">="
71
108
  - !ruby/object:Gem::Version
72
- version: '0.11'
109
+ version: 6.3.1
110
+ type: :runtime
111
+ prerelease: false
112
+ version_requirements: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - ">="
115
+ - !ruby/object:Gem::Version
116
+ version: 6.3.1
73
117
  - !ruby/object:Gem::Dependency
74
- name: thor
118
+ name: net-sftp
75
119
  requirement: !ruby/object:Gem::Requirement
76
120
  requirements:
77
121
  - - "~>"
78
122
  - !ruby/object:Gem::Version
79
- version: 0.19.0
123
+ version: 3.0.0
124
+ type: :runtime
125
+ prerelease: false
126
+ version_requirements: !ruby/object:Gem::Requirement
127
+ requirements:
128
+ - - "~>"
129
+ - !ruby/object:Gem::Version
130
+ version: 3.0.0
131
+ - !ruby/object:Gem::Dependency
132
+ name: ed25519
133
+ requirement: !ruby/object:Gem::Requirement
134
+ requirements:
80
135
  - - ">="
81
136
  - !ruby/object:Gem::Version
82
- version: 0.19.1
137
+ version: '1.2'
83
138
  type: :runtime
84
139
  prerelease: false
85
140
  version_requirements: !ruby/object:Gem::Requirement
86
141
  requirements:
87
- - - "~>"
142
+ - - ">="
88
143
  - !ruby/object:Gem::Version
89
- version: 0.19.0
144
+ version: '1.2'
145
+ - !ruby/object:Gem::Dependency
146
+ name: bcrypt_pbkdf
147
+ requirement: !ruby/object:Gem::Requirement
148
+ requirements:
149
+ - - ">="
150
+ - !ruby/object:Gem::Version
151
+ version: '1.0'
152
+ type: :runtime
153
+ prerelease: false
154
+ version_requirements: !ruby/object:Gem::Requirement
155
+ requirements:
90
156
  - - ">="
91
157
  - !ruby/object:Gem::Version
92
- version: 0.19.1
158
+ version: '1.0'
93
159
  - !ruby/object:Gem::Dependency
94
160
  name: bundler
95
161
  requirement: !ruby/object:Gem::Requirement
96
162
  requirements:
97
163
  - - "~>"
98
164
  - !ruby/object:Gem::Version
99
- version: '1.10'
165
+ version: '2'
100
166
  type: :development
101
167
  prerelease: false
102
168
  version_requirements: !ruby/object:Gem::Requirement
103
169
  requirements:
104
170
  - - "~>"
105
171
  - !ruby/object:Gem::Version
106
- version: '1.10'
172
+ version: '2'
107
173
  - !ruby/object:Gem::Dependency
108
174
  name: rake
109
175
  requirement: !ruby/object:Gem::Requirement
110
176
  requirements:
111
177
  - - "~>"
112
178
  - !ruby/object:Gem::Version
113
- version: '10.0'
179
+ version: '13'
114
180
  type: :development
115
181
  prerelease: false
116
182
  version_requirements: !ruby/object:Gem::Requirement
117
183
  requirements:
118
184
  - - "~>"
119
185
  - !ruby/object:Gem::Version
120
- version: '10.0'
186
+ version: '13'
121
187
  - !ruby/object:Gem::Dependency
122
188
  name: minitest
123
189
  requirement: !ruby/object:Gem::Requirement
@@ -172,9 +238,23 @@ dependencies:
172
238
  - - ">="
173
239
  - !ruby/object:Gem::Version
174
240
  version: '0'
241
+ - !ruby/object:Gem::Dependency
242
+ name: irb
243
+ requirement: !ruby/object:Gem::Requirement
244
+ requirements:
245
+ - - ">="
246
+ - !ruby/object:Gem::Version
247
+ version: '0'
248
+ type: :development
249
+ prerelease: false
250
+ version_requirements: !ruby/object:Gem::Requirement
251
+ requirements:
252
+ - - ">="
253
+ - !ruby/object:Gem::Version
254
+ version: '0'
175
255
  description: |
176
256
  Snapsync is a tool that automates transferring snapper snapshots to
177
- external media (USB drives ...) and managing these snapshots (e.g.
257
+ external media (USB drives ...), remote filesystems [experimental] and managing these snapshots (e.g.
178
258
  timeline cleanup)
179
259
  email:
180
260
  - sylvain.joyeux@m4x.org
@@ -195,28 +275,33 @@ files:
195
275
  - lib/snapsync.rb
196
276
  - lib/snapsync/auto_sync.rb
197
277
  - lib/snapsync/btrfs.rb
278
+ - lib/snapsync/btrfs_subvolume.rb
198
279
  - lib/snapsync/cleanup.rb
199
280
  - lib/snapsync/cli.rb
200
281
  - lib/snapsync/default_sync_policy.rb
201
282
  - lib/snapsync/exceptions.rb
202
- - lib/snapsync/local_sync.rb
203
- - lib/snapsync/local_target.rb
204
283
  - lib/snapsync/partitions_monitor.rb
284
+ - lib/snapsync/remote_pathname.rb
205
285
  - lib/snapsync/snapper_config.rb
206
286
  - lib/snapsync/snapshot.rb
287
+ - lib/snapsync/snapshot_transfer.rb
288
+ - lib/snapsync/ssh_popen.rb
207
289
  - lib/snapsync/sync.rb
208
290
  - lib/snapsync/sync_all.rb
209
291
  - lib/snapsync/sync_last_policy.rb
292
+ - lib/snapsync/sync_target.rb
210
293
  - lib/snapsync/test.rb
211
294
  - lib/snapsync/timeline_sync_policy.rb
295
+ - lib/snapsync/util.rb
212
296
  - lib/snapsync/version.rb
213
297
  - snapsync.gemspec
214
298
  - snapsync.service
299
+ - snapsync.timer
215
300
  homepage: https://github.com/doudou/snapsync
216
301
  licenses:
217
302
  - MIT
218
303
  metadata: {}
219
- post_install_message:
304
+ post_install_message:
220
305
  rdoc_options: []
221
306
  require_paths:
222
307
  - lib
@@ -231,9 +316,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
231
316
  - !ruby/object:Gem::Version
232
317
  version: '0'
233
318
  requirements: []
234
- rubyforge_project:
235
- rubygems_version: 2.5.1
236
- signing_key:
319
+ rubygems_version: 3.3.8
320
+ signing_key:
237
321
  specification_version: 4
238
322
  summary: tool to automate backing up snapper snapshots to other medias
239
323
  test_files: []