knife-tidy 0.1.1 → 0.2.0
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 +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
|