knife-ec-backup 2.0.2 → 2.0.3
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.
- checksums.yaml +4 -4
- data/README.md +16 -1
- data/lib/chef/knife/ec_backup.rb +7 -7
- data/lib/chef/knife/ec_base.rb +6 -4
- data/lib/chef/knife/ec_restore.rb +9 -9
- data/lib/knife_ec_backup/version.rb +1 -1
- data/spec/chef/knife/ec_backup_spec.rb +16 -16
- data/spec/chef/knife/ec_base_spec.rb +6 -6
- data/spec/chef/knife/ec_restore_spec.rb +11 -11
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 04304f65196eef419d1d4dcaebe502b2fbdc447e
|
4
|
+
data.tar.gz: 8479d9bb56279a59c4b3928d9ab500937a2d53ca
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1896a28f8524b4fc82fbf72b44127cda7efdd4d917e6451088b4ff17d9967bba559d86eba9b467c5e09f3fe6c8ffa78deb3aa5189e9bf23ca363e141ccb63460
|
7
|
+
data.tar.gz: ab1a72efa1c3e0bd71c5a66cdd38b02230801ac92c2fa6b429a00e201a8fff8702e428ce47fe2b2f883855a5ec10fe1bf7c572a029463b5d8b6048ad13e48491
|
data/README.md
CHANGED
@@ -8,7 +8,7 @@ text format. It is similar to the `knife download` and `knife upload`
|
|
8
8
|
commands and uses the same underlying libraries, but also includes
|
9
9
|
workarounds for objects not yet supported by those tools and various
|
10
10
|
Server API deficiencies. The long-run goal is to improve `knife
|
11
|
-
|
11
|
+
download`, `knife upload` and the Chef Server API and deprecate this
|
12
12
|
tool.
|
13
13
|
|
14
14
|
# Requirements
|
@@ -52,6 +52,21 @@ on your system, try the following:
|
|
52
52
|
|
53
53
|
/opt/opscode/embedded/bin/gem install knife-ec-backup -- --with-pg-config=/opt/opscode/embedded/postgresql/9.2/bin/pg_config
|
54
54
|
|
55
|
+
## Running tests
|
56
|
+
|
57
|
+
```
|
58
|
+
$ bundle install
|
59
|
+
$ bundle exec rspec spec/
|
60
|
+
```
|
61
|
+
|
62
|
+
If bundle install fails on the pg gem and the note above does not work for you, try:
|
63
|
+
|
64
|
+
```
|
65
|
+
$ brew install postgres (if not present)
|
66
|
+
$ ARCHFLAGS="-arch x86_64" gem install pg
|
67
|
+
$ bundle exec rspec spec/
|
68
|
+
```
|
69
|
+
|
55
70
|
## Build from source
|
56
71
|
|
57
72
|
Clone the git repository and run the following from inside:
|
data/lib/chef/knife/ec_backup.rb
CHANGED
@@ -48,16 +48,16 @@ class Chef
|
|
48
48
|
end
|
49
49
|
|
50
50
|
def for_each_user
|
51
|
-
rest.
|
51
|
+
rest.get('/users').each_pair do |name, url|
|
52
52
|
yield name, url
|
53
53
|
end
|
54
54
|
end
|
55
55
|
|
56
56
|
def for_each_organization
|
57
|
-
rest.
|
57
|
+
rest.get('/organizations').each_pair do |name, url|
|
58
58
|
next unless (config[:org].nil? || config[:org] == name)
|
59
59
|
ui.msg "Downloading organization object for #{name} from #{url}"
|
60
|
-
org = rest.
|
60
|
+
org = rest.get(url)
|
61
61
|
# Enterprise Chef 11 and below uses a pool of precreated
|
62
62
|
# organizations to account for slow organization creation
|
63
63
|
# using CouchDB. Thus, on server versions < 12 we want to
|
@@ -75,14 +75,14 @@ class Chef
|
|
75
75
|
def download_user(username, url)
|
76
76
|
ensure_dir("#{dest_dir}/users")
|
77
77
|
File.open("#{dest_dir}/users/#{username}.json", 'w') do |file|
|
78
|
-
file.write(Chef::JSONCompat.to_json_pretty(rest.
|
78
|
+
file.write(Chef::JSONCompat.to_json_pretty(rest.get(url)))
|
79
79
|
end
|
80
80
|
end
|
81
81
|
|
82
82
|
def download_user_acl(username)
|
83
83
|
ensure_dir("#{dest_dir}/user_acls")
|
84
84
|
File.open("#{dest_dir}/user_acls/#{username}.json", 'w') do |file|
|
85
|
-
file.write(Chef::JSONCompat.to_json_pretty(user_acl_rest.
|
85
|
+
file.write(Chef::JSONCompat.to_json_pretty(user_acl_rest.get("users/#{username}/_acl")))
|
86
86
|
end
|
87
87
|
end
|
88
88
|
|
@@ -111,14 +111,14 @@ class Chef
|
|
111
111
|
def download_org_members(name)
|
112
112
|
ensure_dir("#{dest_dir}/organizations/#{name}")
|
113
113
|
File.open("#{dest_dir}/organizations/#{name}/members.json", 'w') do |file|
|
114
|
-
file.write(Chef::JSONCompat.to_json_pretty(rest.
|
114
|
+
file.write(Chef::JSONCompat.to_json_pretty(rest.get("/organizations/#{name}/users")))
|
115
115
|
end
|
116
116
|
end
|
117
117
|
|
118
118
|
def download_org_invitations(name)
|
119
119
|
ensure_dir("#{dest_dir}/organizations/#{name}")
|
120
120
|
File.open("#{dest_dir}/organizations/#{name}/invitations.json", 'w') do |file|
|
121
|
-
file.write(Chef::JSONCompat.to_json_pretty(rest.
|
121
|
+
file.write(Chef::JSONCompat.to_json_pretty(rest.get("/organizations/#{name}/association_requests")))
|
122
122
|
end
|
123
123
|
end
|
124
124
|
|
data/lib/chef/knife/ec_base.rb
CHANGED
@@ -89,8 +89,8 @@ class Chef
|
|
89
89
|
|
90
90
|
def org_admin
|
91
91
|
rest = Chef::REST.new(Chef::Config.chef_server_url)
|
92
|
-
admin_users = rest.
|
93
|
-
org_members = rest.
|
92
|
+
admin_users = rest.get('groups/admins')['users']
|
93
|
+
org_members = rest.get('users').map { |user| user['user']['username'] }
|
94
94
|
admin_users.delete_if { |user| !org_members.include?(user) || user == 'pivotal' }
|
95
95
|
if admin_users.empty?
|
96
96
|
raise Chef::Knife::EcBase::NoAdminFound
|
@@ -109,8 +109,10 @@ class Chef
|
|
109
109
|
end
|
110
110
|
end
|
111
111
|
|
112
|
+
# Since knife-ec-backup hasn't been updated to use API V1 keys endpoints
|
113
|
+
# we should explicitly as for V0.
|
112
114
|
def rest
|
113
|
-
@rest ||= Chef::
|
115
|
+
@rest ||= Chef::ServerAPI.new(server.root_url, {:api_version => "0"})
|
114
116
|
end
|
115
117
|
|
116
118
|
def user_acl_rest
|
@@ -119,7 +121,7 @@ class Chef
|
|
119
121
|
elsif server.supports_user_acls?
|
120
122
|
rest
|
121
123
|
elsif server.direct_account_access?
|
122
|
-
Chef::
|
124
|
+
Chef::ServerAPI.new("http://127.0.0.1:9465", {:api_version => "0"})
|
123
125
|
end
|
124
126
|
|
125
127
|
end
|
@@ -62,10 +62,10 @@ class Chef
|
|
62
62
|
|
63
63
|
def create_organization(orgname)
|
64
64
|
org = JSONCompat.from_json(File.read("#{dest_dir}/organizations/#{orgname}/org.json"))
|
65
|
-
rest.
|
65
|
+
rest.post('organizations', org)
|
66
66
|
rescue Net::HTTPServerException => e
|
67
67
|
if e.response.code == "409"
|
68
|
-
rest.
|
68
|
+
rest.put("organizations/#{orgname}", org)
|
69
69
|
else
|
70
70
|
raise
|
71
71
|
end
|
@@ -75,7 +75,7 @@ class Chef
|
|
75
75
|
invitations = JSONCompat.from_json(File.read("#{dest_dir}/organizations/#{orgname}/invitations.json"))
|
76
76
|
invitations.each do |invitation|
|
77
77
|
begin
|
78
|
-
rest.
|
78
|
+
rest.post("organizations/#{orgname}/association_requests", { 'user' => invitation['username'] })
|
79
79
|
rescue Net::HTTPServerException => e
|
80
80
|
if e.response.code != "409"
|
81
81
|
ui.error("Cannot create invitation #{invitation['id']}")
|
@@ -89,9 +89,9 @@ class Chef
|
|
89
89
|
members.each do |member|
|
90
90
|
username = member['user']['username']
|
91
91
|
begin
|
92
|
-
response = rest.
|
92
|
+
response = rest.post("organizations/#{orgname}/association_requests", { 'user' => username })
|
93
93
|
association_id = response["uri"].split("/").last
|
94
|
-
rest.
|
94
|
+
rest.put("users/#{username}/association_requests/#{association_id}", { 'response' => 'accept' })
|
95
95
|
rescue Net::HTTPServerException => e
|
96
96
|
if e.response.code != "409"
|
97
97
|
raise
|
@@ -136,10 +136,10 @@ class Chef
|
|
136
136
|
# Supply password for new user
|
137
137
|
user_with_password = user.dup
|
138
138
|
user_with_password['password'] = SecureRandom.hex
|
139
|
-
rest.
|
139
|
+
rest.post('users', user_with_password)
|
140
140
|
rescue Net::HTTPServerException => e
|
141
141
|
if e.response.code == "409"
|
142
|
-
rest.
|
142
|
+
rest.put("users/#{name}", user)
|
143
143
|
else
|
144
144
|
raise
|
145
145
|
end
|
@@ -304,12 +304,12 @@ class Chef
|
|
304
304
|
end
|
305
305
|
|
306
306
|
def put_acl(rest, url, acls)
|
307
|
-
old_acls = rest.
|
307
|
+
old_acls = rest.get(url)
|
308
308
|
old_acls = Chef::ChefFS::DataHandler::AclDataHandler.new.normalize(old_acls, nil)
|
309
309
|
acls = Chef::ChefFS::DataHandler::AclDataHandler.new.normalize(acls, nil)
|
310
310
|
if acls != old_acls
|
311
311
|
Chef::ChefFS::FileSystem::AclEntry::PERMISSIONS.each do |permission|
|
312
|
-
rest.
|
312
|
+
rest.put("#{url}/#{permission}", { permission => acls[permission] })
|
313
313
|
end
|
314
314
|
end
|
315
315
|
end
|
@@ -37,19 +37,19 @@ describe Chef::Knife::EcBackup do
|
|
37
37
|
|
38
38
|
describe "#for_each_user" do
|
39
39
|
it "iterates over remote users" do
|
40
|
-
allow(@rest).to receive(:
|
40
|
+
allow(@rest).to receive(:get).with("/users").and_return(USER_RESPONSE)
|
41
41
|
expect{ |b| @knife.for_each_user(&b) }.to yield_successive_args(["foo", USER_RESPONSE["foo"]], ["bar", USER_RESPONSE["bar"]])
|
42
42
|
end
|
43
43
|
end
|
44
44
|
|
45
45
|
describe "#for_each_organization" do
|
46
46
|
before(:each) do
|
47
|
-
allow(@rest).to receive(:
|
47
|
+
allow(@rest).to receive(:get).with("/organizations").and_return(ORG_RESPONSE)
|
48
48
|
end
|
49
49
|
|
50
50
|
it "iterates over remote organizations" do
|
51
|
-
allow(@rest).to receive(:
|
52
|
-
allow(@rest).to receive(:
|
51
|
+
allow(@rest).to receive(:get).with("organizations/bar").and_return(org_response("bar"))
|
52
|
+
allow(@rest).to receive(:get).with("organizations/foo").and_return(org_response("foo"))
|
53
53
|
expect{ |b| @knife.for_each_organization(&b) }.to yield_successive_args(org_response("bar"), org_response("foo"))
|
54
54
|
end
|
55
55
|
|
@@ -57,8 +57,8 @@ describe Chef::Knife::EcBackup do
|
|
57
57
|
server = double('Chef::Server')
|
58
58
|
allow(Chef::Server).to receive(:new).and_return(server)
|
59
59
|
allow(server).to receive(:version).and_return(Gem::Version.new("11.12.3"))
|
60
|
-
allow(@rest).to receive(:
|
61
|
-
allow(@rest).to receive(:
|
60
|
+
allow(@rest).to receive(:get).with("organizations/bar").and_return(org_response("bar"))
|
61
|
+
allow(@rest).to receive(:get).with("organizations/foo").and_return(org_response("foo", true))
|
62
62
|
expect{ |b| @knife.for_each_organization(&b) }.to yield_successive_args(org_response("bar"))
|
63
63
|
end
|
64
64
|
|
@@ -66,8 +66,8 @@ describe Chef::Knife::EcBackup do
|
|
66
66
|
server = double('Chef::Server')
|
67
67
|
allow(Chef::Server).to receive(:new).and_return(server)
|
68
68
|
allow(server).to receive(:version).and_return(Gem::Version.new("12.0.0"))
|
69
|
-
allow(@rest).to receive(:
|
70
|
-
allow(@rest).to receive(:
|
69
|
+
allow(@rest).to receive(:get).with("organizations/bar").and_return(org_response("bar"))
|
70
|
+
allow(@rest).to receive(:get).with("organizations/foo").and_return(org_response("foo", true))
|
71
71
|
expect{ |b| @knife.for_each_organization(&b) }.to yield_successive_args(org_response("bar"),
|
72
72
|
org_response("foo", true))
|
73
73
|
end
|
@@ -79,13 +79,13 @@ describe Chef::Knife::EcBackup do
|
|
79
79
|
let (:url) { "users/foo" }
|
80
80
|
|
81
81
|
it "downloads a named user from the api" do
|
82
|
-
expect(@rest).to receive(:
|
82
|
+
expect(@rest).to receive(:get).with(url)
|
83
83
|
@knife.download_user(username, url)
|
84
84
|
end
|
85
85
|
|
86
86
|
it "writes it to a json file in the destination directory" do
|
87
87
|
user_response = {"username" => "foo"}
|
88
|
-
allow(@rest).to receive(:
|
88
|
+
allow(@rest).to receive(:get).with(url).and_return(user_response)
|
89
89
|
@knife.download_user(username, url)
|
90
90
|
expect(JSON.parse(File.read("/users/foo.json"))).to eq(user_response)
|
91
91
|
end
|
@@ -96,13 +96,13 @@ describe Chef::Knife::EcBackup do
|
|
96
96
|
let (:username) {"foo"}
|
97
97
|
|
98
98
|
it "downloads a user acl from the API" do
|
99
|
-
expect(@rest).to receive(:
|
99
|
+
expect(@rest).to receive(:get).with("users/#{username}/_acl")
|
100
100
|
@knife.download_user_acl(username)
|
101
101
|
end
|
102
102
|
|
103
103
|
it "writes it to a json file in the destination directory" do
|
104
104
|
user_acl_response = {"create" => {}}
|
105
|
-
allow(@rest).to receive(:
|
105
|
+
allow(@rest).to receive(:get).with("users/#{username}/_acl").and_return(user_acl_response)
|
106
106
|
@knife.download_user_acl(username)
|
107
107
|
expect(JSON.parse(File.read("/user_acls/foo.json"))).to eq(user_acl_response)
|
108
108
|
end
|
@@ -130,12 +130,12 @@ describe Chef::Knife::EcBackup do
|
|
130
130
|
}
|
131
131
|
|
132
132
|
it "downloads org members for a given org" do
|
133
|
-
expect(@rest).to receive(:
|
133
|
+
expect(@rest).to receive(:get).with("/organizations/bob/users").and_return(users)
|
134
134
|
@knife.download_org_members("bob")
|
135
135
|
end
|
136
136
|
|
137
137
|
it "writes the org members to a JSON file" do
|
138
|
-
expect(@rest).to receive(:
|
138
|
+
expect(@rest).to receive(:get).with("/organizations/bob/users").and_return(users)
|
139
139
|
@knife.download_org_members("bob")
|
140
140
|
expect(JSON.parse(File.read("/organizations/bob/members.json"))).to eq(users)
|
141
141
|
end
|
@@ -145,12 +145,12 @@ describe Chef::Knife::EcBackup do
|
|
145
145
|
include FakeFS::SpecHelpers
|
146
146
|
let(:invites) { {"a json" => "maybe"} }
|
147
147
|
it "downloads invitations for a given org" do
|
148
|
-
expect(@rest).to receive(:
|
148
|
+
expect(@rest).to receive(:get).with("/organizations/bob/association_requests").and_return(invites)
|
149
149
|
@knife.download_org_invitations("bob")
|
150
150
|
end
|
151
151
|
|
152
152
|
it "writes the invitations to a JSON file" do
|
153
|
-
expect(@rest).to receive(:
|
153
|
+
expect(@rest).to receive(:get).with("/organizations/bob/association_requests").and_return(invites)
|
154
154
|
@knife.download_org_invitations("bob")
|
155
155
|
expect(JSON.parse(File.read("/organizations/bob/invitations.json"))).to eq(invites)
|
156
156
|
end
|
@@ -19,20 +19,20 @@ describe Chef::Knife::EcBase do
|
|
19
19
|
|
20
20
|
context "org_admin" do
|
21
21
|
it "selects an admin from an org" do
|
22
|
-
allow(@rest).to receive(:
|
23
|
-
allow(@rest).to receive(:
|
22
|
+
allow(@rest).to receive(:get).with("groups/admins").and_return({"users" => ["bob"]})
|
23
|
+
allow(@rest).to receive(:get).with("users").and_return([{"user" => { "username" => "bob"}}])
|
24
24
|
expect(o.org_admin).to eq("bob")
|
25
25
|
end
|
26
26
|
|
27
27
|
it "refuses to return pivotal" do
|
28
|
-
allow(@rest).to receive(:
|
29
|
-
allow(@rest).to receive(:
|
28
|
+
allow(@rest).to receive(:get).with("groups/admins").and_return({"users" => ["pivotal"]})
|
29
|
+
allow(@rest).to receive(:get).with("users").and_return([{"user" => { "username" => "pivotal"}}])
|
30
30
|
expect{o.org_admin}.to raise_error(Chef::Knife::EcBase::NoAdminFound)
|
31
31
|
end
|
32
32
|
|
33
33
|
it "refuses to return users not in the org" do
|
34
|
-
allow(@rest).to receive(:
|
35
|
-
allow(@rest).to receive(:
|
34
|
+
allow(@rest).to receive(:get).with("groups/admins").and_return({"users" => ["bob"]})
|
35
|
+
allow(@rest).to receive(:get).with("users").and_return([{"user" => { "username" => "sally"}}])
|
36
36
|
expect{o.org_admin}.to raise_error(Chef::Knife::EcBase::NoAdminFound)
|
37
37
|
end
|
38
38
|
end
|
@@ -33,15 +33,15 @@ describe Chef::Knife::EcRestore do
|
|
33
33
|
it "posts a given org to the API from data on disk" do
|
34
34
|
make_org "foo"
|
35
35
|
org = JSON.parse(File.read("/organizations/foo/org.json"))
|
36
|
-
expect(@rest).to receive(:
|
36
|
+
expect(@rest).to receive(:post).with("organizations", org)
|
37
37
|
@knife.create_organization("foo")
|
38
38
|
end
|
39
39
|
|
40
40
|
it "updates a given org if it already exists" do
|
41
41
|
make_org "foo"
|
42
42
|
org = JSON.parse(File.read("/organizations/foo/org.json"))
|
43
|
-
allow(@rest).to receive(:
|
44
|
-
expect(@rest).to receive(:
|
43
|
+
allow(@rest).to receive(:post).with("organizations", org).and_raise(net_exception(409))
|
44
|
+
expect(@rest).to receive(:put).with("organizations/foo", org)
|
45
45
|
@knife.create_organization("foo")
|
46
46
|
end
|
47
47
|
end
|
@@ -51,15 +51,15 @@ describe Chef::Knife::EcRestore do
|
|
51
51
|
|
52
52
|
it "reads the invitations from disk and posts them to the API" do
|
53
53
|
make_org "foo"
|
54
|
-
expect(@rest).to receive(:
|
55
|
-
expect(@rest).to receive(:
|
54
|
+
expect(@rest).to receive(:post).with("organizations/foo/association_requests", {"user" => "bob"})
|
55
|
+
expect(@rest).to receive(:post).with("organizations/foo/association_requests", {"user" => "jane"})
|
56
56
|
@knife.restore_open_invitations("foo")
|
57
57
|
end
|
58
58
|
|
59
59
|
it "does NOT fail if an inivitation already exists" do
|
60
60
|
make_org "foo"
|
61
|
-
allow(@rest).to receive(:
|
62
|
-
allow(@rest).to receive(:
|
61
|
+
allow(@rest).to receive(:post).with("organizations/foo/association_requests", {"user" => "bob"}).and_return(net_exception(409))
|
62
|
+
allow(@rest).to receive(:post).with("organizations/foo/association_requests", {"user" => "jane"}).and_return(net_exception(409))
|
63
63
|
expect {@knife.restore_open_invitations("foo")}.to_not raise_error
|
64
64
|
end
|
65
65
|
end
|
@@ -117,21 +117,21 @@ describe Chef::Knife::EcRestore do
|
|
117
117
|
|
118
118
|
it "reads the user from disk and posts it to the API" do
|
119
119
|
make_user "jane"
|
120
|
-
expect(@rest).to receive(:
|
120
|
+
expect(@rest).to receive(:post).with("users", anything)
|
121
121
|
@knife.restore_users
|
122
122
|
end
|
123
123
|
|
124
124
|
it "sets a random password for users" do
|
125
125
|
make_user "jane"
|
126
126
|
# FIX ME: How can we test this better?
|
127
|
-
expect(@rest).to receive(:
|
127
|
+
expect(@rest).to receive(:post).with("users", {"username" => "jane", "password" => anything})
|
128
128
|
@knife.restore_users
|
129
129
|
end
|
130
130
|
|
131
131
|
it "updates the user if it already exists" do
|
132
132
|
make_user "jane"
|
133
|
-
allow(@rest).to receive(:
|
134
|
-
expect(@rest).to receive(:
|
133
|
+
allow(@rest).to receive(:post).with("users", anything).and_raise(net_exception(409))
|
134
|
+
expect(@rest).to receive(:put).with("users/jane", {"username" => "jane"})
|
135
135
|
@knife.restore_users
|
136
136
|
end
|
137
137
|
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.
|
4
|
+
version: 2.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- John Keiser
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-07-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: sequel
|