chef_fixie 0.3.0 → 1.0.2
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 +5 -5
- data/bin/chef_fixie +1 -1
- data/doc/BulkFixup.md +1 -1
- data/doc/CommonTasks.md +14 -3
- data/lib/chef_fixie.rb +7 -7
- data/lib/chef_fixie/authz_mapper.rb +26 -28
- data/lib/chef_fixie/authz_objects.rb +44 -41
- data/lib/chef_fixie/bulk_edit_permissions.rb +24 -20
- data/lib/chef_fixie/check_org_associations.rb +56 -58
- data/lib/chef_fixie/config.rb +58 -24
- data/lib/chef_fixie/console.rb +15 -10
- data/lib/chef_fixie/context.rb +2 -4
- data/lib/chef_fixie/sql.rb +12 -12
- data/lib/chef_fixie/sql_objects.rb +49 -38
- data/lib/chef_fixie/utility_helpers.rb +13 -9
- data/lib/chef_fixie/version.rb +1 -1
- data/spec/chef_fixie/acl_spec.rb +23 -25
- data/spec/chef_fixie/assoc_invite_spec.rb +5 -8
- data/spec/chef_fixie/check_org_associations_spec.rb +14 -17
- data/spec/chef_fixie/groups_spec.rb +7 -11
- data/spec/chef_fixie/org_spec.rb +4 -5
- data/spec/chef_fixie/orgs_spec.rb +6 -9
- data/spec/spec_helper.rb +5 -6
- metadata +18 -84
- data/bin/bundler +0 -16
- data/bin/chef-apply +0 -16
- data/bin/chef-client +0 -16
- data/bin/chef-shell +0 -16
- data/bin/chef-solo +0 -16
- data/bin/chef-zero +0 -16
- data/bin/coderay +0 -16
- data/bin/edit_json.rb +0 -16
- data/bin/erubis +0 -16
- data/bin/ffi-yajl-bench +0 -16
- data/bin/fixie~ +0 -231
- data/bin/htmldiff +0 -16
- data/bin/knife +0 -16
- data/bin/ldiff +0 -16
- data/bin/net-dhcp +0 -16
- data/bin/ohai +0 -16
- data/bin/prettify_json.rb +0 -16
- data/bin/pry +0 -16
- data/bin/rackup +0 -16
- data/bin/rake +0 -16
- data/bin/rdoc +0 -16
- data/bin/restclient +0 -16
- data/bin/ri +0 -16
- data/bin/rspec +0 -16
- data/bin/s3sh +0 -16
- data/bin/sequel +0 -16
- data/bin/serverspec-init +0 -16
- data/doc/AccessingSQL.md~ +0 -32
- data/doc/BulkFixup.md~ +0 -28
- data/doc/CommonTasks.md~ +0 -0
- data/doc/GETTING_STARTED.md~ +0 -6
- data/spec/chef_fixie/assoc_invite_spec.rb~ +0 -26
- data/spec/chef_fixie/check_org_associations_spec.rb~ +0 -34
- data/spec/chef_fixie/org_spec.rb~ +0 -53
@@ -18,45 +18,55 @@
|
|
18
18
|
# Author: Mark Anderson <mark@chef.io>
|
19
19
|
#
|
20
20
|
|
21
|
-
require_relative
|
22
|
-
require_relative
|
23
|
-
require_relative
|
24
|
-
require_relative
|
21
|
+
require_relative "config"
|
22
|
+
require_relative "authz_objects"
|
23
|
+
require_relative "authz_mapper"
|
24
|
+
require_relative "utility_helpers"
|
25
25
|
|
26
26
|
module ChefFixie
|
27
27
|
module CheckOrgAssociations
|
28
28
|
def self.orgs
|
29
29
|
@orgs ||= ChefFixie::Sql::Orgs.new
|
30
30
|
end
|
31
|
+
|
31
32
|
def self.users
|
32
33
|
@users ||= ChefFixie::Sql::Users.new
|
33
34
|
end
|
35
|
+
|
34
36
|
def self.assocs
|
35
37
|
@assocs ||= ChefFixie::Sql::Associations.new
|
36
38
|
end
|
39
|
+
|
37
40
|
def self.invites
|
38
41
|
invites ||= ChefFixie::Sql::Invites.new
|
39
42
|
end
|
40
43
|
|
41
44
|
def self.make_user(user)
|
42
45
|
if user.is_a?(String)
|
43
|
-
|
46
|
+
users[user]
|
44
47
|
elsif user.is_a?(ChefFixie::Sql::User)
|
45
|
-
|
48
|
+
user
|
46
49
|
else
|
47
50
|
raise "Expected a user, got a #{user.class}"
|
48
51
|
end
|
49
52
|
end
|
53
|
+
|
50
54
|
def self.make_org(org)
|
51
55
|
if org.is_a?(String)
|
52
|
-
|
56
|
+
orgs[org]
|
53
57
|
elsif org.is_a?(ChefFixie::Sql::Org)
|
54
|
-
|
58
|
+
org
|
55
59
|
else
|
56
60
|
raise "Expected an org, got a #{org.class}"
|
57
61
|
end
|
58
62
|
end
|
59
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
|
+
|
60
70
|
def self.check_association(org, user, global_admins = nil)
|
61
71
|
# magic to make usage easier
|
62
72
|
org = make_org(org)
|
@@ -78,7 +88,7 @@ module ChefFixie
|
|
78
88
|
return :user_not_in_usag
|
79
89
|
end
|
80
90
|
|
81
|
-
if !org.groups[
|
91
|
+
if !org.groups["users"].member?(usag)
|
82
92
|
return :usag_not_in_users
|
83
93
|
end
|
84
94
|
|
@@ -89,7 +99,7 @@ module ChefFixie
|
|
89
99
|
if invites.by_org_id_user_id(org.id, user.id)
|
90
100
|
return :zombie_invite
|
91
101
|
end
|
92
|
-
|
102
|
+
true
|
93
103
|
end
|
94
104
|
|
95
105
|
def self.fix_association(org, user, global_admins = nil)
|
@@ -98,7 +108,7 @@ module ChefFixie
|
|
98
108
|
user = users[user] if user.is_a?(String)
|
99
109
|
global_admins ||= org.global_admins
|
100
110
|
|
101
|
-
failure = check_association(org,user,global_admins)
|
111
|
+
failure = check_association(org, user, global_admins)
|
102
112
|
|
103
113
|
case failure
|
104
114
|
when true
|
@@ -108,14 +118,14 @@ module ChefFixie
|
|
108
118
|
usag.group_add(user)
|
109
119
|
when :usag_not_in_users
|
110
120
|
usag = org.groups[user.id]
|
111
|
-
org.groups[
|
121
|
+
org.groups["users"].group_add(usag)
|
112
122
|
when :global_admins_lacks_read
|
113
123
|
user.ace_add(:read, global_admins)
|
114
124
|
else
|
115
125
|
puts "#{org.name} #{user.name} can't fix problem #{failure} yet"
|
116
126
|
return false
|
117
127
|
end
|
118
|
-
|
128
|
+
true
|
119
129
|
end
|
120
130
|
|
121
131
|
def self.check_associations(org)
|
@@ -133,56 +143,54 @@ module ChefFixie
|
|
133
143
|
users_assoc = assocs.by_org_id(org.id).all(:all)
|
134
144
|
users_invite = invites.by_org_id(org.id).all(:all)
|
135
145
|
|
136
|
-
user_ids = users_assoc.map {|a| a.user_id }
|
137
|
-
users_in_org = user_ids.map {|i| users.by_id(i).all.first }
|
138
|
-
usernames = users_in_org.map {|u| u.name }
|
139
|
-
|
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 }
|
140
149
|
|
141
150
|
# check that users aren't both invited and associated
|
142
|
-
invited_ids = users_invite.map {|a| a.user_id }
|
151
|
+
invited_ids = users_invite.map { |a| a.user_id }
|
143
152
|
overlap_ids = user_ids & invited_ids
|
144
153
|
|
145
154
|
if !overlap_ids.empty?
|
146
|
-
overlap_names = overlap_ids.map {|i| users.by_id(i).all.first.name rescue "#{i}" }
|
147
|
-
puts "#{orgname} users both associated and invited: #{overlap_names.join(', ')
|
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(', ')}"
|
148
157
|
success = false
|
149
158
|
end
|
150
159
|
|
151
160
|
# Check that we don't have zombie USAGs left around (not 100% reliable)
|
152
161
|
# because someone could create a group that looks like a USAG
|
153
162
|
possible_usags = org.groups.list(:all) - user_ids
|
154
|
-
usags = possible_usags.select {|n| n =~ /^\h+{20}$/ }
|
163
|
+
usags = possible_usags.select { |n| n =~ /^\h+{20}$/ }
|
155
164
|
if !usags.empty?
|
156
|
-
puts "#{orgname} Suspicious USAGS without associated user #{usags.join(', ')
|
165
|
+
puts "#{orgname} Suspicious USAGS without associated user #{usags.join(', ')}"
|
157
166
|
end
|
158
167
|
|
159
168
|
# Check group membership for sanity
|
160
|
-
success &= check_group(org,
|
161
|
-
success &= check_group(org,
|
169
|
+
success &= check_group(org, "billing-admins", usernames)
|
170
|
+
success &= check_group(org, "admins", usernames)
|
162
171
|
|
163
172
|
# TODO check for non-usags in users!
|
164
|
-
users_members = org.groups[
|
165
|
-
users_actors = users_members[
|
173
|
+
users_members = org.groups["users"].group
|
174
|
+
users_actors = users_members["actors"] - [[:global, "pivotal"]]
|
166
175
|
if !users_actors.empty?
|
167
176
|
puts "#{orgname} has actors in it's users group #{users_actors}"
|
168
177
|
end
|
169
|
-
non_usags = users_members[
|
178
|
+
non_usags = users_members["groups"].map { |g| g[1] } - user_ids
|
170
179
|
if !non_usags.empty?
|
171
180
|
puts "#{orgname} warning: has non usags in it's users group #{non_usags.join(', ')}"
|
172
181
|
end
|
173
182
|
|
174
|
-
|
175
183
|
# Check individual associations
|
176
184
|
users_in_org.each do |user|
|
177
|
-
result =
|
178
|
-
if
|
185
|
+
result = check_association(org, user, global_admins)
|
186
|
+
if result != true
|
179
187
|
puts "Org #{orgname} Association check failed for #{user.name} #{result}"
|
180
188
|
success = false
|
181
189
|
end
|
182
190
|
end
|
183
191
|
|
184
192
|
puts "Org #{orgname} is #{success ? 'ok' : 'bad'} (#{users_in_org.count} users)"
|
185
|
-
|
193
|
+
success
|
186
194
|
end
|
187
195
|
|
188
196
|
# expect at least one current user to be in admins and billing admins
|
@@ -192,50 +200,40 @@ module ChefFixie
|
|
192
200
|
puts "#{orgname} Missing group #{groupname}"
|
193
201
|
return :no_such_group
|
194
202
|
end
|
195
|
-
actors = g.group[
|
203
|
+
actors = g.group["actors"].map { |x| x[1] }
|
196
204
|
live = actors & users
|
197
205
|
|
198
206
|
if live.count == 0
|
199
207
|
puts "Org #{org.name} has no active users in #{groupname}"
|
200
208
|
return false
|
201
209
|
end
|
202
|
-
|
210
|
+
true
|
203
211
|
end
|
204
212
|
|
205
|
-
|
206
|
-
## TODO: Port this
|
207
213
|
def self.remove_association(org, user)
|
208
214
|
# magic to make usage easier
|
209
|
-
org =
|
210
|
-
user =
|
215
|
+
org = make_org(org)
|
216
|
+
user = make_user(user)
|
211
217
|
|
212
218
|
# remove USAG
|
213
|
-
|
219
|
+
usag = org.groups[user.id]
|
220
|
+
usag.delete if usag
|
214
221
|
|
215
|
-
# remove
|
216
|
-
|
217
|
-
|
218
|
-
|
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
|
219
226
|
|
220
|
-
|
221
|
-
|
222
|
-
OrgMapper::RawAuth.put("actors/#{u_aid}/acl/read", read_ace)
|
227
|
+
# remove read ACE
|
228
|
+
user.ace_delete(:read, org.global_admins)
|
223
229
|
|
224
230
|
# remove association record
|
231
|
+
assoc = assocs.by_org_id_user_id(org.id, user.id)
|
232
|
+
assoc.delete if assoc
|
225
233
|
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
OrgMapper::CouchSupport.delete_account_doc(doc[:id])
|
230
|
-
|
231
|
-
# clean up excess invites
|
232
|
-
invites = OrgMapper::CouchSupport.invites_for_org(orgname)
|
233
|
-
invite_map = invites.inject({}) {|a,e| a[e[:name]] = e; a}
|
234
|
-
|
235
|
-
if invite_map.has_key?(username)
|
236
|
-
invite = invite_map[username]
|
237
|
-
OrgMapper::CouchSupport.delete_account_doc(invite[:id])
|
238
|
-
end
|
234
|
+
# remove any invites
|
235
|
+
invite = invites.by_org_id_user_id(org.id, user.id)
|
236
|
+
invite.delete if invite
|
239
237
|
end
|
240
238
|
end
|
241
239
|
end
|
data/lib/chef_fixie/config.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
#
|
2
|
-
# Copyright (c) 2014-2015 Chef Software Inc.
|
2
|
+
# Copyright (c) 2014-2015 Chef Software Inc.
|
3
3
|
# License :: Apache License, Version 2.0
|
4
4
|
#
|
5
5
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
@@ -18,9 +18,10 @@
|
|
18
18
|
#
|
19
19
|
# Much of this code was orginally derived from the orgmapper tool, which had many varied authors.
|
20
20
|
|
21
|
-
require
|
22
|
-
require
|
23
|
-
require
|
21
|
+
require "singleton"
|
22
|
+
require "ffi_yajl"
|
23
|
+
require "pathname"
|
24
|
+
require "veil"
|
24
25
|
|
25
26
|
module ChefFixie
|
26
27
|
def self.configure
|
@@ -29,11 +30,11 @@ module ChefFixie
|
|
29
30
|
|
30
31
|
def self.load_config(config_file = nil)
|
31
32
|
if config_file
|
32
|
-
puts "loading config: #{config_file}..."
|
33
|
+
puts "loading config: #{config_file}..." if ChefFixie::Console.started_from_command_line?
|
33
34
|
Kernel.load(config_file)
|
34
35
|
else
|
35
36
|
path = "/etc/opscode"
|
36
|
-
puts "loading config from #{path}"
|
37
|
+
puts "loading config from #{path}" if ChefFixie::Console.started_from_command_line?
|
37
38
|
ChefFixie::Config.instance.load_from_pc(path)
|
38
39
|
end
|
39
40
|
end
|
@@ -65,7 +66,7 @@ module ChefFixie
|
|
65
66
|
KEYS = [:authz_uri, :sql_database, :superuser_id, :pivotal_key]
|
66
67
|
KEYS.each { |k| attr_accessor k }
|
67
68
|
|
68
|
-
def merge_opts(opts={})
|
69
|
+
def merge_opts(opts = {})
|
69
70
|
opts.each do |key, value|
|
70
71
|
send("#{key}=".to_sym, value)
|
71
72
|
end
|
@@ -83,7 +84,7 @@ module ChefFixie
|
|
83
84
|
key_len > max ? key_len : max
|
84
85
|
end
|
85
86
|
KEYS.each do |key|
|
86
|
-
value = send(key) ||
|
87
|
+
value = send(key) || "default"
|
87
88
|
txt << "# %#{max_key_len}s: %s" % [key.to_s, value]
|
88
89
|
end
|
89
90
|
txt.join("\n")
|
@@ -101,26 +102,28 @@ module ChefFixie
|
|
101
102
|
def load_from_pc(dir = "/etc/opscode")
|
102
103
|
configdir = Pathname.new(dir)
|
103
104
|
|
104
|
-
config_files = %w
|
105
|
+
config_files = %w{chef-server-running.json}
|
105
106
|
config = load_json_from_path([configdir], config_files)
|
106
107
|
|
107
|
-
|
108
|
-
|
109
|
-
|
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"]
|
110
113
|
@authz_uri = "http://#{authz_vip}:#{authz_port}"
|
111
|
-
|
112
|
-
@superuser_id = authz_config[
|
113
|
-
|
114
|
-
sql_config = config[
|
115
|
-
erchef_config = config[
|
116
|
-
|
117
|
-
sql_user = sql_config[
|
118
|
-
sql_pw = sql_config[
|
119
|
-
sql_vip = sql_config[
|
120
|
-
sql_port = sql_config[
|
121
|
-
|
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
|
+
|
122
125
|
@sql_database = "postgres://#{sql_user}:#{sql_pw}@#{sql_vip}/opscode_chef"
|
123
|
-
|
126
|
+
|
124
127
|
@pivotal_key = configdir + "pivotal.pem"
|
125
128
|
end
|
126
129
|
|
@@ -136,5 +139,36 @@ module ChefFixie
|
|
136
139
|
end
|
137
140
|
end
|
138
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
|
+
|
139
173
|
end
|
140
174
|
end
|
data/lib/chef_fixie/console.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
#
|
2
|
-
# Copyright (c) 2015 Chef Software Inc.
|
2
|
+
# Copyright (c) 2015 Chef Software Inc.
|
3
3
|
# License :: Apache License, Version 2.0
|
4
4
|
#
|
5
5
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
@@ -18,18 +18,19 @@
|
|
18
18
|
#
|
19
19
|
# Much of this code was orginally derived from the orgmapper tool, which had many varied authors.
|
20
20
|
|
21
|
-
require
|
22
|
-
require
|
23
|
-
require
|
21
|
+
require "optparse"
|
22
|
+
require "pp"
|
23
|
+
require "pry"
|
24
24
|
|
25
|
-
require_relative
|
26
|
-
require_relative
|
25
|
+
require_relative "../chef_fixie"
|
26
|
+
require_relative "context"
|
27
27
|
|
28
28
|
module ChefFixie
|
29
29
|
module Console
|
30
30
|
extend self
|
31
31
|
|
32
32
|
def start
|
33
|
+
@@started_from_command_line = true
|
33
34
|
configure
|
34
35
|
ChefFixie.setup
|
35
36
|
configure_pry
|
@@ -46,9 +47,9 @@ module ChefFixie
|
|
46
47
|
options = {}
|
47
48
|
OptionParser.new do |opt|
|
48
49
|
opt.banner = "Usage: fixie [config] [options]"
|
49
|
-
opt.on(
|
50
|
-
opt.on("--sql_database DATABASE",
|
51
|
-
opt.on_tail(
|
50
|
+
opt.on("--authz_uri AUTH_URI", "The URI of the opscode authz service") { |v| options[:authz_uri] = v }
|
51
|
+
opt.on("--sql_database DATABASE", "The URI of the opscode_chef database") { |v| options[:sql_database] = v }
|
52
|
+
opt.on_tail("-h", "--help", "Show this message") do
|
52
53
|
puts opt
|
53
54
|
puts "\nExample configuration file:\n\n"
|
54
55
|
puts ChefFixie::Config.instance.example_config
|
@@ -67,7 +68,7 @@ module ChefFixie
|
|
67
68
|
Pry.config.history.file = "~/.fixie_history"
|
68
69
|
Pry.config.prompt_name = "fixie"
|
69
70
|
Pry::Commands.block_command("fixie-help", "Show fixie's help") do
|
70
|
-
|
71
|
+
output.puts(<<-HALP)
|
71
72
|
** ORGS **
|
72
73
|
* access with ORGS or ORGS
|
73
74
|
* access a specific org: ORGS['orgname']
|
@@ -87,5 +88,9 @@ HALP
|
|
87
88
|
end
|
88
89
|
end
|
89
90
|
|
91
|
+
def started_from_command_line?
|
92
|
+
@@started_from_command_line == true
|
93
|
+
end
|
94
|
+
|
90
95
|
end
|
91
96
|
end
|
data/lib/chef_fixie/context.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
#
|
2
|
-
# Copyright (c) 2015 Chef Software Inc.
|
2
|
+
# Copyright (c) 2015 Chef Software Inc.
|
3
3
|
# License :: Apache License, Version 2.0
|
4
4
|
#
|
5
5
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
@@ -18,9 +18,8 @@
|
|
18
18
|
#
|
19
19
|
# Much of this code was orginally derived from the orgmapper tool, which had many varied authors.
|
20
20
|
|
21
|
-
|
22
21
|
module ChefFixie
|
23
|
-
|
22
|
+
module Context
|
24
23
|
|
25
24
|
def describe_orgs
|
26
25
|
OrgMetrics.org_stats(orgs)
|
@@ -67,6 +66,5 @@ module ChefFixie
|
|
67
66
|
|
68
67
|
ChefFixie::Dissociator.dissociate_user(org, user)
|
69
68
|
end
|
70
|
-
|
71
69
|
end
|
72
70
|
end
|