knife-ec-backup 1.1.8 → 1.1.9
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/chef/knife/ec_backup.rb +7 -2
- data/lib/chef/knife/ec_key_base.rb +74 -0
- data/lib/chef/knife/ec_key_export.rb +45 -0
- data/lib/chef/knife/ec_key_import.rb +76 -0
- data/lib/chef/knife/ec_restore.rb +31 -6
- data/lib/chef/tsorter.rb +20 -0
- data/lib/knife_ec_backup/version.rb +1 -1
- metadata +49 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2f6ccb75df554513932811d591b998bc003b5e2a
|
4
|
+
data.tar.gz: f483c5827dc422e42a77a1f3c0d38c6afd23ca44
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5faefbd227c50d317b3570ccb88f2c9a0a5e44e7dd5cdca7482b667eafdaf0b779e51c491a83127939da69082c11916df1acf4e48663e80300ce2ede6307dbc8
|
7
|
+
data.tar.gz: a3a8ddadea8cfd3ff190aca59120edf249e59194355e9a97f7fc438c0e692b7bed5cc270ac70735bb246124a0a8679ebde34065f3a4c507ef8af57f6d6c9252f
|
data/lib/chef/knife/ec_backup.rb
CHANGED
@@ -3,7 +3,7 @@ require 'chef/knife'
|
|
3
3
|
class Chef
|
4
4
|
class Knife
|
5
5
|
class EcBackup < Chef::Knife
|
6
|
-
banner "knife ec backup"
|
6
|
+
banner "knife ec backup DIRECTORY"
|
7
7
|
|
8
8
|
option :concurrency,
|
9
9
|
:long => '--concurrency THREADS',
|
@@ -25,6 +25,10 @@ class Chef
|
|
25
25
|
:default => false,
|
26
26
|
:description => "Whether to skip checking the Chef Server version. This will also skip any auto-configured options"
|
27
27
|
|
28
|
+
option :org,
|
29
|
+
:long => '--only-org ORGNAME',
|
30
|
+
:description => "Only back up objects in the named organization (default: all orgs)"
|
31
|
+
|
28
32
|
deps do
|
29
33
|
require 'chef_fs/config'
|
30
34
|
require 'chef_fs/file_system'
|
@@ -140,8 +144,9 @@ class Chef
|
|
140
144
|
# Download organizations
|
141
145
|
ensure_dir("#{dest_dir}/organizations")
|
142
146
|
rest.get_rest('/organizations').each_pair do |name, url|
|
147
|
+
do_org = (config[:org].nil? || config[:org] == name)
|
143
148
|
org = rest.get_rest(url)
|
144
|
-
if org['assigned_at']
|
149
|
+
if org['assigned_at'] and do_org
|
145
150
|
puts "Grabbing organization #{name} ..."
|
146
151
|
ensure_dir("#{dest_dir}/organizations/#{name}")
|
147
152
|
download_org(dest_dir, webui_key, name)
|
@@ -0,0 +1,74 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Steven Danna (<steve@getchef.com>)
|
3
|
+
# Copyright:: Copyright (c) 2014 Chef Software, Inc.
|
4
|
+
# License:: Apache License, Version 2.0
|
5
|
+
#
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
+
# you may not use this file except in compliance with the License.
|
8
|
+
# You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
# See the License for the specific language governing permissions and
|
16
|
+
# limitations under the License.
|
17
|
+
#
|
18
|
+
|
19
|
+
require 'chef/knife'
|
20
|
+
|
21
|
+
class Chef
|
22
|
+
class Knife
|
23
|
+
module EcKeyBase
|
24
|
+
|
25
|
+
def self.included(includer)
|
26
|
+
includer.class_eval do
|
27
|
+
|
28
|
+
deps do
|
29
|
+
require 'sequel'
|
30
|
+
require 'json'
|
31
|
+
end
|
32
|
+
|
33
|
+
option :sql_host,
|
34
|
+
:long => '--sql-host HOSTNAME',
|
35
|
+
:description => 'Postgresql database hostname (default: localhost)',
|
36
|
+
:default => "localhost"
|
37
|
+
|
38
|
+
option :sql_port,
|
39
|
+
:long => '--sql-port PORT',
|
40
|
+
:description => 'Postgresql database port (default: 5432)',
|
41
|
+
:default => 5432
|
42
|
+
|
43
|
+
option :sql_user,
|
44
|
+
:long => "--sql-user USERNAME",
|
45
|
+
:description => 'User used to connect to the postgresql database.'
|
46
|
+
|
47
|
+
option :sql_password,
|
48
|
+
:long => "--sql-password PASSWORD",
|
49
|
+
:description => 'Password used to connect to the postgresql database'
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def db
|
54
|
+
@db ||= begin
|
55
|
+
server_string = "#{config[:sql_user]}:#{config[:sql_password]}@#{config[:sql_host]}:#{config[:sql_port]}/opscode_chef"
|
56
|
+
Sequel.connect("postgres://#{server_string}")
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# Loads SQL user and password from running config if not passed
|
61
|
+
# as a command line option
|
62
|
+
def load_config_from_file!
|
63
|
+
if ! File.exists?("/etc/opscode/chef-server-running.json")
|
64
|
+
ui.fatal "SQL User or Password not provided as option and running config cannot be found!"
|
65
|
+
exit 1
|
66
|
+
else
|
67
|
+
running_config ||= JSON.parse(File.read("/etc/opscode/chef-server-running.json"))
|
68
|
+
config[:sql_user] ||= running_config['private_chef']['postgresql']['sql_user']
|
69
|
+
config[:sql_password] ||= running_config['private_chef']['postgresql']['sql_password']
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Steven Danna (<steve@getchef.com>)
|
3
|
+
# Copyright:: Copyright (c) 2014 Chef Software, Inc.
|
4
|
+
# License:: Apache License, Version 2.0
|
5
|
+
#
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
+
# you may not use this file except in compliance with the License.
|
8
|
+
# You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
# See the License for the specific language governing permissions and
|
16
|
+
# limitations under the License.
|
17
|
+
#
|
18
|
+
|
19
|
+
require 'chef/knife'
|
20
|
+
require 'chef/knife/ec_key_base'
|
21
|
+
|
22
|
+
class Chef
|
23
|
+
class Knife
|
24
|
+
class EcKeyExport < Chef::Knife
|
25
|
+
|
26
|
+
include Knife::EcKeyBase
|
27
|
+
|
28
|
+
banner "knife ec key export [PATH]"
|
29
|
+
|
30
|
+
def run
|
31
|
+
if config[:sql_user].nil? || config[:sql_password].nil?
|
32
|
+
load_config_from_file!
|
33
|
+
end
|
34
|
+
|
35
|
+
path = @name_args[0] || "key_dump.json"
|
36
|
+
export(path)
|
37
|
+
end
|
38
|
+
|
39
|
+
def export(path)
|
40
|
+
users = db.select(:username, :public_key, :pubkey_version, :hashed_password, :salt, :hash_type).from(:users)
|
41
|
+
File.open(path, 'w') { |file| file.write(users.all.to_json) }
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Steven Danna (<steve@getchef.com>)
|
3
|
+
# Copyright:: Copyright (c) 2014 Chef Software, Inc.
|
4
|
+
# License:: Apache License, Version 2.0
|
5
|
+
#
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
+
# you may not use this file except in compliance with the License.
|
8
|
+
# You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
# See the License for the specific language governing permissions and
|
16
|
+
# limitations under the License.
|
17
|
+
#
|
18
|
+
|
19
|
+
require 'chef/knife'
|
20
|
+
require 'chef/knife/ec_key_base'
|
21
|
+
|
22
|
+
class Chef
|
23
|
+
class Knife
|
24
|
+
class EcKeyImport < Chef::Knife
|
25
|
+
|
26
|
+
include Knife::EcKeyBase
|
27
|
+
|
28
|
+
banner "knife ec key import [PATH]"
|
29
|
+
|
30
|
+
option :skip_pivotal,
|
31
|
+
:long => "--[no-]skip-pivotal",
|
32
|
+
:default => true,
|
33
|
+
:boolean => true,
|
34
|
+
:description => "Upload pivotal key. By default the pivotal key is not uploaded."
|
35
|
+
|
36
|
+
def run
|
37
|
+
if config[:sql_user].nil? || config[:sql_password].nil?
|
38
|
+
load_config_from_file!
|
39
|
+
end
|
40
|
+
|
41
|
+
path = @name_args[0] || "key_dump.json"
|
42
|
+
import(path)
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
def import(path)
|
47
|
+
key_data = JSON.parse(File.read(path))
|
48
|
+
key_data.each do |d|
|
49
|
+
username = d['username']
|
50
|
+
key = d['public_key']
|
51
|
+
version = d['pubkey_version']
|
52
|
+
hashed_password = d['hashed_password']
|
53
|
+
hash_type = d['hash_type']
|
54
|
+
salt = d['salt']
|
55
|
+
|
56
|
+
if username == 'pivotal' && config[:skip_pivotal]
|
57
|
+
ui.warn "Skipping pivotal user."
|
58
|
+
next
|
59
|
+
end
|
60
|
+
|
61
|
+
ui.msg "Updating key for #{username}"
|
62
|
+
users_to_update = db[:users].where(:username => username)
|
63
|
+
if users_to_update.count != 1
|
64
|
+
ui.warn "Wrong number of users to update for #{username}. Skipping"
|
65
|
+
else
|
66
|
+
users_to_update.update(:public_key => key,
|
67
|
+
:pubkey_version => version,
|
68
|
+
:salt => salt,
|
69
|
+
:hashed_password => hashed_password,
|
70
|
+
:hash_type => hash_type)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -3,7 +3,7 @@ require 'chef/knife'
|
|
3
3
|
class Chef
|
4
4
|
class Knife
|
5
5
|
class EcRestore < Chef::Knife
|
6
|
-
banner "knife ec restore"
|
6
|
+
banner "knife ec restore DIRECTORY"
|
7
7
|
|
8
8
|
option :concurrency,
|
9
9
|
:long => '--concurrency THREADS',
|
@@ -40,6 +40,7 @@ class Chef
|
|
40
40
|
require 'chef_fs/data_handler/acl_data_handler'
|
41
41
|
require 'securerandom'
|
42
42
|
require 'chef_fs/parallelizer'
|
43
|
+
require 'chef/tsorter'
|
43
44
|
end
|
44
45
|
|
45
46
|
def configure_chef
|
@@ -64,8 +65,8 @@ class Chef
|
|
64
65
|
ui.error("Username not configured as pivotal and /etc/opscode/pivotal.pem does not exist. It is recommended that you run this plugin from your Chef server.")
|
65
66
|
exit 1
|
66
67
|
end
|
67
|
-
node_name = 'pivotal'
|
68
|
-
client_key = '/etc/opscode/pivotal.pem'
|
68
|
+
Chef::Config.node_name = 'pivotal'
|
69
|
+
Chef::Config.client_key = '/etc/opscode/pivotal.pem'
|
69
70
|
end
|
70
71
|
|
71
72
|
#Check for WebUI Key
|
@@ -268,9 +269,14 @@ class Chef
|
|
268
269
|
puts "Restoring the rest of the org"
|
269
270
|
chef_fs_config = ::ChefFS::Config.new
|
270
271
|
top_level_paths = chef_fs_config.local_fs.children.select { |entry| entry.name != 'acls' && entry.name != 'groups' }.map { |entry| entry.path }
|
271
|
-
|
272
|
+
|
273
|
+
# Topologically sort groups for upload
|
274
|
+
unsorted_groups = ::ChefFS::FileSystem.list(chef_fs_config.local_fs, ::ChefFS::FilePattern.new('/groups/*')).select { |entry| entry.name != 'billing-admins.json' }.map { |entry| JSON.parse(entry.read) }
|
275
|
+
group_paths = sort_groups_for_upload(unsorted_groups).map { |group_name| "/groups/#{group_name}.json" }
|
276
|
+
|
272
277
|
group_acl_paths = ::ChefFS::FileSystem.list(chef_fs_config.local_fs, ::ChefFS::FilePattern.new('/acls/groups/*')).select { |entry| entry.name != 'billing-admins.json' }.map { |entry| entry.path }
|
273
|
-
|
278
|
+
acl_paths = ::ChefFS::FileSystem.list(chef_fs_config.local_fs, ::ChefFS::FilePattern.new('/acls/*')).select { |entry| entry.name != 'groups' }.map { |entry| entry.path }
|
279
|
+
|
274
280
|
(top_level_paths + group_paths + group_acl_paths + acl_paths).each do |path|
|
275
281
|
::ChefFS::FileSystem.copy_to(::ChefFS::FilePattern.new(path), chef_fs_config.local_fs, chef_fs_config.chef_fs, nil, config, ui, proc { |entry| chef_fs_config.format_path(entry) })
|
276
282
|
end
|
@@ -279,7 +285,7 @@ class Chef
|
|
279
285
|
Chef::Config[:client_key] = old_config['client_key']
|
280
286
|
Chef::Config.custom_http_headers = {}
|
281
287
|
['admins', 'billing-admins'].each do |group|
|
282
|
-
restore_group(::ChefFS::Config.new, group
|
288
|
+
restore_group(::ChefFS::Config.new, group)
|
283
289
|
end
|
284
290
|
ensure
|
285
291
|
CONFIG_VARS.each do |key|
|
@@ -288,6 +294,25 @@ class Chef
|
|
288
294
|
end
|
289
295
|
end
|
290
296
|
|
297
|
+
# Takes an array of group objects
|
298
|
+
# and topologically sorts them
|
299
|
+
def sort_groups_for_upload(groups)
|
300
|
+
Chef::Tsorter.new(group_array_to_sortable_hash(groups)).tsort
|
301
|
+
end
|
302
|
+
|
303
|
+
def group_array_to_sortable_hash(groups)
|
304
|
+
ret = {}
|
305
|
+
groups.each do |group|
|
306
|
+
name = group["name"]
|
307
|
+
ret[name] = if group.key?("groups")
|
308
|
+
group["groups"]
|
309
|
+
else
|
310
|
+
[]
|
311
|
+
end
|
312
|
+
end
|
313
|
+
ret
|
314
|
+
end
|
315
|
+
|
291
316
|
def restore_group(chef_fs_config, group_name, includes = {:users => true, :clients => true})
|
292
317
|
includes[:users] = true unless includes.key? :users
|
293
318
|
includes[:clients] = true unless includes.key? :clients
|
data/lib/chef/tsorter.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'tsort'
|
2
|
+
|
3
|
+
class Chef
|
4
|
+
class Tsorter
|
5
|
+
|
6
|
+
include TSort
|
7
|
+
|
8
|
+
def initialize(data)
|
9
|
+
@data = data
|
10
|
+
end
|
11
|
+
|
12
|
+
def tsort_each_node(&block)
|
13
|
+
@data.each_key(&block)
|
14
|
+
end
|
15
|
+
|
16
|
+
def tsort_each_child(node, &block)
|
17
|
+
@data.fetch(node).each(&block)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
metadata
CHANGED
@@ -1,15 +1,57 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: knife-ec-backup
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.1.
|
4
|
+
version: 1.1.9
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- John Keiser
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-05-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: knife-essentials
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: sequel
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: pg
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
13
55
|
- !ruby/object:Gem::Dependency
|
14
56
|
name: rspec
|
15
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -50,7 +92,11 @@ files:
|
|
50
92
|
- README.md
|
51
93
|
- Rakefile
|
52
94
|
- lib/chef/knife/ec_backup.rb
|
95
|
+
- lib/chef/knife/ec_key_base.rb
|
96
|
+
- lib/chef/knife/ec_key_export.rb
|
97
|
+
- lib/chef/knife/ec_key_import.rb
|
53
98
|
- lib/chef/knife/ec_restore.rb
|
99
|
+
- lib/chef/tsorter.rb
|
54
100
|
- lib/knife_ec_backup/version.rb
|
55
101
|
homepage: http://www.opscode.com
|
56
102
|
licenses:
|
@@ -72,7 +118,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
72
118
|
version: '0'
|
73
119
|
requirements: []
|
74
120
|
rubyforge_project:
|
75
|
-
rubygems_version: 2.
|
121
|
+
rubygems_version: 2.0.14
|
76
122
|
signing_key:
|
77
123
|
specification_version: 4
|
78
124
|
summary: Backup and Restore of Enterprise Chef
|