chef_fixie_shahid 0.5.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +201 -0
- data/README.md +69 -0
- data/bin/chef_fixie +5 -0
- data/doc/AccessingSQL.md +68 -0
- data/doc/BulkFixup.md +33 -0
- data/doc/CommonTasks.md +31 -0
- data/doc/GETTING_STARTED.md +228 -0
- data/fixie.conf.example +8 -0
- data/lib/chef_fixie_shahid.rb +28 -0
- data/lib/chef_fixie_shahid/authz_mapper.rb +141 -0
- data/lib/chef_fixie_shahid/authz_objects.rb +295 -0
- data/lib/chef_fixie_shahid/bulk_edit_permissions.rb +161 -0
- data/lib/chef_fixie_shahid/check_org_associations.rb +239 -0
- data/lib/chef_fixie_shahid/config.rb +174 -0
- data/lib/chef_fixie_shahid/console.rb +96 -0
- data/lib/chef_fixie_shahid/context.rb +70 -0
- data/lib/chef_fixie_shahid/sql.rb +74 -0
- data/lib/chef_fixie_shahid/sql_objects.rb +573 -0
- data/lib/chef_fixie_shahid/utility_helpers.rb +63 -0
- data/lib/chef_fixie_shahid/version.rb +3 -0
- data/spec/chef_fixie/acl_spec.rb +81 -0
- data/spec/chef_fixie/assoc_invite_spec.rb +44 -0
- data/spec/chef_fixie/check_org_associations_spec.rb +137 -0
- data/spec/chef_fixie/groups_spec.rb +30 -0
- data/spec/chef_fixie/org_spec.rb +25 -0
- data/spec/chef_fixie/orgs_spec.rb +50 -0
- data/spec/spec_helper.rb +40 -0
- metadata +216 -0
@@ -0,0 +1,161 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (c) 2015 Chef Software Inc.
|
3
|
+
# License :: Apache License, Version 2.0
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
#
|
17
|
+
# Author: Mark Anderson <mark@chef.io>
|
18
|
+
#
|
19
|
+
require "sequel"
|
20
|
+
|
21
|
+
require_relative "config.rb"
|
22
|
+
require_relative "authz_objects.rb"
|
23
|
+
require_relative "authz_mapper.rb"
|
24
|
+
|
25
|
+
require "pp"
|
26
|
+
|
27
|
+
module ChefFixie
|
28
|
+
module BulkEditPermissions
|
29
|
+
def self.orgs
|
30
|
+
@orgs ||= ChefFixie::Sql::Orgs.new
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.users
|
34
|
+
@users ||= ChefFixie::Sql::Users.new
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.assocs
|
38
|
+
@assocs ||= ChefFixie::Sql::Associations.new
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.invites
|
42
|
+
invites ||= ChefFixie::Sql::Invites.new
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.check_permissions(org)
|
46
|
+
org = orgs[org] if org.is_a?(String)
|
47
|
+
admins = org.groups["admins"].authz_id
|
48
|
+
pivotal = users["pivotal"].authz_id
|
49
|
+
errors = Hash.new({})
|
50
|
+
org.each_authz_object do |object|
|
51
|
+
begin
|
52
|
+
acl = object.acl_raw
|
53
|
+
rescue RestClient::ResourceNotFound => e
|
54
|
+
puts "#{object.class} '#{object.name}' id '#{object.id}' missing authz info"
|
55
|
+
# pp :object=>object, :e=>e
|
56
|
+
next
|
57
|
+
end
|
58
|
+
broken_acl = {}
|
59
|
+
# the one special case
|
60
|
+
acl.each do |k, v|
|
61
|
+
list = []
|
62
|
+
list << "pivotal" if !v["actors"].member?(pivotal)
|
63
|
+
# admins doesn't belong to the billing admins group
|
64
|
+
if object.class != ChefFixie::Sql::Group || object.name != "billing-admins"
|
65
|
+
list << "admins" if !v["groups"].member?(admins)
|
66
|
+
end
|
67
|
+
broken_acl[k] = list if !list.empty?
|
68
|
+
end
|
69
|
+
if !broken_acl.empty?
|
70
|
+
classname = object.class
|
71
|
+
errors[classname] = {} if !errors.has_key?(classname)
|
72
|
+
errors[classname][object.name] = broken_acl
|
73
|
+
end
|
74
|
+
end
|
75
|
+
errors
|
76
|
+
end
|
77
|
+
|
78
|
+
def self.ace_add(list, ace_type, entity)
|
79
|
+
list.each do |item|
|
80
|
+
if item.respond_to?(:ace_add)
|
81
|
+
item.ace_add(ace_type, entity)
|
82
|
+
else
|
83
|
+
puts "item.class is not a native authz type"
|
84
|
+
return nil
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def self.ace_delete(list, ace_type, entity)
|
90
|
+
list.each do |item|
|
91
|
+
if item.respond_to?(:ace_delete)
|
92
|
+
item.ace_delete(ace_type, entity)
|
93
|
+
else
|
94
|
+
puts "item.class is not a native authz type"
|
95
|
+
return nil
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def self.do_all_objects(org)
|
101
|
+
org = orgs[org] if org.is_a?(String)
|
102
|
+
|
103
|
+
containers = org.containers.all(:all)
|
104
|
+
# Maybe we should fix up containers first?
|
105
|
+
# fix up objects in containers
|
106
|
+
containers.each do |container|
|
107
|
+
# TODO Write some tests to validate that this stuff
|
108
|
+
# works, since it depends on a lot of name magic...
|
109
|
+
object_type = container.name.to_sym
|
110
|
+
# raise Exception "No such object_type #{object_type}" unless org.respond_to?(object_type)
|
111
|
+
objects = org.send(object_type).all(:all)
|
112
|
+
if block_given?
|
113
|
+
yield objects
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def self.ace_add_all(org, ace_type, entity)
|
119
|
+
org = orgs[org] if org.is_a?(String)
|
120
|
+
org.each_authz_object_by_class do |objects|
|
121
|
+
ace_add(objects, ace_type, entity)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def self.ace_delete_all(org, ace_type, entity)
|
126
|
+
org = orgs[org] if org.is_a?(String)
|
127
|
+
org.each_authz_object_by_class do |objects|
|
128
|
+
ace_delete(objects, ace_type, entity)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def self.add_admin_permissions(org)
|
133
|
+
org = orgs[org] if org.is_a?(String)
|
134
|
+
# rework when ace add takes multiple items...
|
135
|
+
admins = org.groups["admins"]
|
136
|
+
pivotal = users["pivotal"]
|
137
|
+
org.each_authz_object do |object|
|
138
|
+
object.ace_add(:all, pivotal)
|
139
|
+
if object.class != ChefFixie::Sql::Group || object.name != "billing-admins"
|
140
|
+
object.ace_add(:all, admins)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
def self.copy_from_containers(org)
|
146
|
+
org = orgs[org] if org.is_a?(String)
|
147
|
+
|
148
|
+
containers = org.containers.all(:all)
|
149
|
+
containers.each do |c|
|
150
|
+
# don't mess with containers and groups, they are special
|
151
|
+
next if c.name == "containers" || c.name == "groups"
|
152
|
+
org.objects_by_container_type(c.name).each do |obj|
|
153
|
+
obj.acl_add_from_object(c)
|
154
|
+
puts "#{obj.name} from #{c.name}"
|
155
|
+
end
|
156
|
+
end
|
157
|
+
nil
|
158
|
+
end
|
159
|
+
|
160
|
+
end
|
161
|
+
end
|
@@ -0,0 +1,239 @@
|
|
1
|
+
# -*- indent-tabs-mode: nil; fill-column: 110 -*-
|
2
|
+
#
|
3
|
+
# 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
|
+
# Author: Mark Anderson <mark@chef.io>
|
19
|
+
#
|
20
|
+
|
21
|
+
require_relative "config"
|
22
|
+
require_relative "authz_objects"
|
23
|
+
require_relative "authz_mapper"
|
24
|
+
require_relative "utility_helpers"
|
25
|
+
|
26
|
+
module ChefFixie
|
27
|
+
module CheckOrgAssociations
|
28
|
+
def self.orgs
|
29
|
+
@orgs ||= ChefFixie::Sql::Orgs.new
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.users
|
33
|
+
@users ||= ChefFixie::Sql::Users.new
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.assocs
|
37
|
+
@assocs ||= ChefFixie::Sql::Associations.new
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.invites
|
41
|
+
invites ||= ChefFixie::Sql::Invites.new
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.make_user(user)
|
45
|
+
if user.is_a?(String)
|
46
|
+
users[user]
|
47
|
+
elsif user.is_a?(ChefFixie::Sql::User)
|
48
|
+
user
|
49
|
+
else
|
50
|
+
raise "Expected a user, got a #{user.class}"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.make_org(org)
|
55
|
+
if org.is_a?(String)
|
56
|
+
orgs[org]
|
57
|
+
elsif org.is_a?(ChefFixie::Sql::Org)
|
58
|
+
org
|
59
|
+
else
|
60
|
+
raise "Expected an org, got a #{org.class}"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def usag_for_user(org, user)
|
65
|
+
user = make_user(user)
|
66
|
+
org = make_org(org)
|
67
|
+
org.groups[user.id]
|
68
|
+
end
|
69
|
+
|
70
|
+
def self.check_association(org, user, global_admins = nil)
|
71
|
+
# magic to make usage easier
|
72
|
+
org = make_org(org)
|
73
|
+
user = make_user(user)
|
74
|
+
global_admins ||= org.global_admins
|
75
|
+
|
76
|
+
# check that the user is associated
|
77
|
+
if !assocs.by_org_id_user_id(org.id, user.id)
|
78
|
+
return :not_associated
|
79
|
+
end
|
80
|
+
|
81
|
+
usag = org.groups[user.id]
|
82
|
+
# check that user has USAG
|
83
|
+
if usag.nil?
|
84
|
+
return :missing_usag
|
85
|
+
end
|
86
|
+
|
87
|
+
if !usag.member?(user)
|
88
|
+
return :user_not_in_usag
|
89
|
+
end
|
90
|
+
|
91
|
+
if !org.groups["users"].member?(usag)
|
92
|
+
return :usag_not_in_users
|
93
|
+
end
|
94
|
+
|
95
|
+
if !user.ace_member?(:read, global_admins)
|
96
|
+
return :global_admins_lacks_read
|
97
|
+
end
|
98
|
+
|
99
|
+
if invites.by_org_id_user_id(org.id, user.id)
|
100
|
+
return :zombie_invite
|
101
|
+
end
|
102
|
+
true
|
103
|
+
end
|
104
|
+
|
105
|
+
def self.fix_association(org, user, global_admins = nil)
|
106
|
+
# magic to make usage easier
|
107
|
+
org = orgs[org] if org.is_a?(String)
|
108
|
+
user = users[user] if user.is_a?(String)
|
109
|
+
global_admins ||= org.global_admins
|
110
|
+
|
111
|
+
failure = check_association(org, user, global_admins)
|
112
|
+
|
113
|
+
case failure
|
114
|
+
when true
|
115
|
+
puts "#{org.name} #{user.name} doesn't need repair"
|
116
|
+
when :user_not_in_usag
|
117
|
+
usag = org.groups[user.id]
|
118
|
+
usag.group_add(user)
|
119
|
+
when :usag_not_in_users
|
120
|
+
usag = org.groups[user.id]
|
121
|
+
org.groups["users"].group_add(usag)
|
122
|
+
when :global_admins_lacks_read
|
123
|
+
user.ace_add(:read, global_admins)
|
124
|
+
else
|
125
|
+
puts "#{org.name} #{user.name} can't fix problem #{failure} yet"
|
126
|
+
return false
|
127
|
+
end
|
128
|
+
true
|
129
|
+
end
|
130
|
+
|
131
|
+
def self.check_associations(org)
|
132
|
+
success = true
|
133
|
+
org = make_org(org)
|
134
|
+
orgname = org.name
|
135
|
+
|
136
|
+
# check that global_admins exists:
|
137
|
+
global_admins = org.global_admins
|
138
|
+
if !global_admins || !global_admins.is_a?(ChefFixie::Sql::Group)
|
139
|
+
puts "#{orgname} Missing global admins group"
|
140
|
+
success = false
|
141
|
+
end
|
142
|
+
|
143
|
+
users_assoc = assocs.by_org_id(org.id).all(:all)
|
144
|
+
users_invite = invites.by_org_id(org.id).all(:all)
|
145
|
+
|
146
|
+
user_ids = users_assoc.map { |a| a.user_id }
|
147
|
+
users_in_org = user_ids.map { |i| users.by_id(i).all.first }
|
148
|
+
usernames = users_in_org.map { |u| u.name }
|
149
|
+
|
150
|
+
# check that users aren't both invited and associated
|
151
|
+
invited_ids = users_invite.map { |a| a.user_id }
|
152
|
+
overlap_ids = user_ids & invited_ids
|
153
|
+
|
154
|
+
if !overlap_ids.empty?
|
155
|
+
overlap_names = overlap_ids.map { |i| users.by_id(i).all.first.name rescue "#{i}" }
|
156
|
+
puts "#{orgname} users both associated and invited: #{overlap_names.join(', ')}"
|
157
|
+
success = false
|
158
|
+
end
|
159
|
+
|
160
|
+
# Check that we don't have zombie USAGs left around (not 100% reliable)
|
161
|
+
# because someone could create a group that looks like a USAG
|
162
|
+
possible_usags = org.groups.list(:all) - user_ids
|
163
|
+
usags = possible_usags.select { |n| n =~ /^\h+{20}$/ }
|
164
|
+
if !usags.empty?
|
165
|
+
puts "#{orgname} Suspicious USAGS without associated user #{usags.join(', ')}"
|
166
|
+
end
|
167
|
+
|
168
|
+
# Check group membership for sanity
|
169
|
+
success &= check_group(org, "billing-admins", usernames)
|
170
|
+
success &= check_group(org, "admins", usernames)
|
171
|
+
|
172
|
+
# TODO check for non-usags in users!
|
173
|
+
users_members = org.groups["users"].group
|
174
|
+
users_actors = users_members["actors"] - [[:global, "pivotal"]]
|
175
|
+
if !users_actors.empty?
|
176
|
+
puts "#{orgname} has actors in it's users group #{users_actors}"
|
177
|
+
end
|
178
|
+
non_usags = users_members["groups"].map { |g| g[1] } - user_ids
|
179
|
+
if !non_usags.empty?
|
180
|
+
puts "#{orgname} warning: has non usags in it's users group #{non_usags.join(', ')}"
|
181
|
+
end
|
182
|
+
|
183
|
+
# Check individual associations
|
184
|
+
users_in_org.each do |user|
|
185
|
+
result = check_association(org, user, global_admins)
|
186
|
+
if result != true
|
187
|
+
puts "Org #{orgname} Association check failed for #{user.name} #{result}"
|
188
|
+
success = false
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
puts "Org #{orgname} is #{success ? 'ok' : 'bad'} (#{users_in_org.count} users)"
|
193
|
+
success
|
194
|
+
end
|
195
|
+
|
196
|
+
# expect at least one current user to be in admins and billing admins
|
197
|
+
def self.check_group(org, groupname, users)
|
198
|
+
g = org.groups[groupname]
|
199
|
+
if g.nil?
|
200
|
+
puts "#{orgname} Missing group #{groupname}"
|
201
|
+
return :no_such_group
|
202
|
+
end
|
203
|
+
actors = g.group["actors"].map { |x| x[1] }
|
204
|
+
live = actors & users
|
205
|
+
|
206
|
+
if live.count == 0
|
207
|
+
puts "Org #{org.name} has no active users in #{groupname}"
|
208
|
+
return false
|
209
|
+
end
|
210
|
+
true
|
211
|
+
end
|
212
|
+
|
213
|
+
def self.remove_association(org, user)
|
214
|
+
# magic to make usage easier
|
215
|
+
org = make_org(org)
|
216
|
+
user = make_user(user)
|
217
|
+
|
218
|
+
# remove USAG
|
219
|
+
usag = org.groups[user.id]
|
220
|
+
usag.delete if usag
|
221
|
+
|
222
|
+
# remove from any groups they are in
|
223
|
+
org.groups.all(:all).each do |g|
|
224
|
+
g.group_delete(user) if g.member?(user)
|
225
|
+
end
|
226
|
+
|
227
|
+
# remove read ACE
|
228
|
+
user.ace_delete(:read, org.global_admins)
|
229
|
+
|
230
|
+
# remove association record
|
231
|
+
assoc = assocs.by_org_id_user_id(org.id, user.id)
|
232
|
+
assoc.delete if assoc
|
233
|
+
|
234
|
+
# remove any invites
|
235
|
+
invite = invites.by_org_id_user_id(org.id, user.id)
|
236
|
+
invite.delete if invite
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
@@ -0,0 +1,174 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (c) 2014-2015 Chef Software Inc.
|
3
|
+
# License :: Apache License, Version 2.0
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
#
|
17
|
+
# Author: Mark Anderson <mark@chef.io>
|
18
|
+
#
|
19
|
+
# Much of this code was orginally derived from the orgmapper tool, which had many varied authors.
|
20
|
+
|
21
|
+
require "singleton"
|
22
|
+
require "ffi_yajl"
|
23
|
+
require "pathname"
|
24
|
+
require "veil"
|
25
|
+
|
26
|
+
module ChefFixie
|
27
|
+
def self.configure
|
28
|
+
yield Config.instance
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.load_config(config_file = nil)
|
32
|
+
if config_file
|
33
|
+
puts "loading config: #{config_file}..." if ChefFixie::Console.started_from_command_line?
|
34
|
+
Kernel.load(config_file)
|
35
|
+
else
|
36
|
+
path = "/etc/opscode"
|
37
|
+
puts "loading config from #{path}" if ChefFixie::Console.started_from_command_line?
|
38
|
+
ChefFixie::Config.instance.load_from_pc(path)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.setup
|
43
|
+
# TODO: do we have to polute global object with this to make it available to the irb instance?
|
44
|
+
Object.const_set(:ORGS, ChefFixie::Sql::Orgs.new)
|
45
|
+
Object.const_set(:USERS, ChefFixie::Sql::Users.new)
|
46
|
+
Object.const_set(:ASSOCS, ChefFixie::Sql::Associations.new)
|
47
|
+
Object.const_set(:INVITES, ChefFixie::Sql::Invites.new)
|
48
|
+
|
49
|
+
# scope this by the global org id?
|
50
|
+
Object.const_set(:GLOBAL_GROUPS, ChefFixie::Sql::Groups.new.by_org_id(ChefFixie::Sql::Orgs::GlobalOrg))
|
51
|
+
Object.const_set(:GLOBAL_CONTAINERS, ChefFixie::Sql::Containers.new.by_org_id(ChefFixie::Sql::Orgs::GlobalOrg))
|
52
|
+
end
|
53
|
+
|
54
|
+
##
|
55
|
+
# = ChefFixie::Config
|
56
|
+
# configuration for the fixie command.
|
57
|
+
#
|
58
|
+
# ==Example Config File:
|
59
|
+
#
|
60
|
+
# Fixie.configure do |mapper|
|
61
|
+
# mapper.authz_uri = 'http://authz.example.com:5959'
|
62
|
+
# end
|
63
|
+
#
|
64
|
+
class Config
|
65
|
+
include Singleton
|
66
|
+
KEYS = [:authz_uri, :sql_database, :superuser_id, :pivotal_key]
|
67
|
+
KEYS.each { |k| attr_accessor k }
|
68
|
+
|
69
|
+
def merge_opts(opts = {})
|
70
|
+
opts.each do |key, value|
|
71
|
+
send("#{key}=".to_sym, value)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# this is waaay tightly coupled to ::Backend's initialize method
|
76
|
+
def to_ary
|
77
|
+
[couchdb_uri, database, auth_uri, authz_couch, sql_database, superuser_id].compact
|
78
|
+
end
|
79
|
+
|
80
|
+
def to_text
|
81
|
+
txt = ["### ChefFixie::Config"]
|
82
|
+
max_key_len = KEYS.inject(0) do |max, k|
|
83
|
+
key_len = k.to_s.length
|
84
|
+
key_len > max ? key_len : max
|
85
|
+
end
|
86
|
+
KEYS.each do |key|
|
87
|
+
value = send(key) || "default"
|
88
|
+
txt << "# %#{max_key_len}s: %s" % [key.to_s, value]
|
89
|
+
end
|
90
|
+
txt.join("\n")
|
91
|
+
end
|
92
|
+
|
93
|
+
def example_config
|
94
|
+
txt = ["Fixie.configure do |mapper|"]
|
95
|
+
KEYS.each do |key|
|
96
|
+
txt << " mapper.%s = %s" % [key.to_s, '"something"']
|
97
|
+
end
|
98
|
+
txt << "end"
|
99
|
+
txt.join("\n")
|
100
|
+
end
|
101
|
+
|
102
|
+
def load_from_pc(dir = "/etc/opscode")
|
103
|
+
configdir = Pathname.new(dir)
|
104
|
+
|
105
|
+
config_files = %w{chef-server-running.json}
|
106
|
+
config = load_json_from_path([configdir], config_files)
|
107
|
+
|
108
|
+
secrets = load_secrets_from_path([configdir], %w{private-chef-secrets.json} )
|
109
|
+
|
110
|
+
authz_config = config["private_chef"]["oc_bifrost"]
|
111
|
+
authz_vip = authz_config["vip"]
|
112
|
+
authz_port = authz_config["port"]
|
113
|
+
@authz_uri = "http://#{authz_vip}:#{authz_port}"
|
114
|
+
|
115
|
+
@superuser_id = dig(secrets, %w{oc_bifrost superuser_id}) || authz_config["superuser_id"]
|
116
|
+
|
117
|
+
sql_config = config["private_chef"]["postgresql"]
|
118
|
+
erchef_config = config["private_chef"]["opscode-erchef"]
|
119
|
+
|
120
|
+
sql_user = sql_config["sql_user"] || erchef_config["sql_user"]
|
121
|
+
sql_pw = dig(secrets, %w{opscode_erchef sql_password}) || sql_config["sql_password"] || erchef_config["sql_password"]
|
122
|
+
sql_vip = sql_config["vip"]
|
123
|
+
sql_port = sql_config["port"]
|
124
|
+
|
125
|
+
@sql_database = "postgres://#{sql_user}:#{sql_pw}@#{sql_vip}/opscode_chef"
|
126
|
+
|
127
|
+
@pivotal_key = configdir + "pivotal.pem"
|
128
|
+
end
|
129
|
+
|
130
|
+
def load_json_from_path(pathlist, filelist)
|
131
|
+
parser = FFI_Yajl::Parser.new
|
132
|
+
pathlist.each do |path|
|
133
|
+
filelist.each do |file|
|
134
|
+
configfile = path + file
|
135
|
+
if configfile.file?
|
136
|
+
data = File.read(configfile)
|
137
|
+
return parser.parse(data)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
def load_secrets_from_path(pathlist, filelist)
|
144
|
+
pathlist.each do |path|
|
145
|
+
filelist.each do |file|
|
146
|
+
configfile = path + file
|
147
|
+
if configfile.file?
|
148
|
+
data = Veil::CredentialCollection::ChefSecretsFile.from_file(configfile)
|
149
|
+
return data
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
nil
|
154
|
+
end
|
155
|
+
|
156
|
+
def dig(hash, list)
|
157
|
+
if hash.respond_to?(:get)
|
158
|
+
hash.get(*list)
|
159
|
+
elsif hash.nil?
|
160
|
+
nil
|
161
|
+
elsif list.empty?
|
162
|
+
hash
|
163
|
+
else
|
164
|
+
element = list.shift
|
165
|
+
if hash.has_key?(element)
|
166
|
+
dig(hash[element], list)
|
167
|
+
else
|
168
|
+
nil
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
end
|
174
|
+
end
|