knife-tidy 0.1.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +13 -3
- data/README.md +5 -5
- data/Rakefile +1 -1
- data/conf/substitutions.json.example +2 -2
- data/lib/chef/knife/tidy_backup_clean.rb +62 -30
- data/lib/chef/knife/tidy_base.rb +0 -49
- data/lib/chef/tidy_acls.rb +180 -0
- data/lib/chef/tidy_common.rb +70 -0
- data/lib/chef/tidy_substitutions.rb +4 -8
- data/lib/knife-tidy/version.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2bc910eba99a7cccb3e6ca423da6c116f1fd09af
|
4
|
+
data.tar.gz: fc67a3f6dd6f653e28336f6907e409b1dc6934c3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 133361ea06a8bc562de3d149e3b0e523627ab3bbdccbdac8d5a8e4205d0acaadfa249395403f9d2659de82b7cb34024e29affbc3d17cf63a523dc7a69027d560
|
7
|
+
data.tar.gz: a80bd192038fb73f4b375098f0958cdbd537c5d4321d0dc8f14251446788429145709016080fcb83edcc7ae2ed6363625cd975bbbe3c46e662d7094d6f172db9
|
data/CHANGELOG.md
CHANGED
@@ -1,12 +1,22 @@
|
|
1
1
|
# Change Log
|
2
2
|
|
3
|
-
## [0.1.
|
4
|
-
[Full Changelog](https://github.com/jeremymv2/knife-tidy/compare/0.
|
3
|
+
## [0.1.0](https://github.com/jeremymv2/knife-tidy/tree/0.1.0) (2017-08-15)
|
4
|
+
[Full Changelog](https://github.com/jeremymv2/knife-tidy/compare/0.2.0...0.1.0)
|
5
5
|
|
6
6
|
**Merged pull requests:**
|
7
7
|
|
8
|
+
- bump version to 0.2.0 [\#6](https://github.com/jeremymv2/knife-tidy/pull/6) ([jeremymv2](https://github.com/jeremymv2))
|
9
|
+
|
10
|
+
## [0.2.0](https://github.com/jeremymv2/knife-tidy/tree/0.2.0) (2017-08-16)
|
11
|
+
[Full Changelog](https://github.com/jeremymv2/knife-tidy/compare/0.1.1...0.2.0)
|
12
|
+
|
13
|
+
**Merged pull requests:**
|
14
|
+
|
15
|
+
- moved all common functions to tidy\_common.rb [\#5](https://github.com/jeremymv2/knife-tidy/pull/5) ([jeremymv2](https://github.com/jeremymv2))
|
16
|
+
- Jeremymv2/acl items [\#4](https://github.com/jeremymv2/knife-tidy/pull/4) ([jeremymv2](https://github.com/jeremymv2))
|
17
|
+
- updated changelog [\#3](https://github.com/jeremymv2/knife-tidy/pull/3) ([jeremymv2](https://github.com/jeremymv2))
|
8
18
|
- bump version to 0.1.1 [\#2](https://github.com/jeremymv2/knife-tidy/pull/2) ([jeremymv2](https://github.com/jeremymv2))
|
9
19
|
|
10
20
|
|
11
21
|
|
12
|
-
\* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)*
|
22
|
+
\* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)*
|
data/README.md
CHANGED
@@ -31,7 +31,7 @@ The following options are supported across all subcommands:
|
|
31
31
|
* `--orgs ORG1,ORG2`:
|
32
32
|
Only apply to objects in the named organizations (default: all orgs)
|
33
33
|
|
34
|
-
|
34
|
+
## $ knife tidy server report (options)
|
35
35
|
|
36
36
|
Cookbooks and nodes account for the largest objects in your Chef Server.
|
37
37
|
If you want to keep it lean and mean and easy to port the object data, you must
|
@@ -51,7 +51,7 @@ org_threshold_numdays_stale_nodes.json | Nodes in that org that have not checked
|
|
51
51
|
org_cookbook_count.json | Number of cookbook versions for each cookbook that that org.
|
52
52
|
org_unused_cookbooks.json | List of cookbooks and versions that do not appear to be in-use for that org. This is determined by checking the versioned run list of each of the nodes in the org.
|
53
53
|
|
54
|
-
|
54
|
+
## $ knife tidy backup clean (options)
|
55
55
|
|
56
56
|
## Options
|
57
57
|
|
@@ -90,9 +90,9 @@ org_unused_cookbooks.json | List of cookbooks and versions that do not appear to
|
|
90
90
|
* DONE: metadata self-dependency correction
|
91
91
|
* DONE: user email validation
|
92
92
|
* DONE: ensure user emails do not cause primary key violation
|
93
|
-
*
|
94
|
-
*
|
95
|
-
*
|
93
|
+
* DONE: ambiguous actors (acl actor exists as client and user)
|
94
|
+
* DONE: users/clients referenced as actors in acls that do not exist in users/clients
|
95
|
+
* DONE: nonexistent groups referenced in acls
|
96
96
|
|
97
97
|
## Summary and Credits
|
98
98
|
|
data/Rakefile
CHANGED
@@ -2,12 +2,12 @@
|
|
2
2
|
"chef-sugar":{
|
3
3
|
"organizations/*/cookbooks/chef-sugar*/metadata.rb":[
|
4
4
|
{
|
5
|
-
"pattern":"require
|
5
|
+
"pattern":"^require .*/lib/chef/sugar/version",
|
6
6
|
"replace":"# require File.expand_path('../lib/chef/sugar/version', __FILE__)"
|
7
7
|
},
|
8
8
|
{
|
9
9
|
"pattern":"version *Chef::Sugar::VERSION",
|
10
|
-
"replace":"
|
10
|
+
"replace":"version !COOKBOOK_VERSION!"
|
11
11
|
}
|
12
12
|
]
|
13
13
|
}
|
@@ -4,15 +4,17 @@ class Chef
|
|
4
4
|
class Knife
|
5
5
|
class TidyBackupClean < Knife
|
6
6
|
|
7
|
-
include Knife::TidyBase
|
8
|
-
|
9
7
|
deps do
|
10
8
|
require 'chef/cookbook_loader'
|
11
9
|
require 'chef/cookbook/metadata'
|
12
10
|
require 'chef/tidy_substitutions'
|
11
|
+
require 'chef/tidy_acls'
|
12
|
+
require 'chef/tidy_common'
|
13
13
|
require 'ffi_yajl'
|
14
14
|
end
|
15
15
|
|
16
|
+
include Knife::TidyBase
|
17
|
+
|
16
18
|
option :backup_path,
|
17
19
|
:long => '--backup-path path/to/backup',
|
18
20
|
:description => 'The path to the knife-ec-backup backup directory'
|
@@ -22,75 +24,72 @@ class Chef
|
|
22
24
|
:description => 'The path to the file used for substitutions. If non-existant, a boiler plate one will be created.'
|
23
25
|
|
24
26
|
def run
|
25
|
-
unless config[:backup_path]
|
26
|
-
ui.error 'Must specify --backup-path'
|
27
|
+
unless config[:backup_path] && ::File.directory?(config[:backup_path])
|
28
|
+
ui.error 'Must specify valid --backup-path'
|
27
29
|
exit 1
|
28
30
|
end
|
29
31
|
|
30
|
-
validate_user_emails
|
32
|
+
validate_user_emails
|
31
33
|
|
32
34
|
if config[:gsub_file]
|
33
35
|
unless ::File.exist?(config[:gsub_file])
|
34
36
|
Chef::TidySubstitutions.new(substitutions_file).boiler_plate
|
35
37
|
exit
|
36
38
|
else
|
37
|
-
Chef::TidySubstitutions.new(substitutions_file,
|
39
|
+
Chef::TidySubstitutions.new(substitutions_file, tidy).run_substitutions
|
38
40
|
end
|
39
41
|
end
|
40
42
|
|
41
43
|
orgs.each do |org|
|
44
|
+
org_acls = Chef::TidyOrgAcls.new(tidy, org)
|
45
|
+
org_acls.validate_acls
|
46
|
+
org_acls.validate_user_acls
|
42
47
|
fix_self_dependencies(org)
|
43
48
|
load_cookbooks(org)
|
44
49
|
generate_new_metadata(org)
|
45
50
|
end
|
46
51
|
end
|
47
52
|
|
48
|
-
def
|
53
|
+
def tidy
|
54
|
+
@tidy ||= Chef::TidyCommon.new(config[:backup_path])
|
55
|
+
end
|
56
|
+
|
57
|
+
def validate_user_emails
|
49
58
|
emails_seen = []
|
50
|
-
|
59
|
+
tidy.global_user_names.each do |user|
|
51
60
|
email = ''
|
52
61
|
ui.info "Validating #{user}"
|
53
|
-
the_user = FFI_Yajl::Parser.parse(::File.read(::File.join(
|
62
|
+
the_user = FFI_Yajl::Parser.parse(::File.read(::File.join(tidy.users_path, "#{user}.json")), symbolize_names: false)
|
54
63
|
if the_user['email'].match(/\A[^@\s]+@[^@\s]+\z/)
|
55
64
|
if emails_seen.include?(the_user['email'])
|
56
65
|
ui.info "Already saw #{user}'s email, creating a unique one."
|
57
|
-
email = unique_email
|
66
|
+
email = tidy.unique_email
|
58
67
|
new_user = the_user.dup
|
59
68
|
new_user['email'] = email
|
60
|
-
save_user(new_user)
|
69
|
+
tidy.save_user(new_user)
|
61
70
|
emails_seen.push(email)
|
62
71
|
else
|
63
72
|
emails_seen.push(the_user['email'])
|
64
73
|
end
|
65
74
|
else
|
66
75
|
ui.info "User #{user} does not have a valid email, creating a unique one."
|
67
|
-
email = unique_email
|
76
|
+
email = tidy.unique_email
|
68
77
|
new_user = the_user.dup
|
69
78
|
new_user['email'] = email
|
70
|
-
save_user(new_user)
|
79
|
+
tidy.save_user(new_user)
|
71
80
|
emails_seen.push(email)
|
72
81
|
end
|
73
82
|
end
|
74
83
|
end
|
75
84
|
|
76
|
-
def unique_email
|
77
|
-
(0...8).map { (65 + rand(26)).chr }.join.downcase +
|
78
|
-
'@' + (0...8).map { (65 + rand(26)).chr }.join.downcase + '.com'
|
79
|
-
end
|
80
|
-
|
81
|
-
def save_user(user)
|
82
|
-
::File.open(::File.join(global_users_path_expanded, "#{user['username']}.json"), 'w+') do |f|
|
83
|
-
f.write(FFI_Yajl::Encoder.encode(user, pretty: true))
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|
87
85
|
def load_cookbooks(org)
|
88
|
-
cl = Chef::CookbookLoader.new(
|
86
|
+
cl = Chef::CookbookLoader.new(tidy.cookbooks_path(org))
|
89
87
|
for_each_cookbook_basename(org) do |cookbook|
|
90
88
|
ui.info "Loading #{cookbook}"
|
91
89
|
ret = cl.load_cookbook(cookbook)
|
92
90
|
if ret.nil?
|
93
|
-
ui.
|
91
|
+
ui.warn "Something's wrong with the #{cookbook} cookbook - cannot load it! Moving to cookbooks.broken folder."
|
92
|
+
broken_cookooks_add(org, cookbook)
|
94
93
|
end
|
95
94
|
end
|
96
95
|
rescue LoadError => e
|
@@ -99,15 +98,23 @@ class Chef
|
|
99
98
|
exit 1
|
100
99
|
end
|
101
100
|
|
101
|
+
def broken_cookooks_add(org, cookbook)
|
102
|
+
broken_path = ::File.join(tidy.org_path(org), 'cookbooks.broken')
|
103
|
+
FileUtils.mkdir(broken_path) unless ::File.directory?(broken_path)
|
104
|
+
Dir[::File.join(tidy.cookbooks_path(org), "#{cookbook}*")].each do |cb|
|
105
|
+
FileUtils.mv(cb, broken_path, :verbose => true, :force => true)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
102
109
|
def generate_new_metadata(org)
|
103
110
|
for_each_cookbook_path(org) do |cookbook_path|
|
104
|
-
generate_metadata_from_file(cookbook_name_from_path(cookbook_path), cookbook_path)
|
111
|
+
generate_metadata_from_file(tidy.cookbook_name_from_path(cookbook_path), cookbook_path)
|
105
112
|
end
|
106
113
|
end
|
107
114
|
|
108
115
|
def fix_self_dependencies(org)
|
109
116
|
for_each_cookbook_path(org) do |cookbook_path|
|
110
|
-
name = cookbook_name_from_path(cookbook_path)
|
117
|
+
name = tidy.cookbook_name_from_path(cookbook_path)
|
111
118
|
md_path = ::File.join(cookbook_path, 'metadata.rb')
|
112
119
|
unless ::File.exist?(md_path)
|
113
120
|
ui.warn "No metadata.rb in #{cookbook_path} - skipping"
|
@@ -142,8 +149,33 @@ class Chef
|
|
142
149
|
exit 1
|
143
150
|
end
|
144
151
|
|
145
|
-
def
|
146
|
-
|
152
|
+
def substitutions_file
|
153
|
+
@substitutions_file ||= ::File.expand_path(config[:gsub_file])
|
154
|
+
end
|
155
|
+
|
156
|
+
def orgs
|
157
|
+
@orgs ||= if config[:org_list]
|
158
|
+
config[:org_list].split(',')
|
159
|
+
else
|
160
|
+
Dir[::File.join(tidy.backup_path, 'organizations', '*')].map { |dir| ::File.basename(dir) }
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
def for_each_cookbook_basename(org)
|
165
|
+
cookbooks_seen = []
|
166
|
+
Dir[::File.join(tidy.cookbooks_path(org), '**-**')].each do |cookbook|
|
167
|
+
name = tidy.cookbook_name_from_path(cookbook)
|
168
|
+
unless cookbooks_seen.include?(name)
|
169
|
+
cookbooks_seen.push(name)
|
170
|
+
yield name
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
def for_each_cookbook_path(org)
|
176
|
+
Dir[::File.join(tidy.cookbooks_path(org), '**')].each do |cookbook|
|
177
|
+
yield cookbook
|
178
|
+
end
|
147
179
|
end
|
148
180
|
end
|
149
181
|
end
|
data/lib/chef/knife/tidy_base.rb
CHANGED
@@ -47,55 +47,6 @@ class Chef
|
|
47
47
|
def rest
|
48
48
|
@rest ||= Chef::ServerAPI.new(server.root_url, {:api_version => "0"})
|
49
49
|
end
|
50
|
-
|
51
|
-
def backup_path_expanded
|
52
|
-
::File.expand_path(config[:backup_path])
|
53
|
-
end
|
54
|
-
|
55
|
-
def cookbook_name_from_path(path)
|
56
|
-
::File.basename(path, '-*')
|
57
|
-
end
|
58
|
-
|
59
|
-
def cookbooks_path_expanded(org)
|
60
|
-
::File.expand_path(::File.join(backup_path_expanded, 'organizations', org, 'cookbooks'))
|
61
|
-
end
|
62
|
-
|
63
|
-
def global_users_path_expanded
|
64
|
-
::File.expand_path(::File.join(backup_path_expanded, 'users'))
|
65
|
-
end
|
66
|
-
|
67
|
-
def substitutions_file
|
68
|
-
::File.expand_path(config[:gsub_file])
|
69
|
-
end
|
70
|
-
|
71
|
-
def global_users
|
72
|
-
Dir[::File.join(backup_path_expanded, 'users', '*')].map { |dir| ::File.basename(dir, '.json') }
|
73
|
-
end
|
74
|
-
|
75
|
-
def orgs
|
76
|
-
if config[:org_list]
|
77
|
-
config[:org_list].split(',')
|
78
|
-
else
|
79
|
-
Dir[::File.join(backup_path_expanded, 'organizations', '*')].map { |dir| ::File.basename(dir) }
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
def for_each_cookbook_basename(org)
|
84
|
-
cookbooks_seen = []
|
85
|
-
Dir[::File.join(cookbooks_path_expanded(org), '**-**')].each do |cookbook|
|
86
|
-
name = cookbook_name_from_path(cookbook)
|
87
|
-
unless cookbooks_seen.include?(name)
|
88
|
-
cookbooks_seen.push(name)
|
89
|
-
yield name
|
90
|
-
end
|
91
|
-
end
|
92
|
-
end
|
93
|
-
|
94
|
-
def for_each_cookbook_path(org)
|
95
|
-
Dir[::File.join(cookbooks_path_expanded(org), '**')].each do |cookbook|
|
96
|
-
yield cookbook
|
97
|
-
end
|
98
|
-
end
|
99
50
|
end
|
100
51
|
end
|
101
52
|
end
|
@@ -0,0 +1,180 @@
|
|
1
|
+
require 'ffi_yajl'
|
2
|
+
require 'fileutils'
|
3
|
+
require 'chef/log'
|
4
|
+
|
5
|
+
class Chef
|
6
|
+
class TidyOrgAcls
|
7
|
+
attr_accessor :members, :clients, :groups, :users
|
8
|
+
|
9
|
+
def initialize(tidy, org)
|
10
|
+
@tidy = tidy
|
11
|
+
@backup_path = @tidy.backup_path
|
12
|
+
@org = org
|
13
|
+
@clients = []
|
14
|
+
@members = []
|
15
|
+
@groups = []
|
16
|
+
@users = []
|
17
|
+
load_actors
|
18
|
+
end
|
19
|
+
|
20
|
+
def load_users
|
21
|
+
Chef::Log.warn "Loading users"
|
22
|
+
Dir[::File.join(@tidy.users_path, '*.json')].each do |user|
|
23
|
+
@users.push(FFI_Yajl::Parser.parse(::File.read(user), symbolize_names: true))
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def load_members
|
28
|
+
Chef::Log.info "Loading members for #{@org}"
|
29
|
+
@members = FFI_Yajl::Parser.parse(::File.read(@tidy.members_path(@org)), symbolize_names: true)
|
30
|
+
end
|
31
|
+
|
32
|
+
def load_clients
|
33
|
+
Chef::Log.info "Loading clients for #{@org}"
|
34
|
+
Dir[::File.join(@tidy.clients_path(@org), '*.json')].each do |client|
|
35
|
+
@clients.push(FFI_Yajl::Parser.parse(::File.read(client), symbolize_names: true))
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def load_groups
|
40
|
+
Chef::Log.info "Loading groups for #{@org}"
|
41
|
+
Dir[::File.join(@tidy.groups_path(@org), '*.json')].each do |group|
|
42
|
+
@groups.push(FFI_Yajl::Parser.parse(::File.read(group), symbolize_names: true))
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def load_actors
|
47
|
+
load_users
|
48
|
+
load_members
|
49
|
+
load_clients
|
50
|
+
load_groups
|
51
|
+
Chef::Log.info "#{@org} Actors loaded!"
|
52
|
+
end
|
53
|
+
|
54
|
+
def acl_ops
|
55
|
+
%w( create read update delete grant )
|
56
|
+
end
|
57
|
+
|
58
|
+
def acl_actors_groups(acl)
|
59
|
+
actors_seen = []
|
60
|
+
groups_seen = []
|
61
|
+
acl_ops.each do |op|
|
62
|
+
acl[op]['actors'].each do |actor|
|
63
|
+
actors_seen.push(actor) unless actors_seen.include?(actor)
|
64
|
+
end
|
65
|
+
acl[op]['groups'].each do |group|
|
66
|
+
groups_seen.push(group) unless groups_seen.include?(group)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
{ actors: actors_seen, groups: groups_seen }
|
70
|
+
end
|
71
|
+
|
72
|
+
def valid_org_member?(actor)
|
73
|
+
! @members.select { |user| user[:user][:username] == actor }.empty?
|
74
|
+
end
|
75
|
+
|
76
|
+
def valid_org_client?(actor)
|
77
|
+
! @clients.select { |client| client[:name] == actor }.empty?
|
78
|
+
end
|
79
|
+
|
80
|
+
def valid_global_user?(actor)
|
81
|
+
! @users.select { |user| user[:username] == actor }.empty?
|
82
|
+
end
|
83
|
+
|
84
|
+
def invalid_group?(actor)
|
85
|
+
@groups.select { |group| group[:name] == actor }.empty? &&
|
86
|
+
actor != '::server-admins' &&
|
87
|
+
actor != "::#{@org}_read_access_group"
|
88
|
+
end
|
89
|
+
|
90
|
+
def ambiguous_actor?(actor)
|
91
|
+
valid_org_member?(actor) && valid_org_client?(actor)
|
92
|
+
end
|
93
|
+
|
94
|
+
def missing_from_members?(actor)
|
95
|
+
valid_global_user?(actor) && !valid_org_member?(actor) && !valid_org_client?(actor)
|
96
|
+
end
|
97
|
+
|
98
|
+
def missing_org_client?(actor)
|
99
|
+
!valid_global_user?(actor) && !valid_org_member?(actor) && !valid_org_client?(actor)
|
100
|
+
end
|
101
|
+
|
102
|
+
def org_acls
|
103
|
+
@org_acls ||= Dir[::File.join(@tidy.org_acls_path(@org), '**.json')] +
|
104
|
+
Dir[::File.join(@tidy.org_acls_path(@org), '**', '*.json')]
|
105
|
+
end
|
106
|
+
|
107
|
+
def fix_ambiguous_actor(actor)
|
108
|
+
Chef::Log.warn "Ambiguous actor! #{actor} removing from #{@tidy.members_path(@org)}"
|
109
|
+
remove_user_from_org(actor)
|
110
|
+
end
|
111
|
+
|
112
|
+
def add_client_to_org(actor)
|
113
|
+
# TODO
|
114
|
+
Chef::Log.warn "Client referenced in acl non-existant: #{actor}"
|
115
|
+
end
|
116
|
+
|
117
|
+
def add_actor_to_members(actor)
|
118
|
+
Chef::Log.warn "Invalid actor: #{actor} adding to #{@tidy.members_path(@org)}"
|
119
|
+
user = { user: { username: actor } }
|
120
|
+
@members.push(user)
|
121
|
+
write_new_file(@members, @tidy.members_path(@org))
|
122
|
+
end
|
123
|
+
|
124
|
+
def write_new_file(contents, path)
|
125
|
+
FileUtils.cp(path, "#{path}.orig") unless ::File.exist?("#{path}.orig")
|
126
|
+
::File.open(path, 'w+') do |f|
|
127
|
+
f.write(FFI_Yajl::Encoder.encode(contents, pretty: true))
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
def remove_user_from_org(actor)
|
132
|
+
@members.reject! { |user| user[:user][:username] == actor }
|
133
|
+
write_new_file(@members, @tidy.members_path(@org))
|
134
|
+
end
|
135
|
+
|
136
|
+
def remove_group_from_acl(group, acl_file)
|
137
|
+
Chef::Log.warn "Removing invalid group: #{group} from #{acl_file}"
|
138
|
+
acl = FFI_Yajl::Parser.parse(::File.read(acl_file), symbolize_names: false)
|
139
|
+
acl_ops.each do |op|
|
140
|
+
acl[op]['groups'].reject! { |the_group| the_group == group }
|
141
|
+
end
|
142
|
+
write_new_file(acl, acl_file)
|
143
|
+
end
|
144
|
+
|
145
|
+
def validate_acls
|
146
|
+
org_acls.each do |acl_file|
|
147
|
+
acl = FFI_Yajl::Parser.parse(::File.read(acl_file), symbolize_names: false)
|
148
|
+
actors_groups = acl_actors_groups(acl)
|
149
|
+
actors_groups[:actors].each do |actor|
|
150
|
+
next if actor == 'pivotal'
|
151
|
+
if ambiguous_actor?(actor)
|
152
|
+
fix_ambiguous_actor(actor)
|
153
|
+
elsif missing_from_members?(actor)
|
154
|
+
add_actor_to_members(actor)
|
155
|
+
elsif missing_org_client?(actor)
|
156
|
+
add_client_to_org(actor)
|
157
|
+
end
|
158
|
+
end
|
159
|
+
actors_groups[:groups].each do |group|
|
160
|
+
if invalid_group?(group)
|
161
|
+
remove_group_from_acl(group, acl_file)
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
def validate_user_acls
|
168
|
+
@members.each do |member|
|
169
|
+
user_acl_path = ::File.join(@tidy.user_acls_path, "#{member[:user][:username]}.json")
|
170
|
+
user_acl = FFI_Yajl::Parser.parse(::File.read(user_acl_path), symbolize_names: false)
|
171
|
+
actors_groups = acl_actors_groups(user_acl)
|
172
|
+
actors_groups[:groups].each do |group|
|
173
|
+
if invalid_group?(group)
|
174
|
+
remove_group_from_acl(group, user_acl_path)
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'ffi_yajl'
|
2
|
+
require 'fileutils'
|
3
|
+
|
4
|
+
class Chef
|
5
|
+
class TidyCommon
|
6
|
+
attr_accessor :backup_path
|
7
|
+
|
8
|
+
def initialize(backup_path)
|
9
|
+
@backup_path = ::File.expand_path(backup_path)
|
10
|
+
end
|
11
|
+
|
12
|
+
def users_path
|
13
|
+
@users_path ||= File.expand_path(::File.join(@backup_path, 'users'))
|
14
|
+
end
|
15
|
+
|
16
|
+
def members_path(org)
|
17
|
+
::File.expand_path(::File.join(@backup_path, 'organizations', org, 'members.json'))
|
18
|
+
end
|
19
|
+
|
20
|
+
def clients_path(org)
|
21
|
+
::File.expand_path(::File.join(@backup_path, 'organizations', org, 'clients'))
|
22
|
+
end
|
23
|
+
|
24
|
+
def groups_path(org)
|
25
|
+
::File.expand_path(::File.join(@backup_path, 'organizations', org, 'groups'))
|
26
|
+
end
|
27
|
+
|
28
|
+
def org_acls_path(org)
|
29
|
+
::File.expand_path(::File.join(@backup_path, 'organizations', org, 'acls'))
|
30
|
+
end
|
31
|
+
|
32
|
+
def user_acls_path
|
33
|
+
@user_acls_path ||= ::File.expand_path(::File.join(@backup_path, 'user_acls'))
|
34
|
+
end
|
35
|
+
|
36
|
+
def cookbooks_path(org)
|
37
|
+
::File.expand_path(::File.join(@backup_path, 'organizations', org, 'cookbooks'))
|
38
|
+
end
|
39
|
+
|
40
|
+
def org_path(org)
|
41
|
+
::File.expand_path(::File.join(@backup_path, 'organizations', org))
|
42
|
+
end
|
43
|
+
|
44
|
+
def unique_email
|
45
|
+
(0...8).map { (65 + rand(26)).chr }.join.downcase +
|
46
|
+
'@' + (0...8).map { (65 + rand(26)).chr }.join.downcase + '.com'
|
47
|
+
end
|
48
|
+
|
49
|
+
def save_user(user)
|
50
|
+
::File.open(::File.join(users_path, "#{user['username']}.json"), 'w+') do |f|
|
51
|
+
f.write(FFI_Yajl::Encoder.encode(user, pretty: true))
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def write_new_file(contents, path)
|
56
|
+
FileUtils.cp(path, "#{path}.orig") unless ::File.exist?("#{path}.orig")
|
57
|
+
::File.open(path, 'w+') do |f|
|
58
|
+
f.write(FFI_Yajl::Encoder.encode(contents, pretty: true))
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def cookbook_name_from_path(path)
|
63
|
+
::File.basename(path, '-*')
|
64
|
+
end
|
65
|
+
|
66
|
+
def global_user_names
|
67
|
+
@global_user_names ||= Dir[::File.join(@backup_path, 'users', '*')].map { |dir| ::File.basename(dir, '.json') }
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -9,15 +9,11 @@ class Chef
|
|
9
9
|
|
10
10
|
attr_accessor :file_path, :backup_path, :data
|
11
11
|
|
12
|
-
def initialize(file_path = nil,
|
12
|
+
def initialize(file_path = nil, tidy_common = nil)
|
13
13
|
@file_path = file_path
|
14
|
-
@backup_path = backup_path
|
14
|
+
@backup_path = tidy_common.backup_path if tidy_common
|
15
15
|
end
|
16
16
|
|
17
|
-
# Load the substitutions from disk
|
18
|
-
#
|
19
|
-
# @return [Hash]
|
20
|
-
#
|
21
17
|
def load_data
|
22
18
|
Chef::Log.info "Loading substitutions from #{file_path}"
|
23
19
|
@data = FFI_Yajl::Parser.parse(::File.read(@file_path), symbolize_names: false)
|
@@ -53,7 +49,7 @@ class Chef
|
|
53
49
|
end
|
54
50
|
end
|
55
51
|
temp_file.close
|
56
|
-
FileUtils.
|
52
|
+
FileUtils.cp(path, "#{path}.orig") unless ::File.exist?("#{path}.orig")
|
57
53
|
FileUtils.mv(temp_file.path, path)
|
58
54
|
ensure
|
59
55
|
temp_file.close
|
@@ -66,7 +62,7 @@ class Chef
|
|
66
62
|
@data.keys.each do |entry|
|
67
63
|
@data[entry].keys.each do |glob|
|
68
64
|
Chef::Log.info "Running substitutions for #{entry} -> #{glob}"
|
69
|
-
Dir[::File.join(backup_path, glob)].each do |file|
|
65
|
+
Dir[::File.join(@backup_path, glob)].each do |file|
|
70
66
|
@data[entry][glob].each do |substitution|
|
71
67
|
search = Regexp.new(substitution['pattern'])
|
72
68
|
replace = substitution['replace'].dup
|
data/lib/knife-tidy/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: knife-tidy
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jeremy Miller
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-08-
|
11
|
+
date: 2017-08-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -113,6 +113,8 @@ files:
|
|
113
113
|
- lib/chef/knife/tidy_backup_clean.rb
|
114
114
|
- lib/chef/knife/tidy_base.rb
|
115
115
|
- lib/chef/knife/tidy_server_report.rb
|
116
|
+
- lib/chef/tidy_acls.rb
|
117
|
+
- lib/chef/tidy_common.rb
|
116
118
|
- lib/chef/tidy_server.rb
|
117
119
|
- lib/chef/tidy_substitutions.rb
|
118
120
|
- lib/knife-tidy/version.rb
|