knife-ec-backup 2.0.0.beta.4 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d766acc26907709ef94b95f41410a3c77f2fe1fa
4
- data.tar.gz: 2fddbc5353225e9b6b4f988f872faa396bb4dfe9
3
+ metadata.gz: f8f08431a9c4bb9de895e7f1de514e586603cf00
4
+ data.tar.gz: bcc07b67d433964eb6b8b080650110b98c7291c2
5
5
  SHA512:
6
- metadata.gz: 80c0598f66fb11f5eb65de808e6e4595c78209fe42b42041ad8f31c022465741f093b223d35864d88383c8be8c157aaf3f850a8648a4d82db3d57ec753e6df33
7
- data.tar.gz: cdc909787dab84ccfe783653e47f8550127a3ca22b6eacfe5320f5205132730a23029a66a430abc6c67503d4ec277044ccb5e52cc65fadc4289c5f54898616fb
6
+ metadata.gz: 964129af4f8e76e3d339f4a10e2d682fbc864d1e2799b6274a2d4fb4f7b4ad0cb2d31deda74fa11f2d62033b60f0aa170e397c44d07bea56294b296abbe1887f
7
+ data.tar.gz: f9de155880bf15cac8afafdcfd81365e8c2764b15065faa501ee92cb7c10772c6259e24434701dddcbe24404c74414c964b4308ddc43fce73ea37f1e52cb2f20
data/README.md CHANGED
@@ -13,13 +13,21 @@ tool.
13
13
 
14
14
  # Requirements
15
15
 
16
- This knife plugin requires Chef 11.8+.
16
+ This knife plugin requires Chef Client 11.8+.
17
17
 
18
18
  ## Chef 10
19
19
 
20
20
  Users who are still using Chef 10 can use the most recent 1.x version
21
21
  of this gem. Version 1.x additionally depends on knife-essentials.
22
22
 
23
+ ## Server Support
24
+
25
+ This plugin currently supports Enterprise Chef 11 and Chef Server 12.
26
+ Support for the beta key rotation features is provided via the
27
+ `--with-keys-sql` flag, but users of this feature should note that
28
+ this may change once the Chef Server supports an API-based export of
29
+ the key data.
30
+
23
31
  # Installation
24
32
 
25
33
  ## Chef Server Install (Recommended)
@@ -86,6 +94,13 @@ The following options are supported across all subcommands:
86
94
  Server. This is required to correctly handle user passwords and
87
95
  to ensure user-specific association groups are not duplicated.
88
96
 
97
+ * `--with-key-sql`: Whether to backup/restore key data directly
98
+ from the database. This requires access to the listening
99
+ postgresql port on the Chef Server. This is required to correctly
100
+ handle keys in Chef Servers with multikey support. This option
101
+ will only work on `restore` if it was also used during the
102
+ `backup`.
103
+
89
104
  * `--skip-useracl`:
90
105
  Skip download/restore of the user ACLs. User ACLs are the
91
106
  permissions that actors have *on other global users*. These are
@@ -187,6 +202,13 @@ Private Chef server. DEST_DIR should be a backup directory created by
187
202
  duplicated. This option will only work on `restore` if it was also
188
203
  used during the `backup`.
189
204
 
205
+ * `--with-key-sql`: Whether to backup/restore key data directly
206
+ from the database. This requires access to the listening
207
+ postgresql port on the Chef Server. This is required to correctly
208
+ handle keys in Chef Servers with multikey support. This option
209
+ will only work on `restore` if it was also used during the
210
+ `backup`.
211
+
190
212
  * `--skip-useracl`:
191
213
  Skip download/restore of the user ACLs. User ACLs are the
192
214
  permissions that actors have *on other global users*. These are
@@ -217,6 +239,9 @@ Please note, most user should use `knife ec restore` with the
217
239
 
218
240
  # Known Bugs
219
241
 
242
+ - knife-ec-backup cannot be installed in the embedded gemset of Chef
243
+ Server 12. This will be resolved in a future Chef Server release.
244
+
220
245
  - `knife ec restore` can fail to restore cookbooks, failing with an
221
246
  internal server error. A common cause of this problem is a
222
247
  concurrency bug in Chef Server. Setting `--concurrency 1` can often
@@ -33,8 +33,8 @@ class Chef
33
33
  end
34
34
  end
35
35
 
36
- if config[:with_user_sql]
37
- export_users_from_sql
36
+ if config[:with_user_sql] || config[:with_key_sql]
37
+ export_from_sql
38
38
  end
39
39
 
40
40
  ensure_dir("#{dest_dir}/organizations")
@@ -86,15 +86,17 @@ class Chef
86
86
  end
87
87
  end
88
88
 
89
- def export_users_from_sql
89
+ def export_from_sql
90
90
  require 'chef/knife/ec_key_export'
91
91
  Chef::Knife::EcKeyExport.deps
92
92
  k = Chef::Knife::EcKeyExport.new
93
- k.name_args = ["#{dest_dir}/key_dump.json"]
93
+ k.name_args = ["#{dest_dir}/key_dump.json", "#{dest_dir}/key_table_dump.json"]
94
94
  k.config[:sql_host] = config[:sql_host]
95
95
  k.config[:sql_port] = config[:sql_port]
96
96
  k.config[:sql_user] = config[:sql_user]
97
97
  k.config[:sql_password] = config[:sql_password]
98
+ k.config[:skip_users_table] = !config[:with_user_sql]
99
+ k.config[:skip_keys_table] = !config[:with_key_sql]
98
100
  k.run
99
101
  end
100
102
 
@@ -72,6 +72,11 @@ class Chef
72
72
  option :with_user_sql,
73
73
  :long => '--with-user-sql',
74
74
  :description => 'Try direct data base access for user export/import. Required to properly handle passwords, keys, and USAGs'
75
+
76
+ option :with_key_sql,
77
+ :long => '--with-key-sql',
78
+ :description => 'Try direct data base access for key table export/import. Required to properly handle rotated keys.'
79
+
75
80
  end
76
81
 
77
82
  attr_accessor :dest_dir
@@ -47,6 +47,16 @@ class Chef
47
47
  option :sql_password,
48
48
  :long => "--sql-password PASSWORD",
49
49
  :description => 'Password used to connect to the postgresql database'
50
+
51
+ option :skip_keys_table,
52
+ :long => "--skip-keys-table",
53
+ :description => "Skip Chef 12-only keys table",
54
+ :default => false
55
+
56
+ option :skip_users_table,
57
+ :long => "--skip-users-table",
58
+ :description => "Skip users table",
59
+ :default => false
50
60
  end
51
61
  end
52
62
 
@@ -54,7 +64,7 @@ class Chef
54
64
  @db ||= begin
55
65
  require 'sequel'
56
66
  server_string = "#{config[:sql_user]}:#{config[:sql_password]}@#{config[:sql_host]}:#{config[:sql_port]}/opscode_chef"
57
- ::Sequel.connect("postgres://#{server_string}")
67
+ ::Sequel.connect("postgres://#{server_string}", :convert_infinite_timestamps => :string)
58
68
  end
59
69
  end
60
70
 
@@ -25,20 +25,41 @@ class Chef
25
25
 
26
26
  include Knife::EcKeyBase
27
27
 
28
- banner "knife ec key export [PATH]"
28
+ banner "knife ec key export [USER_DATA_PATH] [KEY_DATA_PATH]"
29
29
 
30
30
  def run
31
31
  if config[:sql_user].nil? || config[:sql_password].nil?
32
32
  load_config_from_file!
33
33
  end
34
34
 
35
- path = @name_args[0] || "key_dump.json"
36
- export(path)
35
+ # user_data_path defaults to key_dump.json to support
36
+ # older knife-ec-backup exports
37
+ user_data_path = @name_args[0] || "key_dump.json"
38
+ key_data_path = @name_args[1] || "key_table_dump.json"
39
+
40
+ export(:users, user_data_path) unless config[:skip_users_table]
41
+
42
+ begin
43
+ export_keys(key_data_path) unless config[:skip_keys_table]
44
+ rescue Sequel::DatabaseError => e
45
+ if e.message =~ /^PG::UndefinedTable/
46
+ ui.error "Keys table not found. The keys table only exists on Chef Server 12."
47
+ ui.error "Chef Server 11 users should use the --skip-keys-table option to avoid this error."
48
+ exit 1
49
+ else
50
+ raise
51
+ end
52
+ end
53
+ end
54
+
55
+ def export_keys(path)
56
+ data = db.fetch('SELECT keys_by_name.*, orgs.name AS "org_name" FROM keys_by_name LEFT JOIN orgs ON keys_by_name.org_id=orgs.id')
57
+ File.open(path, 'w') { |file| file.write(data.all.to_json) }
37
58
  end
38
59
 
39
- def export(path)
40
- users = db.select.from(:users)
41
- File.open(path, 'w') { |file| file.write(users.all.to_json) }
60
+ def export(table, path)
61
+ data = db.select.from(table)
62
+ File.open(path, 'w') { |file| file.write(data.all.to_json) }
42
63
  end
43
64
  end
44
65
  end
@@ -18,6 +18,7 @@
18
18
 
19
19
  require 'chef/knife'
20
20
  require 'chef/knife/ec_key_base'
21
+ require 'chef/org_id_cache'
21
22
 
22
23
  class Chef
23
24
  class Knife
@@ -25,7 +26,7 @@ class Chef
25
26
 
26
27
  include Knife::EcKeyBase
27
28
 
28
- banner "knife ec key import [PATH]"
29
+ banner "knife ec key import [USER_DATA_PATH] [KEY_DATA_PATH]"
29
30
 
30
31
  option :skip_pivotal,
31
32
  :long => "--[no-]skip-pivotal",
@@ -39,17 +40,130 @@ class Chef
39
40
  :boolean => true,
40
41
  :description => "Upload user ids."
41
42
 
43
+ option :users_only,
44
+ :long => "--users-only",
45
+ :default => false,
46
+ :description => "Only update users (skip client key data)"
47
+
48
+ option :clients_only,
49
+ :log => "--clients-only",
50
+ :default => false,
51
+ :description => "Only update client key data. Implies --skip-users-table"
52
+
42
53
  def run
43
54
  if config[:sql_user].nil? || config[:sql_password].nil?
44
55
  load_config_from_file!
45
56
  end
46
57
 
47
- path = @name_args[0] || "key_dump.json"
48
- import(path)
58
+ @org_id_cache = Chef::OrgIdCache.new(db)
59
+
60
+ # user_data_path defaults to key_dump.json to support
61
+ # older knife-ec-backup exports
62
+ user_data_path = @name_args[0] || "key_dump.json"
63
+ key_data_path = @name_args[1] || "key_table_dump.json"
64
+ import_user_data(user_data_path) unless (config[:skip_users_table] || config[:clients_only])
65
+ import_key_data(key_data_path) unless config[:skip_keys_table]
49
66
  end
50
67
 
68
+ def import_key_data(path)
69
+ key_data = JSON.parse(File.read(path))
70
+ key_data.each do |d|
71
+ case d['type']
72
+ when 'client'
73
+ next if config[:users_only]
74
+ insert_key_data_for_client(d)
75
+ when 'user'
76
+ next if config[:clients_only]
77
+ insert_key_data_for_user(d)
78
+ else
79
+ ui.warn "Unkown actor type #{d['type']} for #{d['name']}"
80
+ next
81
+ end
82
+ end
83
+ end
84
+
85
+ # If a given key_name already exists for the client, update it,
86
+ # otherwise insert a new key into the key table.
87
+ #
88
+ # Unlike users, we never want to keep the internal ID from the
89
+ # backup.
90
+ #
91
+ # The org_id is likely different than that stored in the backup.
92
+ # We query the new org_id based on org_name, caching it to avoid
93
+ # multiple lookups in a large org.
94
+ def insert_key_data_for_client(d)
95
+ ui.msg "Updating key data for client[#{d['name']}]"
96
+
97
+ org_id = @org_id_cache.fetch(d['org_name'])
98
+ if org_id.nil?
99
+ ui.warn "Could not find organization for client[#{d['name']}], skipping."
100
+ ui.warn "Organizations much be restored before key data can be imported."
101
+ return
102
+ end
103
+
104
+ existing_client = db[:clients].where(:org_id => org_id, :name => d['name']).first
105
+ if existing_client.nil?
106
+ ui.warn "Did not find existing client record for #{d['name']}, skipping."
107
+ ui.warn "Client records must be restored before key data can be imported."
108
+ return
109
+ end
110
+
111
+ new_id = existing_client[:id]
112
+ Chef::Log.debug("Found client id for #{d['name']}: #{new_id}")
113
+ upsert_key_record(key_record_for_db(d, new_id))
114
+ end
115
+
116
+ # Insert key data for each user record
117
+ #
118
+ # When :skip_id's is set, we are not using the ids from the
119
+ # backup. In this case, look up the user id in the users table.
120
+ #
121
+ # When :skip_id's is not set, we are using the ids from the
122
+ # backup. The update_key trigger on the users table should
123
+ # ensure that the user ids have already been replaced and should
124
+ # match what we have in the backup.
125
+ def insert_key_data_for_user(d)
126
+ if d['name'] == 'pivotal' && config[:skip_pivotal]
127
+ ui.warn "Skipping pivotal user."
128
+ return
129
+ end
130
+ ui.msg "Updating key data for user[#{d['name']}]"
131
+ new_id = if config[:skip_ids]
132
+ db[:users].where(:username => d['name']).first[:id]
133
+ else
134
+ d['id']
135
+ end
136
+ Chef::Log.debug("Found user id for #{d['name']}: #{new_id}")
137
+ upsert_key_record(key_record_for_db(d, new_id))
138
+ end
139
+
140
+ def upsert_key_record(r)
141
+ key_records_to_update = db[:keys].where(:key_name => r[:key_name], :id => r[:id])
142
+ case key_records_to_update.count
143
+ when 0
144
+ Chef::Log.debug("No existing records found for #{r[:key_name]}, #{r[:id]}")
145
+ db[:keys].insert(r)
146
+ when 1
147
+ Chef::Log.debug("1 record found for #{r[:key_name]}, #{r[:id]}")
148
+ key_records_to_update.update(r)
149
+ else
150
+ ui.warn "Found too many records for actor id #{r[:id]} key #{d[:key_name]}"
151
+ return
152
+ end
153
+ end
154
+
155
+ def key_record_for_db(d, new_id=nil)
156
+ {
157
+ :id => new_id || d['id'],
158
+ :key_name => d['key_name'],
159
+ :public_key => d['public_key'],
160
+ :key_version => d['key_version'],
161
+ :created_at => Time.now,
162
+ :expires_at => d['expires_at']
163
+ }
164
+ end
51
165
 
52
- def import(path)
166
+ def import_user_data(path)
53
167
  key_data = JSON.parse(File.read(path))
54
168
  key_data.each do |d|
55
169
  if d['username'] == 'pivotal' && config[:skip_pivotal]
@@ -57,7 +171,7 @@ class Chef
57
171
  next
58
172
  end
59
173
 
60
- ui.msg "Updating key for #{d['username']}"
174
+ ui.msg "Updating user record for #{d['username']}"
61
175
  users_to_update = db[:users].where(:username => d['username'])
62
176
 
63
177
  if users_to_update.count != 1
@@ -44,12 +44,15 @@ class Chef
44
44
  restore_user_sql if config[:with_user_sql]
45
45
 
46
46
  for_each_organization do |orgname|
47
+ ui.msg "Restoring organization[#{orgname}]"
47
48
  create_organization(orgname)
48
49
  restore_open_invitations(orgname)
49
50
  add_users_to_org(orgname)
50
51
  upload_org_data(orgname)
51
52
  end
52
53
 
54
+ restore_key_sql if config[:with_key_sql]
55
+
53
56
  if config[:skip_useracl]
54
57
  ui.warn("Skipping user ACL update. To update user ACLs, remove --skip-useracl or upgrade your Enterprise Chef Server.")
55
58
  else
@@ -98,7 +101,7 @@ class Chef
98
101
  end
99
102
 
100
103
  def restore_user_acls
101
- ui.msg "Restoring user ACLs ..."
104
+ ui.msg "Restoring user ACLs"
102
105
  for_each_user do |name|
103
106
  user_acl = JSONCompat.from_json(File.read("#{dest_dir}/user_acls/#{name}.json"))
104
107
  put_acl(user_acl_rest, "users/#{name}/_acl", user_acl)
@@ -126,7 +129,7 @@ class Chef
126
129
  end
127
130
 
128
131
  def restore_users
129
- ui.msg "Restoring users ..."
132
+ ui.msg "Restoring users"
130
133
  for_each_user do |name|
131
134
  user = JSONCompat.from_json(File.read("#{dest_dir}/users/#{name}.json"))
132
135
  begin
@@ -144,16 +147,35 @@ class Chef
144
147
  end
145
148
  end
146
149
 
150
+ def ec_key_import
151
+ @ec_key_import ||= begin
152
+ require 'chef/knife/ec_key_import'
153
+ k = Chef::Knife::EcKeyImport.new
154
+ k.name_args = ["#{dest_dir}/key_dump.json", "#{dest_dir}/key_table_dump.json"]
155
+ k.config[:skip_pivotal] = true
156
+ k.config[:skip_ids] = false
157
+ k.config[:sql_host] = config[:sql_host]
158
+ k.config[:sql_port] = config[:sql_port]
159
+ k.config[:sql_user] = config[:sql_user]
160
+ k.config[:sql_password] = config[:sql_password]
161
+ k
162
+ end
163
+ end
164
+
147
165
  def restore_user_sql
148
- require 'chef/knife/ec_key_import'
149
- k = Chef::Knife::EcKeyImport.new
150
- k.name_args = ["#{dest_dir}/key_dump.json"]
151
- k.config[:skip_pivotal] = true
152
- k.config[:skip_ids] = false
153
- k.config[:sql_host] = config[:sql_host]
154
- k.config[:sql_port] = config[:sql_port]
155
- k.config[:sql_user] = config[:sql_user]
156
- k.config[:sql_password] = config[:sql_password]
166
+ k = ec_key_import
167
+ k.config[:skip_users_table] = false
168
+ k.config[:skip_keys_table] = false
169
+ k.config[:users_only] = true
170
+ k.run
171
+ end
172
+
173
+ def restore_key_sql
174
+ k = ec_key_import
175
+ k.config[:skip_users_table] = true
176
+ k.config[:skip_keys_table] = false
177
+ k.config[:users_only] = false
178
+ k.config[:clients_only] = true
157
179
  k.run
158
180
  end
159
181
 
@@ -172,7 +194,7 @@ class Chef
172
194
  Chef::Config.chef_server_url = "#{server.root_url}/organizations/#{name}"
173
195
 
174
196
  # Upload the admins group and billing-admins acls
175
- ui.msg "Restoring the org admin data"
197
+ ui.msg "Restoring org admin data"
176
198
  chef_fs_config = Chef::ChefFS::Config.new
177
199
 
178
200
  # Handle Admins and Billing Admins seperately
@@ -215,7 +237,13 @@ class Chef
215
237
  group_acl_paths = Chef::ChefFS::FileSystem.list(chef_fs_config.local_fs, Chef::ChefFS::FilePattern.new('/acls/groups/*')).select { |entry| entry.name != 'billing-admins.json' }.map { |entry| entry.path }
216
238
  acl_paths = Chef::ChefFS::FileSystem.list(chef_fs_config.local_fs, Chef::ChefFS::FilePattern.new('/acls/*')).select { |entry| entry.name != 'groups' }.map { |entry| entry.path }
217
239
 
218
- (top_level_paths + group_paths + group_acl_paths + acl_paths).each do |path|
240
+
241
+ # Store organization data in a particular order:
242
+ # - clients must be uploaded before groups (in top_level_paths)
243
+ # - groups must be uploaded before any acl's
244
+ # - groups must be uploaded twice to account for Chef Server versions that don't
245
+ # accept group members on POST
246
+ (top_level_paths + group_paths*2 + group_acl_paths + acl_paths).each do |path|
219
247
  Chef::ChefFS::FileSystem.copy_to(Chef::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) })
220
248
  end
221
249
 
@@ -0,0 +1,50 @@
1
+ #
2
+ # Author:: Steven Danna (<steve@chef.io>)
3
+ # Copyright:: Copyright (c) 2015 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
+ class Chef
20
+ class OrgIdCache
21
+ NO_ORG = "not here"
22
+
23
+ attr_accessor :db, :cache
24
+ def initialize(db)
25
+ @db = db
26
+ @cache = {}
27
+ end
28
+
29
+ def fetch(org_name)
30
+ if cache.key?(org_name) && cache[org_name] != NO_ORG
31
+ cache[org_name]
32
+ elsif cache.key?(org_name) && cache[org_name] == NO_ORG
33
+ nil
34
+ else
35
+ r = db.select(:id).from(:orgs).where(:name => org_name).first
36
+ if r.nil?
37
+ store(org_name, NO_ORG)
38
+ nil
39
+ else
40
+ store(org_name, r[:id])
41
+ r[:id]
42
+ end
43
+ end
44
+ end
45
+
46
+ def store(org_name, org_guid)
47
+ cache[org_name] = org_guid
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,45 @@
1
+ #
2
+ # Author:: Steven Danna (<steve@chef.io>)
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
+ class OrgIdCache
20
+ class NoSuchOrg < RuntimeError; end
21
+
22
+ attr_accesor :db, :cache
23
+ def initialize(db)
24
+ @db = db
25
+ @cache = {}
26
+ end
27
+
28
+ def fetch(org_name)
29
+ if cache.key?(org_name)
30
+ cache[org_name]
31
+ else
32
+ r = db.get(:id).from(:orgs).where(:org_name => org_name)
33
+ if r.nil?
34
+ raise NoSuchOrg
35
+ else
36
+ store(org_name, r[:id])
37
+ r[:id]
38
+ end
39
+ end
40
+ end
41
+
42
+ def store(org_name, org_guid)
43
+ cache[org_name] = org_guid
44
+ end
45
+ end
@@ -1,3 +1,3 @@
1
1
  module KnifeECBackup
2
- VERSION = '2.0.0.beta.4'
2
+ VERSION = '2.0.0'
3
3
  end
@@ -1,2 +1,106 @@
1
1
  require File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "spec_helper"))
2
2
  require 'chef/knife/ec_key_export'
3
+ require 'sequel'
4
+ require 'json'
5
+ require 'securerandom'
6
+ require 'fakefs/spec_helpers'
7
+
8
+ def user_record(name)
9
+ { "id" => SecureRandom.uuid,
10
+ "authz_id" => SecureRandom.uuid,
11
+ "username" => name,
12
+ "email" => "#{name}@example.com",
13
+ "pubkey_version" => 0,
14
+ "public_key" => "BEGIN RSA PUBLIC KEY",
15
+ "serialized_object" => "{ \"a string\" => \"of JSONNNN\"}",
16
+ "last_updated_by" => "a time",
17
+ "created_at" => "a time",
18
+ "updated_at" => "a time",
19
+ "external_authentication_uid" => nil,
20
+ "recovery_authentication_enabled" => false,
21
+ "admin" => false,
22
+ "hashed_password" => "alkdsj5834751934",
23
+ "salt" => "01943891jgfkjf",
24
+ "hash_type" => "not good 1.0" }
25
+ end
26
+
27
+ def key_record(name, type, key_name)
28
+ {
29
+ "id" => SecureRandom.uuid,
30
+ "org_id" => SecureRandom.uuid,
31
+ "name" => name,
32
+ "authz_id" => SecureRandom.uuid,
33
+ "type" => type.to_s,
34
+ "key_name" => key_name,
35
+ "public_key" => "BEGIN RSA PUBLIC KEY",
36
+ "key_version" => 0,
37
+ "expires_at" => "a time"
38
+ }
39
+ end
40
+
41
+ describe Chef::Knife::EcKeyExport do
42
+ include FakeFS::SpecHelpers
43
+ let(:users_table) do
44
+ [ user_record("jane"),
45
+ user_record("bob") ]
46
+ end
47
+
48
+ let(:keys_by_name_table) do
49
+ [ key_record("bob", :user, "default"),
50
+ key_record("jane", :user, "default"),
51
+ key_record("rabbit", :client, "default") ]
52
+ end
53
+
54
+ let(:db) do
55
+ # This seem to be the way to vary fetched data on output
56
+ # See https://groups.google.com/forum/#!topic/sequel-talk/NZuxcoXN30M
57
+ output = Proc.new do |query|
58
+ case query
59
+ when /SELECT.*users/ then users_table
60
+ when /SELECT.*keys_by_name/ then keys_by_name_table
61
+ end
62
+ end
63
+ d = Sequel.mock(:fetch => output)
64
+ allow(Sequel).to receive(:connect).and_return(d)
65
+ d
66
+ end
67
+
68
+ let(:knife) do
69
+ Chef::Knife::EcKeyExport.deps
70
+ k = Chef::Knife::EcKeyExport.new
71
+ k.config[:sql_user] = "opscode_chef"
72
+ k.config[:sql_password] = "apassword"
73
+ k.config[:sql_host] = "localhost"
74
+ k.config[:sql_port] = 5432
75
+ k
76
+ end
77
+
78
+ it "writes the users table to json" do
79
+ db; knife.run
80
+ expect(JSON.parse(File.read("key_dump.json"))).to eq(users_table)
81
+ end
82
+
83
+ it "writes the keys_by_name table to json" do
84
+ db; knife.run
85
+ expect(JSON.parse(File.read("key_table_dump.json"))).to eq(keys_by_name_table)
86
+ end
87
+
88
+ it "does not write the users table if :skip_users_table is set" do
89
+ knife.config[:skip_users_table] = true
90
+ db; knife.run
91
+ expect(File.exist?("key_dump.json")).to eq(false)
92
+ end
93
+
94
+ it "does not write the keys_by_name table if :skip_keys_table is set" do
95
+ knife.config[:skip_keys_table] = true
96
+ db; knife.run
97
+ expect(File.exist?("key_table_dump.json")).to eq(false)
98
+ end
99
+
100
+ it "writes the tables to the specified files when given arguments" do
101
+ knife.name_args = ["user_table.json", "key_table.json"]
102
+ db; knife.run
103
+ expect(JSON.parse(File.read("user_table.json"))).to eq(users_table)
104
+ expect(JSON.parse(File.read("key_table.json"))).to eq(keys_by_name_table)
105
+ end
106
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: knife-ec-backup
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0.beta.4
4
+ version: 2.0.0
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-28 00:00:00.000000000 Z
11
+ date: 2015-01-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sequel
@@ -125,6 +125,8 @@ files:
125
125
  - lib/chef/knife/ec_key_export.rb
126
126
  - lib/chef/knife/ec_key_import.rb
127
127
  - lib/chef/knife/ec_restore.rb
128
+ - lib/chef/org_id_cache.rb
129
+ - lib/chef/org_id_cache.rb~
128
130
  - lib/chef/server.rb
129
131
  - lib/chef/tsorter.rb
130
132
  - lib/knife_ec_backup/version.rb
@@ -152,9 +154,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
152
154
  version: '0'
153
155
  required_rubygems_version: !ruby/object:Gem::Requirement
154
156
  requirements:
155
- - - ">"
157
+ - - ">="
156
158
  - !ruby/object:Gem::Version
157
- version: 1.3.1
159
+ version: '0'
158
160
  requirements: []
159
161
  rubyforge_project:
160
162
  rubygems_version: 2.4.1