Class: Restic::Service::Conf
- Inherits:
-
Object
- Object
- Restic::Service::Conf
- Defined in:
- lib/restic/service/conf.rb
Overview
The overall service configuration
This is the API side of the service configuration. The configuration is usually stored on disk in YAML and
The YAML format is as follows:
# The path to the underlying tools
tools:
restic: /opt/restic
rclone: /opt/rclone
# The targets. The only generic parts of a target definition
# are the name and type. The rest is target-specific
targets:
- name: a_restic_sftp_target
type: restic-sftp
See the README.md for more details about available targets
Defined Under Namespace
Classes: InvalidConfigurationFile, NoSuchTarget
Constant Summary collapse
- TARGET_CLASS_FROM_TYPE =
- TOOLS =
%w{restic rclone}
- BANDWIDTH_SCALES =
Instance Attribute Summary collapse
-
#bandwidth_limit ⇒ nil, Integer
readonly
The bandwidth limit in bytes/s.
-
#conf_path ⇒ Pathname
readonly
The configuration path.
-
#period ⇒ Integer
readonly
The polling period in seconds.
Class Method Summary collapse
-
.default_conf ⇒ Object
The default (empty) configuration.
-
.load(path) ⇒ Conf
Load a configuration file.
-
.normalize_yaml(yaml) ⇒ Object
Normalizes and validates a configuration hash, as stored in YAML.
- .parse_bandwidth_limit(limit) ⇒ Object
-
.target_class_from_type(type) ⇒ Object
Returns the target class that will handle the given target type.
Instance Method Summary collapse
- #auto_update_rclone? ⇒ Boolean
- #auto_update_restic? ⇒ Boolean
- #auto_update_restic_service? ⇒ Boolean
-
#conf_keys_path_for(target) ⇒ Object
The path to the key file for the given target.
-
#each_target(&block) ⇒ Object
Enumerates the targets.
-
#find_in_path(name) ⇒ Object
private
Helper that resolves a binary in PATH.
-
#initialize(conf_path) ⇒ Conf
constructor
A new instance of Conf.
-
#load_from_yaml(yaml) ⇒ void
Add the information stored in a YAML-like hash into this configuration.
-
#load_tools_from_yaml(yaml) ⇒ Object
private
Helper for #load_from_yaml.
- #rclone_platform ⇒ Object
-
#register_target(target) ⇒ Object
Registers a target.
- #restic_platform ⇒ Object
-
#target_by_name(name) ⇒ Target
Gets a target configuration.
-
#tool_available?(tool_name) ⇒ Boolean
Checks whether a given tool is available.
-
#tool_path(tool_name, only_if_present: true) ⇒ Pathname
The full path of a given tool.
Constructor Details
#initialize(conf_path) ⇒ Conf
Returns a new instance of Conf.
132 133 134 135 136 137 138 139 140 |
# File 'lib/restic/service/conf.rb', line 132 def initialize(conf_path) @conf_path = conf_path @targets = Hash.new @period = 3600 @tools = Hash.new TOOLS.each do |tool_name| @tools[tool_name] = find_in_path(tool_name) end end |
Instance Attribute Details
#bandwidth_limit ⇒ nil, Integer (readonly)
The bandwidth limit in bytes/s
Default is nil (none)
130 131 132 |
# File 'lib/restic/service/conf.rb', line 130 def bandwidth_limit @bandwidth_limit end |
#conf_path ⇒ Pathname (readonly)
The configuration path
116 117 118 |
# File 'lib/restic/service/conf.rb', line 116 def conf_path @conf_path end |
#period ⇒ Integer (readonly)
The polling period in seconds
Default is 1h (3600s)
123 124 125 |
# File 'lib/restic/service/conf.rb', line 123 def period @period end |
Class Method Details
.default_conf ⇒ Object
The default (empty) configuration
29 30 31 32 33 34 |
# File 'lib/restic/service/conf.rb', line 29 def self.default_conf Hash['targets' => [], 'period' => 3600, 'bandwidth_limit' => nil, 'tools' => Hash.new] end |
.load(path) ⇒ Conf
Load a configuration file
100 101 102 103 104 105 106 107 108 109 110 111 |
# File 'lib/restic/service/conf.rb', line 100 def self.load(path) if !path.file? return Conf.new(Pathname.new("")) end yaml = YAML.load(path.read) || Hash.new yaml = normalize_yaml(yaml) conf = Conf.new(path.dirname) conf.load_from_yaml(yaml) conf end |
.normalize_yaml(yaml) ⇒ Object
Normalizes and validates a configuration hash, as stored in YAML
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 |
# File 'lib/restic/service/conf.rb', line 59 def self.normalize_yaml(yaml) yaml = default_conf.merge(yaml) TOOLS.each do |tool_name| yaml['tools'][tool_name] ||= tool_name end yaml['auto_update'] ||= Array.new target_names = Array.new yaml['targets'] = yaml['targets'].map do |target| if !target['name'] raise InvalidConfigurationFile, "missing 'name' field in target" elsif !target['type'] raise InvalidConfigurationFile, "missing 'type' field in target" end target_class = target_class_from_type(target['type']) if !target_class raise InvalidConfigurationFile, "target type #{target['type']} does not exist, "\ "available targets: #{TARGET_CLASS_FROM_TYPE.keys.sort.join(", ")}" end name = target['name'].to_s if target_names.include?(name) raise InvalidConfigurationFile, "duplicate target name '#{name}'" end target = target.dup target['name'] = name target = target_class.normalize_yaml(target) target_names << name target end yaml end |
.parse_bandwidth_limit(limit) ⇒ Object
148 149 150 151 152 153 154 155 156 157 158 159 |
# File 'lib/restic/service/conf.rb', line 148 def self.parse_bandwidth_limit(limit) if !limit.respond_to?(:to_str) return Integer(limit) else match = /^(\d+)\s*(k|m|g)?$/.match(limit.downcase) if match return Integer(match[1]) * BANDWIDTH_SCALES.fetch(match[2]) else raise ArgumentError, "cannot interpret '#{limit}' as a valid bandwidth limit, give a plain number in bytes or use the k, M and G suffixes" end end end |
.target_class_from_type(type) ⇒ Object
Returns the target class that will handle the given target type
48 49 50 51 52 53 54 |
# File 'lib/restic/service/conf.rb', line 48 def self.target_class_from_type(type) if target_class = TARGET_CLASS_FROM_TYPE[type] return target_class else raise InvalidConfigurationFile, "target type #{type} does not exist, available targets: #{TARGET_CLASS_FROM_TYPE.keys.sort.join(", ")}" end end |
Instance Method Details
#auto_update_rclone? ⇒ Boolean
235 236 237 |
# File 'lib/restic/service/conf.rb', line 235 def auto_update_rclone? @auto_update_rclone end |
#auto_update_restic? ⇒ Boolean
227 228 229 |
# File 'lib/restic/service/conf.rb', line 227 def auto_update_restic? @auto_update_restic end |
#auto_update_restic_service? ⇒ Boolean
223 224 225 |
# File 'lib/restic/service/conf.rb', line 223 def auto_update_restic_service? @auto_update_restic_service end |
#conf_keys_path_for(target) ⇒ Object
The path to the key file for the given target
162 163 164 |
# File 'lib/restic/service/conf.rb', line 162 def conf_keys_path_for(target) conf_path.join("keys", "#{target.name}.keys") end |
#each_target(&block) ⇒ Object
Enumerates the targets
180 181 182 |
# File 'lib/restic/service/conf.rb', line 180 def each_target(&block) @targets.each_value(&block) end |
#find_in_path(name) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Helper that resolves a binary in PATH
192 193 194 195 196 197 198 199 200 |
# File 'lib/restic/service/conf.rb', line 192 def find_in_path(name) ENV['PATH'].split(File::PATH_SEPARATOR).each do |p| candidate = Pathname.new(p).join(name) if candidate.file? return candidate end end nil end |
#load_from_yaml(yaml) ⇒ void
This method returns an undefined value.
Add the information stored in a YAML-like hash into this configuration
249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 |
# File 'lib/restic/service/conf.rb', line 249 def load_from_yaml(yaml) load_tools_from_yaml(yaml['tools']) @period = Integer(yaml['period']) @bandwidth_limit = if limit_yaml = yaml['bandwidth_limit'] Conf.parse_bandwidth_limit(limit_yaml) end yaml['auto_update'].each do |update_target, do_update| if update_target == 'restic-service' @auto_update_restic_service = do_update elsif update_target == 'restic' @auto_update_restic = do_update elsif update_target == 'rclone' @auto_update_rclone = do_update end end yaml['targets'].each do |yaml_target| type = yaml_target['type'] target_class = Conf.target_class_from_type(type) target = target_class.new(yaml_target['name']) target.setup_from_conf(self, yaml_target) register_target(target) end end |
#load_tools_from_yaml(yaml) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Helper for #load_from_yaml
278 279 280 281 282 283 284 285 286 287 288 289 |
# File 'lib/restic/service/conf.rb', line 278 def load_tools_from_yaml(yaml) TOOLS.each do |tool_name| tool_path = Pathname.new(yaml[tool_name]) if tool_path.relative? tool_path = find_in_path(tool_path) end exists = tool_path.file? STDERR.puts "#{tool_path} does not exist" unless exists @tools[tool_name] = [tool_path, exists] end end |
#rclone_platform ⇒ Object
239 240 241 |
# File 'lib/restic/service/conf.rb', line 239 def rclone_platform @auto_update_rclone end |
#register_target(target) ⇒ Object
Registers a target
185 186 187 |
# File 'lib/restic/service/conf.rb', line 185 def register_target(target) @targets[target.name] = target end |
#restic_platform ⇒ Object
231 232 233 |
# File 'lib/restic/service/conf.rb', line 231 def restic_platform @auto_update_restic end |
#target_by_name(name) ⇒ Target
Gets a target configuration
171 172 173 174 175 176 177 |
# File 'lib/restic/service/conf.rb', line 171 def target_by_name(name) if target = @targets[name] target else raise NoSuchTarget, "no target named '#{name}'" end end |
#tool_available?(tool_name) ⇒ Boolean
Checks whether a given tool is available
206 207 208 209 |
# File 'lib/restic/service/conf.rb', line 206 def tool_available?(tool_name) _, available = @tools[tool_name] available end |
#tool_path(tool_name, only_if_present: true) ⇒ Pathname
The full path of a given tool
215 216 217 218 219 220 221 |
# File 'lib/restic/service/conf.rb', line 215 def tool_path(tool_name, only_if_present: true) if tool = @tools[tool_name] tool[0] if tool[1] || !only_if_present else raise ArgumentError, "cound not find '#{tool_name}'" end end |