chef_fixie 0.2.0 → 0.5.1

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.
Files changed (58) hide show
  1. checksums.yaml +5 -5
  2. data/bin/chef_fixie +1 -1
  3. data/doc/BulkFixup.md +1 -1
  4. data/doc/CommonTasks.md +14 -3
  5. data/lib/chef_fixie.rb +7 -7
  6. data/lib/chef_fixie/authz_mapper.rb +26 -28
  7. data/lib/chef_fixie/authz_objects.rb +51 -41
  8. data/lib/chef_fixie/bulk_edit_permissions.rb +24 -20
  9. data/lib/chef_fixie/check_org_associations.rb +56 -58
  10. data/lib/chef_fixie/config.rb +58 -23
  11. data/lib/chef_fixie/console.rb +15 -10
  12. data/lib/chef_fixie/context.rb +2 -4
  13. data/lib/chef_fixie/sql.rb +12 -12
  14. data/lib/chef_fixie/sql_objects.rb +74 -34
  15. data/lib/chef_fixie/utility_helpers.rb +13 -9
  16. data/lib/chef_fixie/version.rb +1 -1
  17. data/spec/chef_fixie/acl_spec.rb +23 -25
  18. data/spec/chef_fixie/assoc_invite_spec.rb +5 -8
  19. data/spec/chef_fixie/check_org_associations_spec.rb +14 -17
  20. data/spec/chef_fixie/groups_spec.rb +7 -11
  21. data/spec/chef_fixie/org_spec.rb +4 -5
  22. data/spec/chef_fixie/orgs_spec.rb +6 -9
  23. data/spec/spec_helper.rb +5 -6
  24. metadata +13 -51
  25. data/bin/bundler +0 -16
  26. data/bin/chef-apply +0 -16
  27. data/bin/chef-client +0 -16
  28. data/bin/chef-shell +0 -16
  29. data/bin/chef-solo +0 -16
  30. data/bin/chef-zero +0 -16
  31. data/bin/coderay +0 -16
  32. data/bin/edit_json.rb +0 -16
  33. data/bin/erubis +0 -16
  34. data/bin/ffi-yajl-bench +0 -16
  35. data/bin/fixie~ +0 -231
  36. data/bin/htmldiff +0 -16
  37. data/bin/knife +0 -16
  38. data/bin/ldiff +0 -16
  39. data/bin/net-dhcp +0 -16
  40. data/bin/ohai +0 -16
  41. data/bin/prettify_json.rb +0 -16
  42. data/bin/pry +0 -16
  43. data/bin/rackup +0 -16
  44. data/bin/rake +0 -16
  45. data/bin/rdoc +0 -16
  46. data/bin/restclient +0 -16
  47. data/bin/ri +0 -16
  48. data/bin/rspec +0 -16
  49. data/bin/s3sh +0 -16
  50. data/bin/sequel +0 -16
  51. data/bin/serverspec-init +0 -16
  52. data/doc/AccessingSQL.md~ +0 -32
  53. data/doc/BulkFixup.md~ +0 -28
  54. data/doc/CommonTasks.md~ +0 -0
  55. data/doc/GETTING_STARTED.md~ +0 -6
  56. data/spec/chef_fixie/assoc_invite_spec.rb~ +0 -26
  57. data/spec/chef_fixie/check_org_associations_spec.rb~ +0 -34
  58. data/spec/chef_fixie/org_spec.rb~ +0 -53
@@ -16,50 +16,53 @@
16
16
  #
17
17
  # Author: Mark Anderson <mark@chef.io>
18
18
  #
19
- require 'sequel'
19
+ require "sequel"
20
20
 
21
- require_relative 'config.rb'
22
- require_relative 'authz_objects.rb'
23
- require_relative 'authz_mapper.rb'
21
+ require_relative "config.rb"
22
+ require_relative "authz_objects.rb"
23
+ require_relative "authz_mapper.rb"
24
24
 
25
- require 'pp'
25
+ require "pp"
26
26
 
27
27
  module ChefFixie
28
28
  module BulkEditPermissions
29
29
  def self.orgs
30
30
  @orgs ||= ChefFixie::Sql::Orgs.new
31
31
  end
32
+
32
33
  def self.users
33
34
  @users ||= ChefFixie::Sql::Users.new
34
35
  end
36
+
35
37
  def self.assocs
36
38
  @assocs ||= ChefFixie::Sql::Associations.new
37
39
  end
40
+
38
41
  def self.invites
39
42
  invites ||= ChefFixie::Sql::Invites.new
40
43
  end
41
44
 
42
45
  def self.check_permissions(org)
43
46
  org = orgs[org] if org.is_a?(String)
44
- admins = org.groups['admins'].authz_id
45
- pivotal = users['pivotal'].authz_id
47
+ admins = org.groups["admins"].authz_id
48
+ pivotal = users["pivotal"].authz_id
46
49
  errors = Hash.new({})
47
50
  org.each_authz_object do |object|
48
- begin
51
+ begin
49
52
  acl = object.acl_raw
50
- rescue RestClient::ResourceNotFound=>e
53
+ rescue RestClient::ResourceNotFound => e
51
54
  puts "#{object.class} '#{object.name}' id '#{object.id}' missing authz info"
52
55
  # pp :object=>object, :e=>e
53
56
  next
54
57
  end
55
58
  broken_acl = {}
56
59
  # the one special case
57
- acl.each do |k,v|
60
+ acl.each do |k, v|
58
61
  list = []
59
- list << "pivotal" if !v['actors'].member?(pivotal)
62
+ list << "pivotal" if !v["actors"].member?(pivotal)
60
63
  # admins doesn't belong to the billing admins group
61
- if object.class != ChefFixie::Sql::Group || object.name != 'billing-admins'
62
- list << "admins" if !v['groups'].member?(admins)
64
+ if object.class != ChefFixie::Sql::Group || object.name != "billing-admins"
65
+ list << "admins" if !v["groups"].member?(admins)
63
66
  end
64
67
  broken_acl[k] = list if !list.empty?
65
68
  end
@@ -69,7 +72,7 @@ module ChefFixie
69
72
  errors[classname][object.name] = broken_acl
70
73
  end
71
74
  end
72
- return errors
75
+ errors
73
76
  end
74
77
 
75
78
  def self.ace_add(list, ace_type, entity)
@@ -78,17 +81,18 @@ module ChefFixie
78
81
  item.ace_add(ace_type, entity)
79
82
  else
80
83
  puts "item.class is not a native authz type"
81
- return
84
+ return nil
82
85
  end
83
86
  end
84
87
  end
88
+
85
89
  def self.ace_delete(list, ace_type, entity)
86
90
  list.each do |item|
87
91
  if item.respond_to?(:ace_delete)
88
92
  item.ace_delete(ace_type, entity)
89
93
  else
90
94
  puts "item.class is not a native authz type"
91
- return
95
+ return nil
92
96
  end
93
97
  end
94
98
  end
@@ -128,11 +132,11 @@ module ChefFixie
128
132
  def self.add_admin_permissions(org)
129
133
  org = orgs[org] if org.is_a?(String)
130
134
  # rework when ace add takes multiple items...
131
- admins = org.groups['admins']
132
- pivotal = users['pivotal']
135
+ admins = org.groups["admins"]
136
+ pivotal = users["pivotal"]
133
137
  org.each_authz_object do |object|
134
138
  object.ace_add(:all, pivotal)
135
- if object.class != ChefFixie::Sql::Group || object.name != 'billing-admins'
139
+ if object.class != ChefFixie::Sql::Group || object.name != "billing-admins"
136
140
  object.ace_add(:all, admins)
137
141
  end
138
142
  end
@@ -150,7 +154,7 @@ module ChefFixie
150
154
  puts "#{obj.name} from #{c.name}"
151
155
  end
152
156
  end
153
- return
157
+ nil
154
158
  end
155
159
 
156
160
  end
@@ -18,45 +18,55 @@
18
18
  # Author: Mark Anderson <mark@chef.io>
19
19
  #
20
20
 
21
- require_relative 'config'
22
- require_relative 'authz_objects'
23
- require_relative 'authz_mapper'
24
- require_relative 'utility_helpers'
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
- return users[user]
46
+ users[user]
44
47
  elsif user.is_a?(ChefFixie::Sql::User)
45
- return user
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
- return orgs[org]
56
+ orgs[org]
53
57
  elsif org.is_a?(ChefFixie::Sql::Org)
54
- return org
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['users'].member?(usag)
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
- return true
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['users'].group_add(usag)
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
- return true
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, 'billing-admins', usernames)
161
- success &= check_group(org, 'admins', usernames)
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['users'].group
165
- users_actors = users_members['actors'] - [[:global, "pivotal"]]
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['groups'].map {|g| g[1] } - user_ids
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 = self.check_association(org,user,global_admins)
178
- if (result != true)
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
- return success
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['actors'].map {|x| x[1] }
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
- return true
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 = orgs[org] if org.is_a?(String)
210
- user = users[user] if user.is_a?(String)
215
+ org = make_org(org)
216
+ user = make_user(user)
211
217
 
212
218
  # remove USAG
213
- delete_usag_for_user(orgname,username)
219
+ usag = org.groups[user.id]
220
+ usag.delete if usag
214
221
 
215
- # remove read ACE
216
- u_aid = user.authz_id
217
- ga = OrgMapper::CouchSupport.doc_from_view("#{orgname}_global_admins", "#{Group}/by_groupname")
218
- ga_aid = user_to_authz(ga["_id"])
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
- read_ace = OrgMapper::RawAuth.get("actors/#{u_aid}/acl/read")
221
- read_ace["groups"] -= [ga_aid]
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
- org_assoc = OrgMapper::CouchSupport.associations_for_org(orgname)
227
- doc = org_assoc.select {|x| x[:uid] == user.id}.first
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
@@ -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 'singleton'
22
- require 'ffi_yajl'
23
- require 'pathname'
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) || 'default'
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,25 +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(chef-server-running.json)
105
+ config_files = %w{chef-server-running.json}
105
106
  config = load_json_from_path([configdir], config_files)
106
107
 
107
- authz_config = config['private_chef']['oc_bifrost']
108
- authz_vip = authz_config['vip']
109
- authz_port = authz_config['port']
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['superuser_id']
113
-
114
- sql_config = config['private_chef']['postgresql']
115
-
116
- sql_user = sql_config['sql_user']
117
- sql_pw = sql_config['sql_password']
118
- sql_vip = sql_config['vip']
119
- sql_port = sql_config['port']
120
-
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
+
121
125
  @sql_database = "postgres://#{sql_user}:#{sql_pw}@#{sql_vip}/opscode_chef"
122
-
126
+
123
127
  @pivotal_key = configdir + "pivotal.pem"
124
128
  end
125
129
 
@@ -135,5 +139,36 @@ module ChefFixie
135
139
  end
136
140
  end
137
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
+
138
173
  end
139
174
  end