landscape-turner 1.2.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/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +45 -0
- data/Rakefile +10 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/exe/landscape-turner-backup +10 -0
- data/exe/landscape-turner-restore +10 -0
- data/landscape-turner.gemspec +29 -0
- data/lib/landscape-turner/backup.rb +116 -0
- data/lib/landscape-turner/helpers.rb +25 -0
- data/lib/landscape-turner/restore.rb +87 -0
- data/lib/landscape-turner/version.rb +3 -0
- metadata +125 -0
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2016 DAQRI
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
# Landscape Turner
|
2
|
+
|
3
|
+
Landscape Turner is a set of two ruby scripts for backing up the Landscape service, `landscape-turner-backup` and `landscape-turner-restore` .
|
4
|
+
|
5
|
+
## General Usage
|
6
|
+
|
7
|
+
```bash
|
8
|
+
$ landscape-turner-backup --snapshot-path=/home/daqri/backup
|
9
|
+
|
10
|
+
$ landscape-turner-restore /home/daqri/backup.tar.gz
|
11
|
+
```
|
12
|
+
|
13
|
+
## Options for landscape-turner-backup
|
14
|
+
|
15
|
+
###-s, --snapshot-path=/path/to/snapshot
|
16
|
+
Required
|
17
|
+
|
18
|
+
###-o, --override=*string*
|
19
|
+
Override paths with -o name1=path1
|
20
|
+
|
21
|
+
### -d, --disable=*string*
|
22
|
+
Disable paths with -d name
|
23
|
+
|
24
|
+
### -n, --no-db
|
25
|
+
Disable database backup
|
26
|
+
|
27
|
+
### -l, --landscape-prefix=/path/to/default/dirs
|
28
|
+
Path to prefix default landscape dirs (/var, /etc), default is nothing.
|
29
|
+
|
30
|
+
### -p, --no-op
|
31
|
+
No-op (dry run)
|
32
|
+
|
33
|
+
|
34
|
+
To override specific paths, use `-o name1=path1 -o name2=path2 -o name3=path3`. To disable specific paths for backup, use `-d name1 -d name2`. Overrides have higher priority than `--landscape-prefix`.
|
35
|
+
|
36
|
+
## Options for landscape-turner-restore
|
37
|
+
|
38
|
+
### -r, --restore-prefix=*string*
|
39
|
+
Prefix to prepend default landscape dirs (/var, /etc) with (default: nothing)
|
40
|
+
|
41
|
+
### -n, --no-db
|
42
|
+
Disable database restore
|
43
|
+
|
44
|
+
|
45
|
+
In addition to the optional arguments, you must specify exactly one .tar.gz file to restore.
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "landscape_turner"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start
|
data/bin/setup
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'landscape-turner/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "landscape-turner"
|
8
|
+
spec.version = LandscapeTurner::VERSION
|
9
|
+
spec.authors = ["Justin Boisvert"]
|
10
|
+
spec.email = ["justin.boisvert@daqri.com"]
|
11
|
+
|
12
|
+
spec.summary = "Backup tool for the Landscape service"
|
13
|
+
spec.description = "A backup tool for the Landscape service that backs up the configuration files and the database related to the service."
|
14
|
+
spec.homepage = "http://www.daqri.com"
|
15
|
+
|
16
|
+
# Prevent pushing this gem to RubyGems.org by setting 'allowed_push_host', or
|
17
|
+
# delete this section to allow pushing this gem to any host.
|
18
|
+
|
19
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
20
|
+
spec.bindir = "exe"
|
21
|
+
spec.executables << "landscape-turner-backup"
|
22
|
+
spec.executables << "landscape-turner-restore"
|
23
|
+
spec.require_paths = ["lib"]
|
24
|
+
|
25
|
+
spec.add_runtime_dependency "trollop"
|
26
|
+
spec.add_development_dependency "bundler", "~> 1.11"
|
27
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
28
|
+
spec.add_development_dependency "minitest"
|
29
|
+
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
require_relative 'helpers'
|
2
|
+
require 'fileutils'
|
3
|
+
require 'pathname'
|
4
|
+
require 'open3'
|
5
|
+
require 'trollop'
|
6
|
+
|
7
|
+
class Backup
|
8
|
+
extend LandscapeTurner::Helpers
|
9
|
+
|
10
|
+
def self.backup_with_cli_args(args = ARGV)
|
11
|
+
paths = {
|
12
|
+
:x509_certificate => "/etc/ssl/certs/landscape_server.pem",
|
13
|
+
:ca_certificate => "/etc/ssl/certs/landscape_server_ca.crt",
|
14
|
+
:ssl_private_key => "/etc/ssl/private/landscape_server.key",
|
15
|
+
:postgresql_config => "/etc/postgresql/9.3/main",
|
16
|
+
:apache_config => "/etc/apache2/sites-available/landscape-server.conf",
|
17
|
+
:hash_id_database => "/var/lib/landscape/hash-id-databases",
|
18
|
+
:landscape_dir => "/etc/landscape",
|
19
|
+
:landscape_default => "/etc/default/landscape-server",
|
20
|
+
}
|
21
|
+
|
22
|
+
new_args = Trollop.options(args) do
|
23
|
+
opt :snapshot_path, "Path to snapshot (required)", :type => String
|
24
|
+
opt :override, "Override paths with -o name1=path1", :type => :strings
|
25
|
+
opt :disable, "Disable paths with -d name", :type => :strings
|
26
|
+
opt :no_db, "Disable database backup"
|
27
|
+
opt :landscape_prefix, "Path to prefix default landscape dirs (/var, /etc) with", :default => ""
|
28
|
+
opt :no_op, "No-op (dry run)"
|
29
|
+
opt :sudo, "Program to use as sudo", :default => "sudo"
|
30
|
+
|
31
|
+
banner <<-USAGE
|
32
|
+
To override specific paths, use -o name1=path1 -o name2=path2 -o name3=path3
|
33
|
+
To disable specific paths for backup, use -d name1 -d name2
|
34
|
+
Overrides have higher priority than --landscape-prefix.
|
35
|
+
|
36
|
+
Names with default values:
|
37
|
+
#{paths.keys.map { |k| " #{k}: #{paths[k]}"} }
|
38
|
+
USAGE
|
39
|
+
end
|
40
|
+
|
41
|
+
@@sudo = new_args[:sudo]
|
42
|
+
|
43
|
+
prefix = new_args[:landscape_prefix]
|
44
|
+
paths.each { |k, v| paths[k] = "#{prefix}#{v}" }
|
45
|
+
|
46
|
+
(new_args[:override] || []).each do |o|
|
47
|
+
key, val = o.split("=")
|
48
|
+
key = key.to_sym
|
49
|
+
raise "Unrecognized name argument: #{key.inspect}!" unless paths[key]
|
50
|
+
paths[key] = val
|
51
|
+
end
|
52
|
+
|
53
|
+
(new_args[:disable] || []).each do |d|
|
54
|
+
raise "Unrecognized name argument: #{d.inspect}!" unless paths[key]
|
55
|
+
paths.delete d.to_sym
|
56
|
+
end
|
57
|
+
|
58
|
+
backup_landscape(new_args, paths, prefix)
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.backup_landscape(params = {}, paths, prefix)
|
62
|
+
#check required arguments needed
|
63
|
+
unless params[:snapshot_path]
|
64
|
+
raise ArgumentError, "Error: Must supply snapshot path with --snapshot-path"
|
65
|
+
end
|
66
|
+
destination = params[:snapshot_path] + "/"
|
67
|
+
operate = !params[:no_op]
|
68
|
+
|
69
|
+
#create the top-level destination path
|
70
|
+
operate ? (FileUtils.mkdir(destination) rescue nil) : nil
|
71
|
+
|
72
|
+
paths.each do |name, path|
|
73
|
+
# Get path relative to landscape_prefix
|
74
|
+
rel_path = Pathname.new(path).relative_path_from(Pathname.new(File.expand_path(prefix))).to_s
|
75
|
+
|
76
|
+
# Make sure destination subdir exists
|
77
|
+
dest_subdir = File.dirname "#{destination}/#{rel_path}"
|
78
|
+
puts "Copying #{path} to #{dest_subdir}..."
|
79
|
+
FileUtils.mkdir_p dest_subdir if operate
|
80
|
+
FileUtils.cp_r(path, dest_subdir, :preserve => true) if operate
|
81
|
+
end
|
82
|
+
|
83
|
+
puts "Backing up Postgres databases.."
|
84
|
+
(operate && !params[:no_db]) ? dump_landscape_databases(destination) : nil
|
85
|
+
destination = params[:snapshot_path]
|
86
|
+
puts "Compressing to file #{destination}.tar.gz"
|
87
|
+
tgz_file = "#{File.basename(destination)}.tar.gz"
|
88
|
+
operate ? safe_system("cd #{destination} && rm -f #{tgz_file} && tar -cpzf #{tgz_file} * && mv #{tgz_file} ..") : nil
|
89
|
+
if operate && !check_consistent_tar(destination)
|
90
|
+
raise "Tarball inconsistent with backup"
|
91
|
+
end
|
92
|
+
# remove the folder where we stored everything
|
93
|
+
operate ? FileUtils.remove_dir(destination) : nil
|
94
|
+
puts "Finished backing up to #{destination}"
|
95
|
+
end
|
96
|
+
|
97
|
+
def self.dump_landscape_databases(backup_destination)
|
98
|
+
FileUtils.mkdir("#{backup_destination}/postgresql_backup") rescue nil
|
99
|
+
get_landscape_databases().each { |database_name|
|
100
|
+
# pg_dump dbname > outfile
|
101
|
+
safe_system("cd /tmp && sudo -u postgres pg_dump #{database_name} > #{database_name}.bak")
|
102
|
+
FileUtils.mv("/tmp/#{database_name}.bak","#{backup_destination}/postgresql_backup/")
|
103
|
+
}
|
104
|
+
end
|
105
|
+
|
106
|
+
def self.check_consistent_tar(destination)
|
107
|
+
FileUtils.rm_rf("/tmp/tar_check")
|
108
|
+
puts "cd #{File.dirname(destination)} && mkdir /tmp/tar_check && tar -xf #{File.basename(destination)}.tar.gz -C /tmp/tar_check"
|
109
|
+
safe_system("cd #{File.dirname(destination)} && mkdir /tmp/tar_check && tar -xf #{File.basename(destination)}.tar.gz -C /tmp/tar_check")
|
110
|
+
hash_folder1 = Open3.capture3("find #{destination} -type f 2>/dev/null -exec md5sum {} \;")
|
111
|
+
hash_folder2 = Open3.capture3("find /tmp/tar_check -type f 2>/dev/null -exec md5sum {} \;")
|
112
|
+
FileUtils.rm_rf("/tmp/tar_check")
|
113
|
+
return hash_folder1 == hash_folder2
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'open3'
|
2
|
+
|
3
|
+
module LandscapeTurner
|
4
|
+
module Helpers
|
5
|
+
def safe_system(cmd)
|
6
|
+
e = system(cmd)
|
7
|
+
raise "Failure in command: #{cmd.inspect}!" unless e
|
8
|
+
end
|
9
|
+
def get_landscape_databases()
|
10
|
+
landscape_databases = Array.new()
|
11
|
+
list = Open3.capture3("cd /tmp && sudo -u postgres psql -qlA")[0].split("\n")
|
12
|
+
#This is to remove irrelevant information generated from this command at the first and last line.
|
13
|
+
list.shift()
|
14
|
+
list.pop()
|
15
|
+
landscape_list = Array.new()
|
16
|
+
list.each { |item|
|
17
|
+
db_name = item.split("|")[0]
|
18
|
+
if db_name.start_with?("landscape")
|
19
|
+
landscape_list.push(db_name)
|
20
|
+
end
|
21
|
+
}
|
22
|
+
return landscape_list
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
require_relative 'helpers'
|
2
|
+
require_relative 'backup'
|
3
|
+
require 'fileutils'
|
4
|
+
|
5
|
+
# TODO: Document that overridden files get restored to their
|
6
|
+
# original location
|
7
|
+
|
8
|
+
class Restore
|
9
|
+
extend LandscapeTurner::Helpers
|
10
|
+
POSTGRES_CONFIG = "/etc/postgresql/9.3/main"
|
11
|
+
EXCLUDE_FILES = [POSTGRES_CONFIG]
|
12
|
+
def self.restore_with_cli_args(args = ARGV)
|
13
|
+
opts = Trollop.options(args) do
|
14
|
+
opt :restore_prefix, "Prefix to prepend default landscape dirs (/var, /etc) with", :default => ""
|
15
|
+
opt :no_db, "Disable database restore"
|
16
|
+
opt :sudo, "Program to use as 'sudo'", :default => "sudo"
|
17
|
+
|
18
|
+
banner <<-USAGE
|
19
|
+
In addition to optional arguments, give exactly one .tar.gz file to restore.
|
20
|
+
USAGE
|
21
|
+
end
|
22
|
+
|
23
|
+
raise "You must supply exactly one argument, the backup path!" unless args.size == 1
|
24
|
+
@@sudo = opts[:sudo]
|
25
|
+
restore_landscape args[0], opts
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.with_service_stopped(service)
|
29
|
+
begin
|
30
|
+
safe_system("#{@@sudo} service #{service} stop")
|
31
|
+
yield
|
32
|
+
ensure
|
33
|
+
safe_system("#{@@sudo} service #{service} start")
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.restore_landscape(backup_loc, options = {})
|
38
|
+
|
39
|
+
with_service_stopped("landscape-server") do
|
40
|
+
expanded_path = File.expand_path(backup_loc)
|
41
|
+
FileUtils.rm_rf "/tmp/landscape_backup"
|
42
|
+
FileUtils.mkdir "/tmp/landscape_backup"
|
43
|
+
safe_system "cd /tmp/landscape_backup && tar xpf \"#{expanded_path}\""
|
44
|
+
|
45
|
+
Dir["/tmp/landscape_backup/*"].each do |top_level|
|
46
|
+
sub_path = top_level.sub /^\/tmp\/landscape_backup/, ""
|
47
|
+
next if EXCLUDE_FILES.any? { |exc| sub_path[exc] }
|
48
|
+
new_location = File.join options[:restore_prefix], sub_path
|
49
|
+
replace new_location, top_level
|
50
|
+
end
|
51
|
+
|
52
|
+
puts "Restoring Postgres"
|
53
|
+
unless options[:no_db]
|
54
|
+
restore_landscape_databases("/tmp/landscape_backup/postgresql_backup")
|
55
|
+
with_service_stopped("postgresql") do
|
56
|
+
replace(POSTGRES_CONFIG,"/tmp/landscape_backup/#{POSTGRES_CONFIG}")
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
puts "Restoration of Landscape configuration completed."
|
61
|
+
|
62
|
+
FileUtils.rm_rf "/tmp/landscape_backup" rescue nil
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
def self.replace(filename_replace,filename)
|
68
|
+
puts "Copying #{filename} to #{File.dirname(filename_replace)}..."
|
69
|
+
FileUtils.cp_r(filename, File.dirname(filename_replace), :preserve => true, :remove_destination => true)
|
70
|
+
end
|
71
|
+
|
72
|
+
|
73
|
+
def self.restore_landscape_databases(restore_location)
|
74
|
+
#clear the databases first
|
75
|
+
Dir["#{restore_location}/*"].each { |database_name|
|
76
|
+
database_name = File.basename(database_name)
|
77
|
+
database_name.slice!(".bak")
|
78
|
+
safe_system("cd /tmp && sudo -u postgres dropdb #{database_name}") rescue nil
|
79
|
+
safe_system("cd /tmp && sudo -u postgres createdb #{database_name}")
|
80
|
+
# psql dbname < infile
|
81
|
+
safe_system("cd /tmp && sudo -u postgres psql #{database_name} < #{restore_location}/#{database_name}.bak")
|
82
|
+
}
|
83
|
+
|
84
|
+
end
|
85
|
+
|
86
|
+
|
87
|
+
end
|
metadata
ADDED
@@ -0,0 +1,125 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: landscape-turner
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.2.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Justin Boisvert
|
9
|
+
autorequire:
|
10
|
+
bindir: exe
|
11
|
+
cert_chain: []
|
12
|
+
date: 2016-02-03 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: trollop
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: bundler
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ~>
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '1.11'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '1.11'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: rake
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ~>
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '10.0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '10.0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: minitest
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
description: A backup tool for the Landscape service that backs up the configuration
|
79
|
+
files and the database related to the service.
|
80
|
+
email:
|
81
|
+
- justin.boisvert@daqri.com
|
82
|
+
executables:
|
83
|
+
- landscape-turner-backup
|
84
|
+
- landscape-turner-restore
|
85
|
+
extensions: []
|
86
|
+
extra_rdoc_files: []
|
87
|
+
files:
|
88
|
+
- Gemfile
|
89
|
+
- LICENSE.txt
|
90
|
+
- README.md
|
91
|
+
- Rakefile
|
92
|
+
- bin/console
|
93
|
+
- bin/setup
|
94
|
+
- exe/landscape-turner-backup
|
95
|
+
- exe/landscape-turner-restore
|
96
|
+
- landscape-turner.gemspec
|
97
|
+
- lib/landscape-turner/backup.rb
|
98
|
+
- lib/landscape-turner/helpers.rb
|
99
|
+
- lib/landscape-turner/restore.rb
|
100
|
+
- lib/landscape-turner/version.rb
|
101
|
+
homepage: http://www.daqri.com
|
102
|
+
licenses: []
|
103
|
+
post_install_message:
|
104
|
+
rdoc_options: []
|
105
|
+
require_paths:
|
106
|
+
- lib
|
107
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
108
|
+
none: false
|
109
|
+
requirements:
|
110
|
+
- - ! '>='
|
111
|
+
- !ruby/object:Gem::Version
|
112
|
+
version: '0'
|
113
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
114
|
+
none: false
|
115
|
+
requirements:
|
116
|
+
- - ! '>='
|
117
|
+
- !ruby/object:Gem::Version
|
118
|
+
version: '0'
|
119
|
+
requirements: []
|
120
|
+
rubyforge_project:
|
121
|
+
rubygems_version: 1.8.23
|
122
|
+
signing_key:
|
123
|
+
specification_version: 3
|
124
|
+
summary: Backup tool for the Landscape service
|
125
|
+
test_files: []
|