config_o_mat 0.3.0 → 0.4.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +57 -0
- data/Gemfile.lock +16 -10
- data/config_o_mat.gemspec +1 -0
- data/lib/config_o_mat/configurator/memory.rb +6 -2
- data/lib/config_o_mat/configurator/op/compile_templates.rb +1 -1
- data/lib/config_o_mat/configurator/op/next_tick.rb +11 -1
- data/lib/config_o_mat/configurator/op/refresh_all_profiles.rb +62 -36
- data/lib/config_o_mat/configurator/op/refresh_profile.rb +32 -0
- data/lib/config_o_mat/meta_configurator/memory.rb +6 -2
- data/lib/config_o_mat/secrets_loader/memory.rb +1 -1
- data/lib/config_o_mat/shared/op/load_meta_config.rb +16 -2
- data/lib/config_o_mat/shared/types.rb +98 -9
- data/lib/config_o_mat/version.rb +1 -1
- metadata +23 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f6e9883d10f0ab6349aa447ef2b199692e05c02aeb8f17a95b8c1a7825ffab9b
|
4
|
+
data.tar.gz: 2486dea3da2ad9f2113e88d966efcff92616fd1baec02e1ac4dacf392df19710
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: edfc8bb95b506e73c191fba4f476e38cc18d3478a2917d159ee448e9392662c042b00991c1ad5f985b29c73f988a580c8fff1814155a71c3f120dc6dd0a117c2
|
7
|
+
data.tar.gz: 80df6494340c67f9ea7b57b558080ae3e369d0249e9505511db33c7c070fc434144c3bba096adff07176a66085b57bbc4a8013329453b57343ef0024305018e5
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
## 0.4.4
|
2
|
+
|
3
|
+
BUG FIXES:
|
4
|
+
|
5
|
+
* Fix MetaConfigurator with new GC parameters.
|
6
|
+
|
7
|
+
## 0.4.3
|
8
|
+
|
9
|
+
BUG FIXES:
|
10
|
+
|
11
|
+
* Fix MetaConfigurator with new GC parameters.
|
12
|
+
|
13
|
+
## 0.4.2
|
14
|
+
|
15
|
+
NEW FEATURES:
|
16
|
+
|
17
|
+
* gc_compact configuration variable. If set, will run `GC.compact` every given number of ticks (roughly seconds).
|
18
|
+
* gc_stat configuration variable. If set, will log `GC.stat` at the info level every given number of ticks (roughly seconds).
|
19
|
+
|
20
|
+
ENHANCEMENTS:
|
21
|
+
|
22
|
+
* Now remove ec2_metadata.iam key from Facter. This value updated every hour or so causing spurious template regeneration and did not contain actionable information.
|
23
|
+
|
24
|
+
## 0.4.1
|
25
|
+
|
26
|
+
ENHANCEMENTS:
|
27
|
+
|
28
|
+
* Omit empty lines in generated config when using <% %> ERB templates.
|
29
|
+
|
30
|
+
## 0.4.0
|
31
|
+
|
32
|
+
NEW FEATURES:
|
33
|
+
|
34
|
+
* Facter support. In your configomat config set a top level `facter` key to either truthy or a string. If truthy, facter data will be exposed in a profile named `facter` in all templates. If set to a string, facter data will be exposed in a profile with the given name in all templates.
|
35
|
+
* Attempting to access a configuration variable from a profile or secret that does not exist using `#[]` will now raise an exception indicating the key being incorrectly accessed. If you need to access optionally present configuration variables from profiles or secrets use `#fetch(key, nil)`.
|
36
|
+
|
37
|
+
## 0.3.0
|
38
|
+
|
39
|
+
NEW FEATURES:
|
40
|
+
|
41
|
+
* AWS Secrets Manager support, through an AWS AppConfig configuration. Values to pull from AWS Secrets Manager can be set using an "aws:secrets" key in any loaded AWS AppConfig JSON or YAML configuration. The value must be a dictionary. Keys in this dictionary will be exposed in the #secrets hash on the profile in templates. Values in this dictionary must be a dictionary containing at a minimum a `secret_id` key, which must be the id of an AWS Secrets Manager Secret. The dictionary may also contain a `version_id` or `version_stage` key to indicate which version of the secret to load, and a `content_type` key which may be one of `text/plan`, `application/json`, or `application/x-yaml` to indicate how the secret data should be parsed.
|
42
|
+
|
43
|
+
## 0.2.1
|
44
|
+
|
45
|
+
BUG FIXES:
|
46
|
+
|
47
|
+
* restart_all actually works.
|
48
|
+
|
49
|
+
## 0.2.0
|
50
|
+
|
51
|
+
NEW FEATURES:
|
52
|
+
|
53
|
+
* restart_all restart_mode for services to restart all running instances of an instantiated service.
|
54
|
+
|
55
|
+
## 0.1.0
|
56
|
+
|
57
|
+
Initial release
|
data/Gemfile.lock
CHANGED
@@ -1,9 +1,10 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
config_o_mat (0.
|
4
|
+
config_o_mat (0.4.0)
|
5
5
|
aws-sdk-appconfig (~> 1.18)
|
6
6
|
aws-sdk-secretsmanager (~> 1.57)
|
7
|
+
facter (~> 4.2, >= 4.2.8)
|
7
8
|
lifecycle_vm (~> 0.1.1)
|
8
9
|
logsformyfamily (~> 0.2)
|
9
10
|
ruby-dbus (~> 0.16.0)
|
@@ -13,25 +14,29 @@ GEM
|
|
13
14
|
remote: https://rubygems.org/
|
14
15
|
specs:
|
15
16
|
aws-eventstream (1.2.0)
|
16
|
-
aws-partitions (1.
|
17
|
-
aws-sdk-appconfig (1.
|
18
|
-
aws-sdk-core (~> 3, >= 3.
|
17
|
+
aws-partitions (1.574.0)
|
18
|
+
aws-sdk-appconfig (1.25.0)
|
19
|
+
aws-sdk-core (~> 3, >= 3.127.0)
|
19
20
|
aws-sigv4 (~> 1.1)
|
20
|
-
aws-sdk-core (3.
|
21
|
+
aws-sdk-core (3.130.0)
|
21
22
|
aws-eventstream (~> 1, >= 1.0.2)
|
22
23
|
aws-partitions (~> 1, >= 1.525.0)
|
23
24
|
aws-sigv4 (~> 1.1)
|
24
25
|
jmespath (~> 1.0)
|
25
|
-
aws-sdk-secretsmanager (1.
|
26
|
-
aws-sdk-core (~> 3, >= 3.
|
26
|
+
aws-sdk-secretsmanager (1.59.0)
|
27
|
+
aws-sdk-core (~> 3, >= 3.127.0)
|
27
28
|
aws-sigv4 (~> 1.1)
|
28
29
|
aws-sigv4 (1.4.0)
|
29
30
|
aws-eventstream (~> 1, >= 1.0.2)
|
30
31
|
diff-lcs (1.5.0)
|
31
32
|
docile (1.4.0)
|
32
|
-
|
33
|
-
|
34
|
-
|
33
|
+
facter (4.2.9)
|
34
|
+
hocon (~> 1.3)
|
35
|
+
thor (>= 1.0.1, < 2.0)
|
36
|
+
hocon (1.3.1)
|
37
|
+
jmespath (1.6.1)
|
38
|
+
lifecycle_vm (0.1.3)
|
39
|
+
logsformyfamily (0.3.0)
|
35
40
|
rspec (3.11.0)
|
36
41
|
rspec-core (~> 3.11.0)
|
37
42
|
rspec-expectations (~> 3.11.0)
|
@@ -53,6 +58,7 @@ GEM
|
|
53
58
|
simplecov_json_formatter (~> 0.1)
|
54
59
|
simplecov-html (0.12.3)
|
55
60
|
simplecov_json_formatter (0.1.4)
|
61
|
+
thor (1.2.1)
|
56
62
|
|
57
63
|
PLATFORMS
|
58
64
|
ruby
|
data/config_o_mat.gemspec
CHANGED
@@ -44,6 +44,7 @@ Gem::Specification.new do |spec|
|
|
44
44
|
spec.add_dependency('lifecycle_vm', '~> 0.1.1')
|
45
45
|
spec.add_dependency('ruby-dbus', '~> 0.16.0')
|
46
46
|
spec.add_dependency('sd_notify', '~> 0.1.1')
|
47
|
+
spec.add_dependency('facter', ['~> 4.2', '>= 4.2.8'])
|
47
48
|
|
48
49
|
spec.add_development_dependency('simplecov', '~> 0.21.2')
|
49
50
|
spec.add_development_dependency('rspec', '~> 3.10')
|
@@ -26,7 +26,7 @@ module ConfigOMat
|
|
26
26
|
:generated_templates, :services_to_reload, :profiles_to_apply,
|
27
27
|
:last_refresh_time, :next_state, :retry_count, :retries_left, :retry_wait,
|
28
28
|
:region, :appconfig_client, :secretsmanager_client, :systemd_interface,
|
29
|
-
:secrets_loader_memory
|
29
|
+
:secrets_loader_memory, :gc_compact, :gc_stat
|
30
30
|
|
31
31
|
def initialize(
|
32
32
|
argv: [],
|
@@ -58,7 +58,9 @@ module ConfigOMat
|
|
58
58
|
appconfig_client: nil,
|
59
59
|
secretsmanager_client: nil,
|
60
60
|
systemd_interface: nil,
|
61
|
-
secrets_loader_memory: nil
|
61
|
+
secrets_loader_memory: nil,
|
62
|
+
gc_compact: 0,
|
63
|
+
gc_stat: 0
|
62
64
|
)
|
63
65
|
super()
|
64
66
|
|
@@ -92,6 +94,8 @@ module ConfigOMat
|
|
92
94
|
@secretsmanager_client = secretsmanager_client
|
93
95
|
@systemd_interface = systemd_interface
|
94
96
|
@secrets_loader_memory = secrets_loader_memory
|
97
|
+
@gc_compact = gc_compact
|
98
|
+
@gc_stat = gc_stat
|
95
99
|
end
|
96
100
|
end
|
97
101
|
end
|
@@ -28,7 +28,7 @@ module ConfigOMat
|
|
28
28
|
self.compiled_templates = template_defs.each_with_object({}) do |(key, templ_def), hash|
|
29
29
|
filename = File.join(configuration_directory, 'templates', templ_def.src)
|
30
30
|
begin
|
31
|
-
templ = ERB.new(File.read(filename))
|
31
|
+
templ = ERB.new(File.read(filename), trim_mode: '<>')
|
32
32
|
templ.filename = filename
|
33
33
|
hash[key] = templ.def_class(Object, 'render(profiles)').new
|
34
34
|
rescue SyntaxError, StandardError => e
|
@@ -23,7 +23,7 @@ module ConfigOMat
|
|
23
23
|
class NextTick < LifecycleVM::OpBase
|
24
24
|
PAUSE_INTERVAL = 1
|
25
25
|
|
26
|
-
reads :last_refresh_time, :refresh_interval, :run_count, :retry_count
|
26
|
+
reads :last_refresh_time, :refresh_interval, :run_count, :retry_count, :gc_stat, :gc_compact
|
27
27
|
writes :next_state, :run_count, :retries_left
|
28
28
|
|
29
29
|
def call
|
@@ -31,6 +31,16 @@ module ConfigOMat
|
|
31
31
|
|
32
32
|
SdNotify.watchdog
|
33
33
|
|
34
|
+
if gc_compact > 0 && run_count % gc_compact == 0
|
35
|
+
response = GC.compact
|
36
|
+
logger&.info(:gc_compact, compact: response)
|
37
|
+
end
|
38
|
+
|
39
|
+
if gc_stat > 0 && run_count % gc_stat == 0
|
40
|
+
response = GC.stat
|
41
|
+
logger&.info(:gc_stat, stat: response)
|
42
|
+
end
|
43
|
+
|
34
44
|
# If we got here then our retry process has succeeded.
|
35
45
|
self.retries_left = retry_count
|
36
46
|
|
@@ -29,56 +29,82 @@ module ConfigOMat
|
|
29
29
|
self.last_refresh_time = Time.now.to_i
|
30
30
|
|
31
31
|
profile_defs.each do |(profile_name, definition)|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
32
|
+
if definition.kind_of?(ConfigOMat::Profile)
|
33
|
+
refresh_appconfig_profile(profile_name, definition)
|
34
|
+
elsif definition.kind_of?(ConfigOMat::FacterProfile)
|
35
|
+
refresh_facter_profile(profile_name)
|
36
|
+
else
|
37
|
+
error profile_name, "unknown profile type #{definition.class.name}"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def refresh_facter_profile(profile_name)
|
45
|
+
current_version = applied_profiles&.fetch(profile_name, nil)&.version
|
46
|
+
new_profile = ConfigOMat::LoadedFacterProfile.new(profile_name)
|
36
47
|
|
37
|
-
|
38
|
-
request[:client_configuration_version] = current_version if current_version
|
48
|
+
return if new_profile.version == current_version
|
39
49
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
error profile_name, e
|
45
|
-
nil
|
46
|
-
end
|
50
|
+
logger&.notice(
|
51
|
+
:updated_profile,
|
52
|
+
name: profile_name, previous_version: current_version, new_version: new_profile.version
|
53
|
+
)
|
47
54
|
|
48
|
-
|
55
|
+
profiles_to_apply << LoadedProfile.new(new_profile, nil)
|
56
|
+
end
|
57
|
+
|
58
|
+
def refresh_appconfig_profile(profile_name, definition)
|
59
|
+
request = {
|
60
|
+
application: definition.application, environment: definition.environment,
|
61
|
+
configuration: definition.profile, client_id: client_id
|
62
|
+
}
|
63
|
+
|
64
|
+
current_version = applied_profiles&.fetch(profile_name, nil)&.version
|
65
|
+
request[:client_configuration_version] = current_version if current_version
|
66
|
+
|
67
|
+
response =
|
68
|
+
begin
|
69
|
+
appconfig_client.get_configuration(request)
|
70
|
+
rescue StandardError => e
|
71
|
+
error profile_name, e
|
72
|
+
nil
|
73
|
+
end
|
49
74
|
|
50
|
-
|
51
|
-
next if current_version && loaded_version == current_version
|
75
|
+
return if response.nil?
|
52
76
|
|
53
|
-
|
54
|
-
|
55
|
-
name: profile_name, previous_version: current_version, new_version: loaded_version
|
56
|
-
)
|
77
|
+
loaded_version = response.configuration_version
|
78
|
+
return if current_version && loaded_version == current_version
|
57
79
|
|
58
|
-
|
59
|
-
|
60
|
-
|
80
|
+
logger&.notice(
|
81
|
+
:updated_profile,
|
82
|
+
name: profile_name, previous_version: current_version, new_version: loaded_version
|
83
|
+
)
|
61
84
|
|
62
|
-
|
85
|
+
profile = LoadedAppconfigProfile.new(
|
86
|
+
profile_name, loaded_version, response.content.read, response.content_type
|
87
|
+
)
|
63
88
|
|
64
|
-
|
65
|
-
self.secrets_loader_memory ||= ConfigOMat::SecretsLoader::Memory.new(secretsmanager_client: secretsmanager_client)
|
66
|
-
secrets_loader_memory.update_secret_defs_to_load(profile.secret_defs.values)
|
89
|
+
loaded_secrets = nil
|
67
90
|
|
68
|
-
|
91
|
+
if !profile.secret_defs.empty?
|
92
|
+
self.secrets_loader_memory ||= ConfigOMat::SecretsLoader::Memory.new(secretsmanager_client: secretsmanager_client)
|
93
|
+
secrets_loader_memory.update_secret_defs_to_load(profile.secret_defs.values)
|
69
94
|
|
70
|
-
|
71
|
-
error :"#{profile_name}_secrets", vm.errors
|
72
|
-
next
|
73
|
-
end
|
95
|
+
vm = ConfigOMat::SecretsLoader::VM.new(secrets_loader_memory).call
|
74
96
|
|
75
|
-
|
76
|
-
|
77
|
-
|
97
|
+
if vm.errors?
|
98
|
+
error :"#{profile_name}_secrets", vm.errors
|
99
|
+
return
|
78
100
|
end
|
79
101
|
|
80
|
-
|
102
|
+
loaded_secrets = secrets_loader_memory.loaded_secrets.each_with_object({}) do |(key, value), hash|
|
103
|
+
hash[value.name] = value
|
104
|
+
end
|
81
105
|
end
|
106
|
+
|
107
|
+
profiles_to_apply << LoadedProfile.new(profile, loaded_secrets)
|
82
108
|
end
|
83
109
|
end
|
84
110
|
end
|
@@ -23,6 +23,38 @@ module ConfigOMat
|
|
23
23
|
writes :applying_profile, :secrets_loader_memory
|
24
24
|
|
25
25
|
def call
|
26
|
+
if applying_profile.loaded_profile_data.kind_of?(ConfigOMat::LoadedAppconfigProfile)
|
27
|
+
refresh_appconfig_profile
|
28
|
+
elsif applying_profile.loaded_profile_data.kind_of?(ConfigOMat::LoadedFacterProfile)
|
29
|
+
refresh_facter_profile
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def refresh_facter_profile
|
36
|
+
profile_name = applying_profile.name
|
37
|
+
profile_version = applying_profile.version
|
38
|
+
definition = profile_defs[profile_name]
|
39
|
+
new_profile = ConfigOMat::LoadedFacterProfile.new(profile_name)
|
40
|
+
|
41
|
+
if new_profile.version == profile_version
|
42
|
+
logger&.warning(
|
43
|
+
:no_update,
|
44
|
+
name: profile_name, version: profile_version
|
45
|
+
)
|
46
|
+
return
|
47
|
+
end
|
48
|
+
|
49
|
+
logger&.notice(
|
50
|
+
:updated_profile,
|
51
|
+
name: profile_name, previous_version: profile_version, new_version: new_profile.version
|
52
|
+
)
|
53
|
+
|
54
|
+
self.applying_profile = LoadedProfile.new(new_profile, nil)
|
55
|
+
end
|
56
|
+
|
57
|
+
def refresh_appconfig_profile
|
26
58
|
profile_name = applying_profile.name
|
27
59
|
profile_version = applying_profile.version
|
28
60
|
definition = profile_defs[profile_name]
|
@@ -23,7 +23,7 @@ module ConfigOMat
|
|
23
23
|
:systemd_directory, :logs_directory, :profile_defs,
|
24
24
|
:template_defs, :service_defs, :dependencies, :refresh_interval,
|
25
25
|
:client_id, :retry_count, :retries_left, :retry_wait,
|
26
|
-
:region, :systemd_interface
|
26
|
+
:region, :systemd_interface, :gc_stat, :gc_compact
|
27
27
|
|
28
28
|
def initialize(
|
29
29
|
argv: [],
|
@@ -44,7 +44,9 @@ module ConfigOMat
|
|
44
44
|
retries_left: 3,
|
45
45
|
retry_wait: 2,
|
46
46
|
region: nil,
|
47
|
-
systemd_interface: nil
|
47
|
+
systemd_interface: nil,
|
48
|
+
gc_stat: 0,
|
49
|
+
gc_copmact: 0
|
48
50
|
)
|
49
51
|
super()
|
50
52
|
|
@@ -67,6 +69,8 @@ module ConfigOMat
|
|
67
69
|
@retry_wait = retry_wait
|
68
70
|
@region = region
|
69
71
|
@systemd_interface = systemd_interface
|
72
|
+
@gc_stat = gc_stat
|
73
|
+
@gc_compact = gc_compact
|
70
74
|
end
|
71
75
|
end
|
72
76
|
end
|
@@ -63,7 +63,7 @@ module ConfigOMat
|
|
63
63
|
reads :configuration_directory, :logs_directory, :env
|
64
64
|
writes :profile_defs, :template_defs, :service_defs, :dependencies,
|
65
65
|
:refresh_interval, :client_id, :logger, :retry_count, :retries_left,
|
66
|
-
:retry_wait, :region, :systemd_interface
|
66
|
+
:retry_wait, :region, :systemd_interface, :gc_stat, :gc_compact
|
67
67
|
|
68
68
|
def call
|
69
69
|
default_config = {
|
@@ -74,7 +74,9 @@ module ConfigOMat
|
|
74
74
|
services: [],
|
75
75
|
templates: [],
|
76
76
|
profiles: [],
|
77
|
-
region: nil
|
77
|
+
region: nil,
|
78
|
+
gc_compact: 0,
|
79
|
+
gc_stat: 0
|
78
80
|
}
|
79
81
|
|
80
82
|
# TODO: I would like to make this configurable. I think the trick
|
@@ -126,6 +128,16 @@ module ConfigOMat
|
|
126
128
|
self.template_defs = instantiate.call(:templates, Template)
|
127
129
|
self.profile_defs = instantiate.call(:profiles, Profile)
|
128
130
|
|
131
|
+
facter = merged_config[:facter]
|
132
|
+
if facter
|
133
|
+
facter_key = facter.kind_of?(String) ? facter.to_sym : :facter
|
134
|
+
if profile_defs.key?(facter_key)
|
135
|
+
error :facter, "conflicts with profile #{facter_key}"
|
136
|
+
else
|
137
|
+
profile_defs[facter_key] = ConfigOMat::FacterProfile.new
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
129
141
|
self.logger = LogsForMyFamily::Logger.new if !logger
|
130
142
|
|
131
143
|
log_type = merged_config[:log_type]&.to_sym || :stdout
|
@@ -164,6 +176,8 @@ module ConfigOMat
|
|
164
176
|
self.retries_left = retry_count
|
165
177
|
self.retry_wait = merged_config[:retry_wait]
|
166
178
|
self.region = merged_config[:region]
|
179
|
+
self.gc_stat = merged_config[:gc_stat]
|
180
|
+
self.gc_compact = merged_config[:gc_compact]
|
167
181
|
|
168
182
|
self.dependencies = service_defs.each_with_object({}) do |(name, service), template_to_services|
|
169
183
|
service.templates.each do |template|
|
@@ -14,6 +14,8 @@
|
|
14
14
|
# See the License for the specific language governing permissions and
|
15
15
|
# limitations under the License.
|
16
16
|
|
17
|
+
require 'facter'
|
18
|
+
|
17
19
|
require 'json'
|
18
20
|
require 'yaml'
|
19
21
|
require 'digest'
|
@@ -187,6 +189,83 @@ module ConfigOMat
|
|
187
189
|
end
|
188
190
|
end
|
189
191
|
|
192
|
+
class FacterProfile < ConfigItem
|
193
|
+
end
|
194
|
+
|
195
|
+
class LoadedFacterProfile < ConfigItem
|
196
|
+
CLEAR_FROM_FACTER = [
|
197
|
+
"memoryfree", "memoryfree_mb", "load_averages", "uptime", "system_uptime", "uptime_seconds", "uptime_hours", "uptime_days",
|
198
|
+
{"ec2_metadata" => ["identity-credentials", "iam"]},
|
199
|
+
{"memory" => [{"system" => ["capacity", "available_bytes", "used", "used_bytes", "available"] }] }
|
200
|
+
].freeze
|
201
|
+
|
202
|
+
attr_reader :name, :version, :contents
|
203
|
+
|
204
|
+
def initialize(name)
|
205
|
+
@name = name
|
206
|
+
load_from_facter
|
207
|
+
@version = contents.hash
|
208
|
+
end
|
209
|
+
|
210
|
+
def validate
|
211
|
+
error :name, 'must be present' if @name.nil? || @name.empty?
|
212
|
+
error :contents, 'must be present' if @contents.nil? || @contents.empty?
|
213
|
+
error :contents, 'must be a hash' if !@contents.kind_of?(Hash)
|
214
|
+
end
|
215
|
+
|
216
|
+
def hash
|
217
|
+
@name.hash ^ @version
|
218
|
+
end
|
219
|
+
|
220
|
+
def to_h
|
221
|
+
@contents
|
222
|
+
end
|
223
|
+
|
224
|
+
def eql?(other)
|
225
|
+
return false if !super(other)
|
226
|
+
return false if other.version != version || other.name != name
|
227
|
+
true
|
228
|
+
end
|
229
|
+
|
230
|
+
private
|
231
|
+
|
232
|
+
def load_from_facter
|
233
|
+
Facter.clear
|
234
|
+
# This is to work around a bug in Facter wherein it fails to invalidate a second cache of the
|
235
|
+
# IMDSv2 token.
|
236
|
+
Facter::Resolvers::Ec2.instance_variable_set(:@v2_token, nil)
|
237
|
+
new_facts = Facter.to_hash
|
238
|
+
clear(new_facts, CLEAR_FROM_FACTER)
|
239
|
+
transform(new_facts)
|
240
|
+
@contents = new_facts
|
241
|
+
end
|
242
|
+
|
243
|
+
def clear(hash, diffs)
|
244
|
+
diffs.each do |diff|
|
245
|
+
if diff.kind_of?(Hash)
|
246
|
+
diff.each do |(key, values)|
|
247
|
+
clear(hash[key], values) if hash.key?(key)
|
248
|
+
end
|
249
|
+
elsif hash
|
250
|
+
hash.delete(diff)
|
251
|
+
end
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
def transform(hash)
|
256
|
+
return unless hash.kind_of?(Hash)
|
257
|
+
hash.transform_keys!(&:to_sym)
|
258
|
+
hash.default_proc = proc { |hash, key| raise KeyError.new("No key #{key.inspect} in profile #{name}", key: key, receiver: hash) }
|
259
|
+
hash.each_value do |value|
|
260
|
+
if value.kind_of?(Hash)
|
261
|
+
transform(value)
|
262
|
+
elsif value.kind_of?(Array)
|
263
|
+
value.each { |v| transform(v) }
|
264
|
+
end
|
265
|
+
end
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
190
269
|
class LoadedAppconfigProfile < ConfigItem
|
191
270
|
attr_reader :name, :version, :contents, :secret_defs
|
192
271
|
|
@@ -206,7 +285,12 @@ module ConfigOMat
|
|
206
285
|
if parser
|
207
286
|
begin
|
208
287
|
@contents = parser.call(contents)
|
209
|
-
|
288
|
+
if @contents.kind_of?(Hash)
|
289
|
+
parse_secrets
|
290
|
+
@contents.default_proc = proc do |hash, key|
|
291
|
+
raise KeyError.new("No key #{key.inspect} in profile #{name}", key: key, receiver: hash)
|
292
|
+
end
|
293
|
+
end
|
210
294
|
rescue StandardError => e
|
211
295
|
error :contents, e
|
212
296
|
end
|
@@ -239,7 +323,7 @@ module ConfigOMat
|
|
239
323
|
private
|
240
324
|
|
241
325
|
def parse_secrets
|
242
|
-
secret_entries = @contents
|
326
|
+
secret_entries = @contents.fetch(:"aws:secrets", nil)
|
243
327
|
return if secret_entries.nil?
|
244
328
|
|
245
329
|
error :contents_secrets, 'must be a dictionary' if !secret_entries.kind_of?(Hash)
|
@@ -305,6 +389,11 @@ module ConfigOMat
|
|
305
389
|
|
306
390
|
begin
|
307
391
|
@contents = LoadedAppconfigProfile::PARSERS[content_type].call(secret_string)
|
392
|
+
if @contents.kind_of?(Hash)
|
393
|
+
@contents.default_proc = proc do |hash, key|
|
394
|
+
raise KeyError.new("No key #{key.inspect} in secret #{name}", key: key, receiver: hash)
|
395
|
+
end
|
396
|
+
end
|
308
397
|
rescue StandardError => e
|
309
398
|
error :contents, e
|
310
399
|
end
|
@@ -335,22 +424,22 @@ module ConfigOMat
|
|
335
424
|
class LoadedProfile < ConfigItem
|
336
425
|
extend Forwardable
|
337
426
|
|
338
|
-
attr_reader :secrets, :
|
427
|
+
attr_reader :secrets, :loaded_profile_data
|
339
428
|
|
340
|
-
def_delegators :@
|
429
|
+
def_delegators :@loaded_profile_data, :name, :version, :contents
|
341
430
|
|
342
|
-
def initialize(
|
343
|
-
@
|
431
|
+
def initialize(loaded_profile_data, secrets)
|
432
|
+
@loaded_profile_data = loaded_profile_data
|
344
433
|
@secrets = secrets || {}
|
345
434
|
|
346
|
-
@errors = @
|
435
|
+
@errors = @loaded_profile_data.errors if @loaded_profile_data.errors?
|
347
436
|
end
|
348
437
|
|
349
438
|
def validate
|
350
439
|
end
|
351
440
|
|
352
441
|
def hash
|
353
|
-
@
|
442
|
+
@loaded_profile_data.hash ^ @secrets.hash
|
354
443
|
end
|
355
444
|
|
356
445
|
def to_h
|
@@ -359,7 +448,7 @@ module ConfigOMat
|
|
359
448
|
|
360
449
|
def eql?(other)
|
361
450
|
return false if !super(other)
|
362
|
-
return false if other.
|
451
|
+
return false if other.loaded_profile_data != @loaded_profile_data || other.secrets != @secrets
|
363
452
|
true
|
364
453
|
end
|
365
454
|
end
|
data/lib/config_o_mat/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: config_o_mat
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alex Scarborough
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-04-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: aws-sdk-appconfig
|
@@ -94,6 +94,26 @@ dependencies:
|
|
94
94
|
- - "~>"
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: 0.1.1
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: facter
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '4.2'
|
104
|
+
- - ">="
|
105
|
+
- !ruby/object:Gem::Version
|
106
|
+
version: 4.2.8
|
107
|
+
type: :runtime
|
108
|
+
prerelease: false
|
109
|
+
version_requirements: !ruby/object:Gem::Requirement
|
110
|
+
requirements:
|
111
|
+
- - "~>"
|
112
|
+
- !ruby/object:Gem::Version
|
113
|
+
version: '4.2'
|
114
|
+
- - ">="
|
115
|
+
- !ruby/object:Gem::Version
|
116
|
+
version: 4.2.8
|
97
117
|
- !ruby/object:Gem::Dependency
|
98
118
|
name: simplecov
|
99
119
|
requirement: !ruby/object:Gem::Requirement
|
@@ -135,6 +155,7 @@ files:
|
|
135
155
|
- ".rspec"
|
136
156
|
- ".ruby-gemset"
|
137
157
|
- ".ruby-version"
|
158
|
+
- CHANGELOG.md
|
138
159
|
- Gemfile
|
139
160
|
- Gemfile.lock
|
140
161
|
- LICENSE
|