knife-ec-backup 2.0.2 → 2.0.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|