terraorg 0.2.3 → 0.5.3
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/README.md +11 -1
- data/bin/terraorg +5 -1
- data/lib/terraorg/model/org.rb +62 -19
- data/lib/terraorg/model/person.rb +1 -1
- data/lib/terraorg/version.rb +1 -1
- metadata +17 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '081a5e9b4201f219e7b153a554a57e32060a8c043b2769d8bd9199d25f871850'
|
4
|
+
data.tar.gz: f6be12775e8435085b35da3bdc0b66af701705ffc9c6d0de45a6cc47cc237737
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8ca99240c4e75a63c6af0e7ff83efe3994dc3da8ac3072a524d3c845a5c99f68211bc189aafe53ed03593a9c748d7179d5f92bc67b4c15cbdc33c1ca3c632c71
|
7
|
+
data.tar.gz: dcb7597efd163ca22e17968c81cd80dd599ddaa98acf304972e25ed5fafe6c9745f15ec143878c6f3898ed415393caaf109b25d5312953fc9fe6393936b0a0db
|
data/README.md
CHANGED
@@ -34,7 +34,9 @@ Based on the org that this tool was originally designed for, orgs are expected
|
|
34
34
|
to have three levels:
|
35
35
|
|
36
36
|
* *squads*: the base unit of team-dom, containing people, who may be in
|
37
|
-
different geographical regions.
|
37
|
+
different geographical regions. Teams contain _members_ (full time heads)
|
38
|
+
and _associates_ (typically part time floaters.) Any associate of a squad
|
39
|
+
must also have a home squad for which they are a full time member.
|
38
40
|
* *platoons*: a unit which contains squads and exceptional people who are
|
39
41
|
members of the platoon, but not part of any squad
|
40
42
|
* *org*: The whole organization, including its manager, any exceptional squads
|
@@ -45,6 +47,10 @@ The tool generates groups for each granular unit of organization in Okta and G
|
|
45
47
|
Suite in Terraform. With patching, it could be possible for more organizational
|
46
48
|
systems to be supported.
|
47
49
|
|
50
|
+
## Diagram
|
51
|
+
|
52
|
+

|
53
|
+
|
48
54
|
## How it works
|
49
55
|
|
50
56
|
Firstly, take your entire existing organization and define it using the
|
@@ -120,6 +126,10 @@ information on how to configure the providers.
|
|
120
126
|
[articulate/terraform-provider-okta]: https://github.com/articulate/terraform-provider-okta
|
121
127
|
[DeviaVir/terraform-provider-gsuite]: https://github.com/DeviaVir/terraform-provider-gsuite
|
122
128
|
|
129
|
+
## Running tests
|
130
|
+
There are a limited number of tests that can be invoked with
|
131
|
+
`ruby -I lib test/terraorg/model/org_test.rb `
|
132
|
+
|
123
133
|
## Suggested process
|
124
134
|
|
125
135
|
At [LiveRamp], a pull request based workflow leveraging [Atlantis] is used to
|
data/bin/terraorg
CHANGED
@@ -31,6 +31,8 @@ ACTIONS = [
|
|
31
31
|
'validate'
|
32
32
|
].freeze
|
33
33
|
|
34
|
+
STRICT_VALIDATION = ENV.fetch('TERRAORG_STRICT_VALIDATION', 'true')
|
35
|
+
ALLOW_ORPHANED_ASSOCIATES = ENV.fetch('ALLOW_ORPHANED_ASSOCIATES', 'false')
|
34
36
|
SQUADS_FILE = ENV.fetch('TERRAORG_SQUADS', 'squads.json')
|
35
37
|
PLATOONS_FILE = ENV.fetch('TERRAORG_PLATOONS', 'platoons.json')
|
36
38
|
ORG_FILE = ENV.fetch('TERRAORG_ROOT', 'org.json')
|
@@ -95,7 +97,9 @@ platoons = Platoons.new(JSON.parse(platoons_data), squads, people, GSUITE_DOMAIN
|
|
95
97
|
org_data = File.read(ORG_FILE)
|
96
98
|
org = Org.new(JSON.parse(org_data), platoons, squads, people, GSUITE_DOMAIN)
|
97
99
|
|
98
|
-
|
100
|
+
strict = (STRICT_VALIDATION == 'true')
|
101
|
+
allow_orphaned_associates = (ALLOW_ORPHANED_ASSOCIATES == 'true')
|
102
|
+
org.validate!(strict: strict, allow_orphaned_associates: allow_orphaned_associates)
|
99
103
|
|
100
104
|
case action
|
101
105
|
when 'generate-squads-md'
|
data/lib/terraorg/model/org.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# Copyright 2019-2020 LiveRamp Holdings, Inc.
|
2
|
+
# Copyright 2020- Joshua Kwan
|
2
3
|
#
|
3
4
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
5
|
# you may not use this file except in compliance with the License.
|
@@ -49,23 +50,33 @@ class Org
|
|
49
50
|
@squads = squads
|
50
51
|
end
|
51
52
|
|
52
|
-
def validate!
|
53
|
+
def validate!(strict: true, allow_orphaned_associates: false)
|
54
|
+
failure = false
|
55
|
+
|
53
56
|
# Do not allow the JSON files to contain any people who have left.
|
54
|
-
|
57
|
+
unless @people.inactive.empty?
|
58
|
+
$stderr.puts "ERROR: Users have left the company, or are Suspended in Okta: #{@people.inactive.map(&:id).join(', ')}"
|
59
|
+
failure = true
|
60
|
+
end
|
55
61
|
|
56
62
|
# Do not allow the org to be totally empty.
|
57
|
-
|
63
|
+
if @member_platoons.size + @member_exception_squads.size == 0
|
64
|
+
$stderr.puts 'ERROR: Org has no platoons or exception squads'
|
65
|
+
failure = true
|
66
|
+
end
|
58
67
|
|
59
68
|
# Require all platoons to be part of the org.
|
60
69
|
platoon_diff = Set.new(@platoons.all_names) - Set.new(@member_platoon_names)
|
61
70
|
unless platoon_diff.empty?
|
62
|
-
|
71
|
+
$stderr.puts "ERROR: Platoons are not used in the org: #{platoon_diff.to_a.sort}"
|
72
|
+
failure = true
|
63
73
|
end
|
64
74
|
|
65
75
|
# Require all squads to be used in the org.
|
66
76
|
squad_diff = Set.new(@squads.all_names) - Set.new(@platoons.all_squad_names) - Set.new(@member_exception_squad_names)
|
67
77
|
unless squad_diff.empty?
|
68
|
-
|
78
|
+
$stderr.puts "ERROR: Squad(s) are not used in the org: #{squad_diff.to_a.sort}"
|
79
|
+
failure = true
|
69
80
|
end
|
70
81
|
|
71
82
|
all_squads = (@member_platoons.map(&:member_squads) + @member_exception_squads).flatten
|
@@ -79,34 +90,37 @@ class Org
|
|
79
90
|
count > 1
|
80
91
|
end
|
81
92
|
if !more_than_one_platoon.empty?
|
82
|
-
|
93
|
+
$stderr.puts "ERROR: Squads are part of more than one platoon: #{more_than_one_platoon}"
|
94
|
+
failure = true
|
83
95
|
end
|
84
96
|
|
85
97
|
# Validate that a squad member belongs to some maximum number of squads
|
86
98
|
# across the entire org. A person can be an associate of other squads
|
87
99
|
# at a different count. See top of file for defined limits.
|
88
100
|
squad_count = {}
|
89
|
-
all_squads.map(&:teams).flatten.map(&:values).flatten.map(&:members).flatten
|
101
|
+
all_members = all_squads.map(&:teams).flatten.map(&:values).flatten.map(&:members).flatten
|
102
|
+
all_members.each do |member|
|
90
103
|
squad_count[member.id] = squad_count.fetch(member.id, 0) + 1
|
91
104
|
end
|
92
105
|
more_than_max_squads = squad_count.select do |member, count|
|
93
106
|
count > MAX_MEMBER_SQUADS_PER_PERSON
|
94
107
|
end
|
95
108
|
if !more_than_max_squads.empty?
|
96
|
-
|
97
|
-
|
109
|
+
$stderr.puts "ERROR: People are members of more than #{MAX_MEMBER_SQUADS_PER_PERSON} squads: #{more_than_max_squads}"
|
110
|
+
failure = true
|
98
111
|
end
|
99
112
|
|
100
113
|
associate_count = {}
|
101
|
-
all_squads.map(&:teams).flatten.map(&:values).flatten.map(&:associates).flatten
|
114
|
+
all_associates = all_squads.map(&:teams).flatten.map(&:values).flatten.map(&:associates).flatten
|
115
|
+
all_associates.each do |assoc|
|
102
116
|
associate_count[assoc.id] = associate_count.fetch(assoc.id, 0) + 1
|
103
117
|
end
|
104
118
|
more_than_max_squads = associate_count.select do |_, count|
|
105
119
|
count > MAX_ASSOCIATE_SQUADS_PER_PERSON
|
106
120
|
end
|
107
121
|
if !more_than_max_squads.empty?
|
108
|
-
|
109
|
-
|
122
|
+
$stderr.puts "ERROR: People are associates of more than #{MAX_ASSOCIATE_SQUADS_PER_PERSON} squads: #{more_than_max_squads}"
|
123
|
+
failure = true
|
110
124
|
end
|
111
125
|
|
112
126
|
# Validate that a squad member is not also an org exception
|
@@ -115,8 +129,20 @@ class Org
|
|
115
129
|
exceptions.member? member
|
116
130
|
end
|
117
131
|
if !exception_and_squad_member.empty?
|
118
|
-
|
132
|
+
$stderr.puts "ERROR: Exception members are also squad members: #{exception_and_squad_member}"
|
133
|
+
failure = true
|
119
134
|
end
|
135
|
+
|
136
|
+
# Validate that any associate is a member of some squad
|
137
|
+
if !allow_orphaned_associates
|
138
|
+
associates_but_not_members = Set.new(all_associates.map(&:id)) - Set.new(all_members.map(&:id)) - exceptions
|
139
|
+
if !associates_but_not_members.empty?
|
140
|
+
$stderr.puts "ERROR: #{associates_but_not_members.to_a} are associates of squads but not members of any squad"
|
141
|
+
failure = true
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
raise "CRITICAL: Validation failed due to at least one error above" if failure && strict
|
120
146
|
end
|
121
147
|
|
122
148
|
def members
|
@@ -179,13 +205,16 @@ class Org
|
|
179
205
|
md_lines.join("\n")
|
180
206
|
end
|
181
207
|
|
182
|
-
def
|
183
|
-
|
184
|
-
|
208
|
+
def generate_tf_platoons
|
209
|
+
@member_platoons.map { |p| p.generate_tf(@id) }.join("\n")
|
210
|
+
end
|
185
211
|
|
186
|
-
|
187
|
-
|
212
|
+
def generate_tf_squads
|
213
|
+
@member_exception_squads.map { |s| s.generate_tf(@id) }.join("\n")
|
214
|
+
end
|
188
215
|
|
216
|
+
def generate_tf_org
|
217
|
+
tf = ''
|
189
218
|
# Roll all platoons and exception squads into the org.
|
190
219
|
roll_up_to_org = \
|
191
220
|
@member_exception_squads.map { |s| s.unique_name(@id, nil) } + \
|
@@ -225,14 +254,18 @@ EOF
|
|
225
254
|
all_locations[@manager_location] = all_locations.fetch(@manager_location, Set.new).add(@manager)
|
226
255
|
|
227
256
|
all_locations.each do |l, m|
|
257
|
+
description = "#{@name} organization members based in #{l} (terraorg)"
|
228
258
|
name = "#{unique_name}-#{l.downcase}"
|
229
259
|
tf += <<-EOF
|
230
260
|
resource "okta_group" "#{name}" {
|
231
261
|
name = "#{name}"
|
232
|
-
description = "#{
|
262
|
+
description = "#{description}"
|
233
263
|
users = #{Util.persons_tf(m)}
|
234
264
|
}
|
265
|
+
|
266
|
+
#{Util.gsuite_group_tf(name, @gsuite_domain, m, description)}
|
235
267
|
EOF
|
268
|
+
|
236
269
|
end
|
237
270
|
|
238
271
|
# Generate a special GSuite group for all managers (org, platoon, squad
|
@@ -241,7 +274,17 @@ EOF
|
|
241
274
|
all_managers = Set.new([@manager] + @platoons.all.map(&:manager) + @squads.all.map(&:manager).select { |m| m })
|
242
275
|
manager_dl = "#{@id}-managers"
|
243
276
|
tf += Util.gsuite_group_tf(manager_dl, @gsuite_domain, all_managers, "All managers of the #{@name} organization (terraorg)")
|
277
|
+
tf
|
278
|
+
end
|
279
|
+
|
280
|
+
def generate_tf
|
281
|
+
tf = generate_tf_platoons
|
282
|
+
File.write('auto.platoons.tf', tf)
|
283
|
+
|
284
|
+
tf = generate_tf_squads
|
285
|
+
File.write('auto.exception_squads.tf', tf)
|
244
286
|
|
287
|
+
tf = generate_tf_org
|
245
288
|
File.write('auto.org.tf', tf)
|
246
289
|
end
|
247
290
|
|
data/lib/terraorg/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: terraorg
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Joshua Kwan
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-01-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: countries
|
@@ -66,6 +66,20 @@ dependencies:
|
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '0.2'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: minitest
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '5.14'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '5.14'
|
69
83
|
description: Manage an organizational structure with Okta and G-Suite using Terraform
|
70
84
|
email: joshk@triplehelix.org
|
71
85
|
executables:
|
@@ -104,7 +118,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
104
118
|
- !ruby/object:Gem::Version
|
105
119
|
version: '0'
|
106
120
|
requirements: []
|
107
|
-
rubygems_version: 3.0.
|
121
|
+
rubygems_version: 3.0.8
|
108
122
|
signing_key:
|
109
123
|
specification_version: 4
|
110
124
|
summary: terraorg
|