rbarman 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -1,10 +1,10 @@
1
1
  # rbarman
2
2
 
3
- rbarman - Ruby Wrapper for 2ndQuadrant's PostgreSQL backup tool [pgbarman](http://pgbarman.org)
3
+ rbarman - Ruby Wrapper for 2ndQuadrant's PostgreSQL backup tool [barman](http://pgbarman.org)
4
4
 
5
5
  ## Installation
6
6
 
7
- pgbarman has to be installed and configured on the same host where this gem is to be used, otherwise it cannot get any useful information about your backups ;)
7
+ barman has to be installed and configured on the same host where this gem is to be used, otherwise it cannot get any useful information about your backups ;)
8
8
 
9
9
 
10
10
  Add this line to your application's Gemfile:
@@ -21,20 +21,32 @@ Or install it yourself as:
21
21
 
22
22
  ## Usage
23
23
 
24
+ Just a few examples..
25
+
24
26
  ### Get all your backups!
25
27
 
26
- This will call pgbarman and some other sources (backup.info, xlog.db) to get information about your backups. This could take several minutes (and memory) if you have many backups with thousand of wal files. If you don't want to scan for wal file information, use RBarman::Backups.all('server', false)
28
+ This will call various barman commands and some other sources (backup.info, xlog.db) to get information about your backups and could take several minutes (and memory) if you have many backups with thousand of wal files.
27
29
 
28
30
  <pre>
29
- backups = RBarman::Backups.all('server', true)
30
- backups.count
31
+ servers = RBarman::Servers.all({:with_backups => true, :with_wal_files => true })
32
+ servers.count
31
33
  => 3
32
34
 
33
- backups.each { |b| p "id: #{b.id} }
35
+ servers[0].name
36
+ => "pgmaster"
37
+
38
+ servers[0].ssh_cmd
39
+ => "ssh postgres@10.118.19.4"
40
+
41
+ servers[0].backups.count
42
+ => 2
43
+
44
+ servers[0].backups.each { |b| p "id: #{b.id} }
34
45
  => "id: 20130304T080002"
35
46
  => "id: 20130225T192654"
36
47
  => "id: 20130218T080002"
37
48
 
49
+ backups = servers[0].backups
38
50
  backups.latest.id
39
51
  => "20130304T080002"
40
52
 
@@ -75,7 +87,7 @@ backups[0].wal_files[1022].compression
75
87
  ### Get just one backup without wal files
76
88
 
77
89
  <pre>
78
- backup = RBarman::Backup.by_id('server', '20130225T192654', false)
90
+ backup = RBarman::Backup.by_id('pg_master', '20130225T192654')
79
91
  p "id: #{backup.id}|size: #{backup.size / (1024 ** 3) } GB|wal size: #{backup.wal_file_size / (1024 ** 3)} GB"
80
92
  => "id: 20130225T192654|size: 217GB|wal size: 72 GB"
81
93
  </pre>
@@ -95,7 +107,7 @@ p b.id
95
107
  This tells pgbarman to delete the specified backup
96
108
 
97
109
  <pre>
98
- backup = RBarman::Backup.by_id('server', '20130225T192654', false)
110
+ backup = RBarman::Backup.by_id('server', '20130225T192654', { :with_wal_files => false })
99
111
  p backup.deleted
100
112
  => false
101
113
  backup.delete
@@ -1,29 +1,120 @@
1
1
  require 'time'
2
2
 
3
+ # @author Holger Amann <holger@sauspiel.de>
3
4
  module RBarman
4
5
 
5
6
  class InvalidBackupIdError < RuntimeError
6
7
  end
7
8
 
9
+
10
+ # Represents a barman Backup
8
11
  class Backup
12
+
13
+ # @return [String, nil] name of the server to which the backup belongs.
9
14
  attr_accessor :server
10
- attr_reader :id, :backup_start, :backup_end, :status, :wal_files, :size, :wal_file_size, :begin_wal, :end_wal, :timeline, :pgdata, :deleted
15
+
16
+ # @overload id
17
+ # @return [String, nil] id (like '20130304T080002') which identifies
18
+ # the backup and is unique among all backups of a server.
19
+ # @overload id=
20
+ # Id of the backup
21
+ # @param [#to_s] id id of the backup
22
+ # @raise [InvalidBackupIdError] if the id is not valid
23
+ # @see backup_id_valid?
24
+ attr_reader :id
25
+
26
+ # @overload backup_start
27
+ # @return [Time, nil] time when the backup started.
28
+ # @overload backup_start=
29
+ # Start of the backup
30
+ # @param [#to_s] start time when the backup started
31
+ attr_reader :backup_start
32
+
33
+ # @overload backup_end
34
+ # @return [Time, nil] time when the backup stopped.
35
+ # @overload backup_end=
36
+ # End of the backup
37
+ # @param [#to_s] b_end time when the backup stopped
38
+ attr_reader :backup_end
39
+
40
+ # @overload status
41
+ # @return [Symbol, nil] status of the backup, `:empty`, `:started`, `:done` or `:failed`
42
+ # @overload status=
43
+ # Status of the backup
44
+ # @param [Symbol] status status of the backup
45
+ # @raise [ArgumentError] if status is not one of `:empty`, `:started`, `:done` or `:failed`
46
+ attr_reader :status
47
+
48
+ # @overload wal_files
49
+ # @return [WalFiles, nil] All wal files
50
+ # @overload wal_files=
51
+ # All wal files
52
+ # @param [Array, WalFiles] wal_files all wal files
53
+ # @raise [ArgumentError] if argument is not an Array
54
+ attr_reader :wal_files
55
+
56
+ # @overload size
57
+ # @return [Integer, nil] size of data (in bytes)
58
+ # @overload size=
59
+ # Size of data (in bytes)
60
+ # @param [#to_i] size size (in bytes
61
+ attr_reader :size
62
+
63
+ # @overload wal_file_size
64
+ # @return [Integer, nil] size of wal files (in bytes)
65
+ # @overload wal_file_size=
66
+ # Size of wal files (in bytes)
67
+ # @param [#to_i] size size of wal files (in bytes)
68
+ attr_reader :wal_file_size
69
+
70
+ # @overload begin_wal
71
+ # @return [WalFile, nil] first wal file after backup started
72
+ # @overload begin_wal=
73
+ # First wal file after backup started
74
+ # @param [String,WalFile] wal_file the wal file
75
+ attr_reader :begin_wal
76
+
77
+ # @overload end_wal
78
+ # @return [WalFile, nil] last wal file after backup stopped
79
+ # @overload end_wal=
80
+ # Last wal file after backup stopped
81
+ # @param [String,WalFile] wal_file the wal file
82
+ attr_reader :end_wal
83
+
84
+ # @overload timeline
85
+ # @return [Integer, nil] timeline of the backup.
86
+ # @overload timeline=
87
+ # Timeline of the backup
88
+ # @param [Integer] i timeline of the backup
89
+ # @raise [ArgumentError] if timeline == 0
90
+ attr_reader :timeline
91
+
92
+ # @overload pgdata
93
+ # @return [String, nil] server's data directory
94
+ # @overload pgdata=
95
+ # Server's data directory
96
+ # @param [String] path path to directory
97
+ # @raise [ArgumentError] if path is empty
98
+ attr_reader :pgdata
99
+
100
+ # @return [Boolean] if the backup has been deleted
101
+ attr_reader :deleted
11
102
 
12
103
  def initialize
13
104
  @deleted = false
14
105
  end
15
106
 
16
107
  def id=(id)
17
- raise InvalidBackupIdError if !Backup.backup_id_valid?(id)
18
- @id = id
108
+ raise InvalidBackupIdError if !Backup.backup_id_valid?(id.to_s)
109
+ @id = id.to_s
19
110
  end
20
111
 
21
112
  def backup_start=(start)
22
- @backup_start = Time.parse(start)
113
+ @backup_start = Time.parse(start.to_s)
23
114
  end
24
115
 
25
116
  def backup_end=(b_end)
26
- @backup_end = Time.parse(b_end)
117
+ @backup_end = Time.parse(b_end.to_s)
27
118
  end
28
119
 
29
120
  def status=(status)
@@ -54,7 +145,6 @@ module RBarman
54
145
  @end_wal = WalFile.parse(wal_file)
55
146
  end
56
147
 
57
-
58
148
  def wal_file_size=(size)
59
149
  @wal_file_size = size.to_i
60
150
  end
@@ -69,38 +159,58 @@ module RBarman
69
159
  @pgdata = path
70
160
  end
71
161
 
162
+ # Adds a wal file to the backup
163
+ # @param [String, WalFile] wal_file the wal file
164
+ # @return [void]
72
165
  def add_wal_file(wal_file)
73
- @wal_files = Array.new if @wal_files.nil?
166
+ @wal_files = WalFiles.new if @wal_files.nil?
74
167
  @wal_files << WalFile.parse(wal_file)
75
168
  end
76
169
 
170
+ # @return [Boolean] if the wal file is already added to the backup
171
+ # @param [String, WalFile] wal_file the wal file
77
172
  def wal_file_already_added?(wal_file)
78
173
  return false if @wal_files.nil?
79
174
  return @wal_files.include?(WalFile.parse(wal_file))
80
175
  end
81
176
 
82
177
 
178
+ # @return [Boolean] if id is a valid backup id
179
+ # @param [#to_s] id the backup id
180
+ # @example Check if a backup id is valid
181
+ # Backup.backup_id_valid?("20130304T080002") #=> true
182
+ # Backup.backup_id_valid?("213") #=> false
83
183
  def self.backup_id_valid?(id)
84
184
  return false if id.nil?
85
- return !id.match(/\d{8,8}T\d{6,6}/).nil?
185
+ return !id.to_s.match(/\d{8,8}T\d{6,6}/).nil?
86
186
  end
87
187
 
188
+ # Instructs the underlying (barman) command to delete the backup and sets its flag {#deleted} to true
88
189
  def delete
89
190
  cmd = CliCommand.new
90
191
  cmd.delete(@server, @id)
91
192
  @deleted = true
92
193
  end
93
194
 
195
+ # Instructs the underlying (barman) command to create a new backup.
196
+ # @param [String] server server name for which a backup should be created
197
+ # @return [Backup] a new backup object with wal files
94
198
  def self.create(server)
95
199
  cmd = CliCommand.new
96
200
  cmd.create(server)
97
- backups = Backups.all(server, false)
98
- return Backup.by_id(server, backups.latest.id, true)
201
+ backups = Backups.all(server, { :with_wal_files => false })
202
+ return Backup.by_id(server, backups.latest.id, { :with_wal_files => true })
99
203
  end
100
204
 
101
- def self.by_id(server, backup_id, with_wal_files=true)
205
+ # Get a specific backup
206
+ # @param [String] server server name
207
+ # @param [String] backup_id id of the backup
208
+ # @param [Hash] opts options for creating a {Backup}
209
+ # @option opts [Boolean] :with_wal_files whether to include {WalFiles} in {Backup}
210
+ # @return [Backup] the backup
211
+ def self.by_id(server, backup_id, opts = {})
102
212
  cmd = CliCommand.new
103
- return cmd.backup(server, backup_id, with_wal_files)
213
+ return cmd.backup(server, backup_id, opts)
104
214
  end
105
215
  end
106
216
  end
@@ -1,18 +1,33 @@
1
+ # @author Holger Amann <holger@sauspiel.de
1
2
  module RBarman
3
+
4
+ # An array of {Backup}
2
5
  class Backups < Array
6
+
7
+ # Initializes a new Array of {Backup}
8
+ # @param [Array,Backups] other appends all backups from another array
3
9
  def initialize(other=nil)
4
10
  self.concat(other) if !other.nil? and other.is_a? Array
5
11
  end
6
12
 
7
- def self.all(server, with_wal_files=true)
13
+ # Instructs the underlying (barman) command to get all backups for a specific server
14
+ # @param [String] server server name
15
+ # @param [Hash] opts options for creating {Backups}
16
+ # @option opts [Boolean] :with_wal_files whether to include {WalFiles}
17
+ # @return [Backups] an array of {Backup}
18
+ def self.all(server, opts={})
8
19
  cmd = CliCommand.new
9
- return Backups.new(cmd.backups(server, with_wal_files))
20
+ return Backups.new(cmd.backups(server, opts))
10
21
  end
11
22
 
23
+ # Get the latest (newest) backup of all backups in the array
24
+ # @return [Backup] the latest {Backup}
12
25
  def latest
13
26
  self.sort_by { |d| Time.parse(d.id) }.reverse.first
14
27
  end
15
28
 
29
+ # Get the oldest backup of all backups in the array
30
+ # @return [Backup] the oldest {Backup}
16
31
  def oldest
17
32
  self.sort_by { |d| Time.parse(d.id) }.first
18
33
  end
@@ -1,9 +1,30 @@
1
1
  require 'mixlib/shellout'
2
2
 
3
+ # @author Holger Amann <holger@sauspiel.de>
3
4
  module RBarman
5
+
6
+ # Wrapper for the barman command line tool
4
7
  class CliCommand
5
- attr_reader :binary, :barman_home
6
8
 
9
+ # @overload binary
10
+ # @return [String] path to the barman binary
11
+ # @overload binary=
12
+ # Path to the barman binary
13
+ # @param [String] path path to the binary
14
+ # @raise [ArgumentError] if path doesn't exist or path doesn't end with 'barman'
15
+ attr_reader :binary
16
+
17
+ # @overload barman_home
18
+ # @return [String] base path where barman stores its backups
19
+ # @overload barman_home=
20
+ # Path to the base directory of barman's backups
21
+ # @param [String] path path to the base directory
22
+ # @raise [ArgumentError] if path doesn't exist
23
+ attr_reader :barman_home
24
+
25
+ # Creates a new instance of CliCommand
26
+ # @param [String] path_to_binary see {#binary}. If nil, it will be initialized from {Configuration}
27
+ # @param [String] path_to_barman_home see {#barman_home}. If nil, it will be initialized from {Configuration}
7
28
  def initialize(path_to_binary=nil, path_to_barman_home=nil)
8
29
  self.binary=path_to_binary || Configuration.instance.binary
9
30
  self.barman_home=path_to_barman_home || Configuration.instance.barman_home
@@ -20,19 +41,34 @@ module RBarman
20
41
  @barman_home = path
21
42
  end
22
43
 
23
- def backup(server, backup_id, with_wal_files=true)
44
+ # Instructs barman to get information about a specific backup
45
+ # @param [String] server server name
46
+ # @param [String] backup_id id of the backup
47
+ # @param [Hash] opts options for creating a {Backup}
48
+ # @option opts [Boolean] :with_wal_files whether to include {WalFiles} in each {Backup}
49
+ # @return [Backup] a new {Backup} object
50
+ # @raise [ArgumentError] if backup_id is nil
51
+ def backup(server, backup_id, opts = {})
24
52
  raise(ArgumentError, "backup id must not be nil!") if backup_id.nil?
25
- return backups(server, with_wal_files, backup_id)[0]
53
+ opts[:backup_id] = backup_id
54
+ return backups(server, opts)[0]
26
55
  end
27
56
 
28
- def backups(server, with_wal_files=true, backup_id=nil)
57
+ # Instructs barman to get information about backups
58
+ # @param [String] server server name
59
+ # @param [String] backup_id when given, only information about this backup id will be retrieved
60
+ # @param [Hash] opts options for creating {Backups}
61
+ # @option opts [Boolean] :with_wal_files whether to include {WalFiles} in each {Backup}
62
+ # @option opts [String] :backup_id retrieve just one {Backup} specified by this backup id
63
+ # @return [Backups] an array of {Backup}
64
+ def backups(server, opts = {})
29
65
  list = run_barman_command("list-backup #{server}")
30
- list = list.grep(/#{backup_id}/) if !backup_id.nil?
66
+ list = list.grep(/#{opts[:backup_id]}/) if !opts[:backup_id].nil?
31
67
 
32
68
  backups = parse_backup_list(list)
33
69
  backups.each do |backup|
34
70
  parse_backup_info_file(backup)
35
- if with_wal_files
71
+ if opts[:with_wal_files]
36
72
  wals = wal_files(backup.server, backup.id)
37
73
  wals.each { |w| backup.add_wal_file(w) }
38
74
  end
@@ -40,6 +76,42 @@ module RBarman
40
76
  return backups
41
77
  end
42
78
 
79
+ # Instructs barman to get information about a server
80
+ # @param [String] name name of the server
81
+ # @param [Hash] opts options for creating {Server}
82
+ # @option opts [Boolean] :with_backups whether to include {Backups} in {Server}
83
+ # @option opts [Boolean] :with_wal_files whether to include {WalFiles} in each {Backup}
84
+ # @return [Server] a new {Server}
85
+ def server(name, opts = {})
86
+ lines = run_barman_command("show-server #{name}")
87
+ server = parse_show_server_lines(name, lines)
88
+ lines = run_barman_command("check #{name}")
89
+ parse_check_lines(server, lines)
90
+ server.backups = backups(server.name, opts) if opts[:with_backups]
91
+ return server
92
+ end
93
+
94
+ # Instructs barman to get information about all servers
95
+ # @param [Hash] opts options for creating {Servers}
96
+ # @option opts [Boolean] :with_backups whether to include {Backups}
97
+ # @option opts [Boolean] :with_wal_files whether to include {WalFiles}
98
+ # @return [Servers] an array of {Server}
99
+ def servers(opts = {})
100
+ result = Servers.new
101
+ lines = run_barman_command("list-server")
102
+ server_names = parse_list_server_lines(lines)
103
+ server_names.each do |name|
104
+ result << server(name, opts)
105
+ end
106
+ return result
107
+ end
108
+
109
+ # Instructs barman to list all wal files for a specific backup id
110
+ # @param [String] server server name
111
+ # @param [String] backup_id id of the backup
112
+ # @return [WalFiles] an array of {WalFile}
113
+ # @raise [RuntimeError] if wal file duplicates are found in xlog.db
114
+ # @raise [RuntimeError] if barman lists a wal file but no information could be found in xlog.db
43
115
  def wal_files(server, backup_id)
44
116
  lines = run_barman_command("list-files --target wal #{server} #{backup_id}")
45
117
  wal_files = parse_wal_files_list(lines)
@@ -54,6 +126,65 @@ module RBarman
54
126
  return wal_files
55
127
  end
56
128
 
129
+
130
+ # Parses lines reported by barman's `list-server`
131
+ # @param [Array<String>] lines an array of lines from output of barman's `list-server` cmd
132
+ # @return [Array<String>] an array of server names
133
+ def parse_list_server_lines(lines)
134
+ result = Array.new
135
+ lines.each do |l|
136
+ result << l.split("-")[0].strip
137
+ end
138
+ return result
139
+ end
140
+
141
+
142
+ # Creates a {Server} object by parsing lines reported by barman's `show-server`
143
+ # @param [String] server name of the server
144
+ # @param [Array<String>] lines an array of lines from output of barman's `show-server` cmd
145
+ # @return [Server] a new {Server} object
146
+ def parse_show_server_lines(server, lines)
147
+ s = Server.new(server)
148
+ lines.each do |l|
149
+ key, value = l.gsub("\t","").split(": ")
150
+ case key.chomp
151
+ when "active"
152
+ s.active = value.to_bool
153
+ when "ssh_command"
154
+ s.ssh_cmd = value
155
+ when "conninfo"
156
+ s.conn_info = value
157
+ when "backup_directory"
158
+ s.backup_dir = value
159
+ when "basebackups_directory"
160
+ s.base_backups_dir = value
161
+ when "wals_directory"
162
+ s.wals_dir = value
163
+ end
164
+ end
165
+ return s
166
+ end
167
+
168
+ # Parses lines reported by barman's `check` and assigns according values
169
+ # @param [Server] server the server
170
+ # @param [Array<String>] lines an array of lines from output of barman's `check` cmd
171
+ # @raise [ArgumentError] if server is nil
172
+ def parse_check_lines(server, lines)
173
+ raise(ArgumentError, 'arg server not of type Server') if !server.is_a? Server
174
+ lines.each do |l|
175
+ key, value = l.gsub("\t","").split(": ")
176
+ case key.chomp
177
+ when "ssh"
178
+ server.ssh_check_ok = value == "OK" ? true : false
179
+ when "PostgreSQL"
180
+ server.pg_conn_ok = value == "OK" ? true : false
181
+ end
182
+ end
183
+ end
184
+
185
+ # Creates a {WalFiles} object by parsing lines reported by barman
186
+ # @param [Array<String>] lines an array of lines like '/var/lib/barman/test/wals/00000001000005A9/00000001000005A9000000BC'
187
+ # @return [WalFiles] the {WalFiles}
57
188
  def parse_wal_files_list(lines)
58
189
  wal_files = Array.new
59
190
  lines.each do |line|
@@ -62,6 +193,9 @@ module RBarman
62
193
  return wal_files
63
194
  end
64
195
 
196
+ # Creates an array of {Backup} by parsing lines reported by barman
197
+ # @param [Array<String>] lines an array of lines like 'test 20130218T080002 - Mon Feb 18 18:11:16 2013 - Size: 213.0 GiB - WAL Size: 130.0 GiB'
198
+ # @return [Array<Backup>] an array of {Backup}
65
199
  def parse_backup_list(lines)
66
200
  result = Array.new
67
201
  lines.each do |l|
@@ -75,14 +209,20 @@ module RBarman
75
209
 
76
210
  if b.status == :done
77
211
  sizematch = l.match(/.+Size:\s(.+)\s(.+)\s-.+Size:\s(.+)\s(.+)/)
78
- b.size = size_in_bytes(sizematch[1].to_f, sizematch[2])
79
- b.wal_file_size = size_in_bytes(sizematch[3].to_f, sizematch[4])
212
+ b.size = CliCommand.size_in_bytes(sizematch[1].to_f, sizematch[2])
213
+ b.wal_file_size = CliCommand.size_in_bytes(sizematch[3].to_f, sizematch[4])
80
214
  end
81
215
  result << b
82
216
  end
83
217
  return result
84
218
  end
85
219
 
220
+ # Assigns various values to a {Backup} by parsing the according "backup.info"
221
+ # @param [Backup] backup the backup
222
+ # @return [void]
223
+ # @raise [ArgumentError] if backup is not of type {Backup}
224
+ # @raise [ArgumentError] if backup.id is not set
225
+ # @raise [ArgumentError] if backup.server is not set
86
226
  def parse_backup_info_file(backup)
87
227
  raise(ArgumentError, "arg not of type Backup") if !backup.is_a? Backup
88
228
  raise(ArgumentError, "Backup.id not set") if backup.id.nil?
@@ -111,6 +251,10 @@ module RBarman
111
251
  end
112
252
  end
113
253
 
254
+ # Assigns size, created and compression values to a {WalFile} by parsing a line from xlog.db
255
+ # @param [WalFile] wal_file the wal file
256
+ # @param [String] line a string like '00000001000005A9000000BC\\t4684503\t1360568429.0\\tbzip2'
257
+ # @return [void]
114
258
  def wal_file_info_from_xlog_db_line(wal_file, line)
115
259
  splitted = line.split("\t")
116
260
  wal_file.size = splitted[1]
@@ -118,10 +262,18 @@ module RBarman
118
262
  wal_file.compression = splitted[3].downcase.to_sym
119
263
  end
120
264
 
121
- def size_in_bytes(size, identifier)
122
- raise(ArgumentError, "identifier not one of B|KiB|MiB|GiB|TiB") if !identifier.match(/(B|KiB|MiB|GiB|TiB)/)
265
+ # Converts the size according to the unit to bytes
266
+ # @param [Numeric] size the size
267
+ # @param [String] unit the unit, like `B`, `KiB`, `MiB`, `GiB` or `TiB`
268
+ # @return [Integer] the size in bytes
269
+ # @raise [ArgumentError] if unit is not one of B|KiB|MiB|GiB|TiB
270
+ # @example
271
+ # CliCommand.size_in_bytes(2048, 'B') #=> 2048
272
+ # CliCommand.size_in_bytes(2048, 'MiB') #=> 2048 * 1024 ** 2
273
+ def self.size_in_bytes(size, unit)
274
+ raise(ArgumentError, "unit not one of B|KiB|MiB|GiB|TiB") if !unit.match(/(B|KiB|MiB|GiB|TiB)/)
123
275
  size_b = 0
124
- case identifier
276
+ case unit
125
277
  when "B"
126
278
  size_b = size
127
279
  when "KiB"
@@ -136,10 +288,17 @@ module RBarman
136
288
  return size_b.to_i
137
289
  end
138
290
 
291
+ # Instructs barman to delete a specific backup
292
+ # @param [String] server server name
293
+ # @param [String] backup_id id of the backup
294
+ # @return [void]
139
295
  def delete(server, backup_id)
140
296
  run_barman_command("delete #{server} #{backup_id}")
141
297
  end
142
298
 
299
+ # Instructs barman to create a backup
300
+ # @param [String] server server name
301
+ # @return [void]
143
302
  def create(server)
144
303
  run_barman_command("backup #{server}")
145
304
  end
@@ -1,25 +1,39 @@
1
1
  require 'singleton'
2
2
 
3
3
  module RBarman
4
+
5
+ # A very flexible configuration class, to be used as Singleton
4
6
  class Configuration
5
7
  include Singleton
6
8
 
9
+ # Creates a new instance of {Configuration}
10
+ # @param [Hash] data added as configuration parameters
7
11
  def initialize(data={})
8
12
  @data = {}
9
13
  update!(data)
10
14
  basic_configuration
11
15
  end
12
16
 
17
+ # Adds parameters
18
+ # @param [Hash] data parameters to add
19
+ # @return [void]
13
20
  def update!(data)
14
21
  data.each do |key, value|
15
22
  self[key] = value
16
23
  end
17
24
  end
18
25
 
26
+ # Gives access to parameters
27
+ # @param [String,Symbol] key the key
28
+ # @return [Object, nil] the value
19
29
  def [](key)
20
30
  @data[key.to_sym]
21
31
  end
22
32
 
33
+ # Adds a new parameter
34
+ # @param [String] key the key
35
+ # @param [Object] value the value
36
+ # @return [void]
23
37
  def []=(key, value)
24
38
  if value.class == Hash
25
39
  @data[key.to_sym] = Config.new(value)
@@ -28,6 +42,16 @@ module RBarman
28
42
  end
29
43
  end
30
44
 
45
+ # For catching [NoMethodError] and trying to add a new parameter or returning a parameter value, based on the "missing" method name
46
+ # @param [Symbol] sym the method name
47
+ # @param [Array] args the arguments passed to the method.
48
+ # @return [Object, nil, void] when method name doesn't end with an `=` operator, a parameter value will be returned (if found, otherwise nil)
49
+ # @example
50
+ # Configuration.instance[:some_key] = "some_value"
51
+ # Configuration.instance.some_key #=> "some_value"
52
+ # Configuration.instance.another_key = { :a => 1 }
53
+ # Configuration.instance[:another_key] #=> { :a => 1}
54
+ # Configuration.instance[:missing] #=> nil
31
55
  def method_missing(sym, *args)
32
56
  if sym.to_s =~ /(.+)=$/
33
57
  self[$1] = args.first
@@ -36,6 +60,11 @@ module RBarman
36
60
  end
37
61
  end
38
62
 
63
+ # adds `:binary` with path to barman binary as value and `:barman_home` (default $HOME) with path to barman's backup base directory as value. If `which` reports a path for barman, that path will be used, otherwise `/usr/bin/barman`
64
+ # @return [void]
65
+ # @example
66
+ # Configuration.Instance.binary #=> "/usr/bin/barman"
67
+ # Configuration.Instance.barman_home #=> "/var/lib/barman"
39
68
  def basic_configuration
40
69
  b_path = `which barman`.chomp
41
70
  self[:binary] = b_path.empty? ? '/usr/bin/barman' : b_path
@@ -0,0 +1,83 @@
1
+ # @author Holger Amann <holger@sauspiel.de>
2
+
3
+ module RBarman
4
+
5
+ # Represents a server for which barman should do/have backups
6
+ class Server
7
+
8
+ # @param [String] name name of the server
9
+ # @return [String] name of the server
10
+ attr_accessor :name
11
+
12
+ # @param [Boolean] active if server is active
13
+ # @return [Boolean, nil] if server is active
14
+ attr_accessor :active
15
+
16
+ # @param [String] cmd ssh command
17
+ # @return [String, nil] the ssh command
18
+ attr_accessor :ssh_cmd
19
+
20
+ # @param [String] the connection info
21
+ # @return [String, nil] the connection info
22
+ attr_accessor :conn_info
23
+
24
+ # @param [String] path to backup directory
25
+ # @return [String, nil] the path to backup directory
26
+ attr_accessor :backup_dir
27
+
28
+ # @param [String] path to base backups directory
29
+ # @return [String, nil] the path to base backups directory
30
+ attr_accessor :base_backups_dir
31
+
32
+ # @param [String] path to wals directory
33
+ # @return [String, nil] the path to wals directory
34
+ attr_accessor :wals_dir
35
+
36
+ # @param [Boolean] if SSH connection is working
37
+ # @return [Boolean, nil] if SSH connection is working
38
+ attr_accessor :ssh_check_ok
39
+
40
+ # @param [Boolean] if PostgreSQL connection is working
41
+ # @return [Boolean, nil] if PostgreSQL connection is working
42
+ attr_accessor :pg_conn_ok
43
+
44
+ # @param [Backups] server backups
45
+ # @return [Backups, nil] server backups
46
+ attr_accessor :backups
47
+
48
+
49
+ # Creates a new instance of {Server}
50
+ def initialize(name)
51
+ @name = name
52
+ end
53
+
54
+ # Instructs the underlying (barman) command to get information about a server
55
+ # @param [String] name name of the server
56
+ # @param [Hash] opts options for creating {Server}
57
+ # @option opts [Boolean] :with_backups whether to include {Backups}
58
+ # @option opts [Boolean] :with_wal_files whether to include {WalFiles} in each {Backup}
59
+ def self.by_name(name, opts = {})
60
+ cmd = CliCommand.new
61
+ return cmd.server(name, opts)
62
+ end
63
+ end
64
+
65
+ # An array of {Server}
66
+ class Servers < Array
67
+ # Initializes a new Array of {Server}
68
+ # @param [Array, Servers] other appends all servers from another array
69
+ def initialize(other=nil)
70
+ self.concat(other) if !other.nil? and other.is_a? Array
71
+ end
72
+
73
+ # Instructs the underlying (barman) command to get all servers
74
+ # @param [Hash] opts options for creating {Servers}
75
+ # @option opts [Boolean] :with_backups whether to include {Backups}
76
+ # @option opts [Boolean] :with_wal_files whether to include {WalFiles}
77
+ # @return [Servers] an array of {Server}
78
+ def self.all(opts={})
79
+ cmd = CliCommand.new
80
+ return Servers.new(cmd.servers(opts))
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,7 @@
1
+ class String
2
+ def to_bool
3
+ return true if self == true || self =~ (/\A(true|t|yes|y|1)\Z/i)
4
+ return false if self == false || self.empty? || self =~ (/\A(false|f|no|n|0)\Z/i)
5
+ raise ArgumentError.new("invalid value for Boolean: \"#{self}\"")
6
+ end
7
+ end
@@ -1,3 +1,3 @@
1
1
  module RBarman
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
@@ -1,14 +1,62 @@
1
1
  require 'time'
2
2
 
3
+ # @author Holger Amann <holger@sauspiel.de>
3
4
  module RBarman
4
5
 
5
6
  class InvalidWalFileNameError < RuntimeError
6
7
  end
7
8
 
9
+ # Represents a wal file
8
10
  class WalFile
9
11
 
10
- attr_reader :timeline, :xlog, :segment, :created, :compression, :size
11
-
12
+ # @overload timeline
13
+ # @return [String, nil] timeline part of the wal file
14
+ # @overload timeline=
15
+ # Timeline part of the wal file
16
+ # @param [#to_s] timeline the timeline part
17
+ # @raise [ArgumentError] if timeline length != 8
18
+ attr_reader :timeline
19
+
20
+ # @overload xlog
21
+ # @return [String, nil] xlog part of the wal file
22
+ # @overload xlog=
23
+ # xlog part of the wal file
24
+ # @param [#to_s] xlog the xlog part
25
+ # @raise [ArgumentError] if xlog length != 8
26
+ attr_reader :xlog
27
+
28
+ # @overload segment
29
+ # @return [String, nil] segment part of the wal file
30
+ # @overload segment=
31
+ # segment part of the wal file
32
+ # @param [#to_s] segment the segment part
33
+ # @raise [ArgumentError] if segment length != 8
34
+ attr_reader :segment
35
+
36
+ # @overload created
37
+ # @return [Time, nil] time when wal file has been created
38
+ # @overload created=
39
+ # Time when wal file has been created
40
+ # @param [Time,Numeric,String] created the time
41
+ attr_reader :created
42
+
43
+ # @overload compression
44
+ # @return [Symbol, nil] compression type of wal file, `:none`, `:gzip`, `:bzip2`, `:custom`
45
+ # @overload compression=
46
+ # Compression type of wal file
47
+ # @param [Symbol] compression compression type
48
+ # @raise [ArgumentError] if compression is not one of `:none`, `:gzip`, `:bzip2`, `:custom`
49
+ attr_reader :compression
50
+
51
+
52
+ # @overload size
53
+ # @return [Integer, nil] size of wal file (in bytes)
54
+ # @overload size=
55
+ # Size of wal file (in bytes)
56
+ # @param [#to_i] size size of wal file (in bytes)
57
+ attr_reader :size
58
+
59
+ # Creates a new instance of {WalFile}
12
60
  def initialize
13
61
  end
14
62
 
@@ -48,6 +96,11 @@ module RBarman
48
96
  @created = Time.parse(created) if created.is_a? String
49
97
  end
50
98
 
99
+ # Creates a new WalFile from the given argument
100
+ # @param [String, WalFile] name the wal file name
101
+ # @return [WalFile] the created WalFile
102
+ # @raise [InvalidWalFileNameError] if name is a string and string's length isn't exactly 24 chars or
103
+ # name could not be splitted in 3 parts (timeline|xlog|segment)
51
104
  def self.parse(name)
52
105
  raise(InvalidWalFileNameError, "name has to be exactly 24 chars") if !name.is_a? WalFile and name.to_s.size != 24
53
106
 
@@ -66,6 +119,9 @@ module RBarman
66
119
  return wal_file
67
120
  end
68
121
 
122
+ # Checks if other is equal to self by comparing timeline, xlog and segment
123
+ # @param [String, WalFile] other other wal file
124
+ # @return [Boolean] if other is equal to self
69
125
  def ==(other)
70
126
  o = other
71
127
  o = WalFile.parse(other.to_s) if !other.is_a? WalFile
@@ -0,0 +1,22 @@
1
+ # @author Holger Amann <holger@sauspiel.de>
2
+ module RBarman
3
+
4
+ # An Array of WalFile
5
+ class WalFiles < Array
6
+
7
+ # Initializes a new Array of {WalFile}
8
+ # @param [Array,WalFiles] other appends all wal files from another array
9
+ def initialize(other=nil)
10
+ self.concat(other) if !other.nil? and other.is_a? Array
11
+ end
12
+
13
+ # Instructs the underlying (barman) command to get all wal files for a specific backup id
14
+ # @param [String] server server name
15
+ # @param [String] backup_id id of the backup
16
+ # @return [WalFiles] an array of {WalFile}
17
+ def self.by_id(server, backup_id)
18
+ cmd = CliCommand.new
19
+ return WalFiles.new(cmd.wal_files(server, backup_id))
20
+ end
21
+ end
22
+ end
data/lib/rbarman.rb CHANGED
@@ -1,9 +1,13 @@
1
+ require "rbarman/string"
1
2
  require "rbarman/version"
2
3
  require "rbarman/backup"
3
4
  require "rbarman/backups"
4
5
  require "rbarman/wal_file"
6
+ require "rbarman/wal_files"
5
7
  require "rbarman/cli_command"
6
8
  require "rbarman/configuration"
9
+ require "rbarman/server"
7
10
 
11
+ # The RBarman module contains all aspects of backups made by barman and dealing with them
8
12
  module RBarman
9
13
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rbarman
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-03-09 00:00:00.000000000 Z
12
+ date: 2013-03-12 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -75,7 +75,7 @@ dependencies:
75
75
  - - ~>
76
76
  - !ruby/object:Gem::Version
77
77
  version: 1.1.0
78
- description: Wrapper about 2ndQuadrant's postgresql backup tool \'barman\'
78
+ description: Wrapper about 2ndQuadrant's postgresql backup tool 'barman'
79
79
  email:
80
80
  - holger@sauspiel.de
81
81
  executables: []
@@ -86,8 +86,11 @@ files:
86
86
  - lib/rbarman/backups.rb
87
87
  - lib/rbarman/cli_command.rb
88
88
  - lib/rbarman/configuration.rb
89
+ - lib/rbarman/server.rb
90
+ - lib/rbarman/string.rb
89
91
  - lib/rbarman/version.rb
90
92
  - lib/rbarman/wal_file.rb
93
+ - lib/rbarman/wal_files.rb
91
94
  - lib/rbarman.rb
92
95
  - LICENSE.txt
93
96
  - README.md
@@ -115,5 +118,6 @@ rubyforge_project:
115
118
  rubygems_version: 1.8.23
116
119
  signing_key:
117
120
  specification_version: 3
118
- summary: Wrapper about 2ndQuadrant's postgresql backup tool \'barman\'
121
+ summary: Wrapper about 2ndQuadrant's postgresql backup tool 'barman'
119
122
  test_files: []
123
+ has_rdoc: