container_config 0.1.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.
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "container_config"
4
+
5
+ module ContainerConfig
6
+ module Provider
7
+ # Base config value provider
8
+ class Base
9
+ #
10
+ # Returns name of the config value provider
11
+ #
12
+ # @return [String] provider name
13
+ #
14
+ def name
15
+ raise ContainerConfig::MissingOverride, "Must override name method in derived class #{self.class}"
16
+ end
17
+
18
+ #
19
+ # Loads a configuration setting from the provider
20
+ #
21
+ # @param [String] key Configuration key to load
22
+ # @param [Array] _dig_keys Variable keys to use to load from providers that accept a dig structure
23
+ # defaults to the lowercase key split by underscores
24
+ # "MY_PASSWORD" => ["my", "password"]
25
+ # @param [Hash] options Options Hash
26
+ # @option options [String] :default default value if the configuration setting cannot be found
27
+ # @option options [String] :secret_mount_directory directory where secret files are mounted
28
+ #
29
+ # @return [Object] configuration setting value
30
+ #
31
+ def load(key, *_dig_keys, **options)
32
+ ContainerConfig.logger.debug do
33
+ "Loading configuration value for #{key} with options #{options} from #{self.class}"
34
+ end
35
+ nil
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "container_config/provider/base"
4
+
5
+ module ContainerConfig
6
+ module Provider
7
+ # Default config value provider (handles :default option)
8
+ class Default < Base
9
+ # @see ContainerConfig::Provider::Base#name
10
+ def name
11
+ "Default Value"
12
+ end
13
+
14
+ #
15
+ # Loads a default configuration setting based on the value of options[:default]
16
+ #
17
+ # @param [String] key Configuration key to load
18
+ # @param [Array] dig_keys Variable keys to use to load from providers that accept a dig structure
19
+ # @param [Hash] options Options Hash
20
+ # @option options [String] :default default value if the configuration setting cannot be found
21
+ #
22
+ # @return [Object] configuration setting value
23
+ #
24
+ def load(key, *dig_keys, **options)
25
+ super
26
+ options[:default]
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "container_config/provider/base"
4
+
5
+ module ContainerConfig
6
+ module Provider
7
+ # Environment variable config value provider
8
+ class Env < Base
9
+ # @see ContainerConfig::Provider::Base#name
10
+ def name
11
+ "Environment Variable"
12
+ end
13
+
14
+ #
15
+ # Loads an environment value configuration setting
16
+ #
17
+ # @param [String] key Configuration key to load
18
+ # @param [Array] dig_keys Variable keys to use to load from providers that accept a dig structure
19
+ # @param [Hash] options Options Hash
20
+ #
21
+ # @return [Object] configuration setting value
22
+ #
23
+ def load(key, *dig_keys, **options)
24
+ super
25
+ ENV[key]
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "container_config/provider/base"
4
+
5
+ module ContainerConfig
6
+ module Provider
7
+ # Rails credential config value provider
8
+ class RailsCredential < Base
9
+ # @see ContainerConfig::Provider::Base#name
10
+ def name
11
+ "Rails Credential"
12
+ end
13
+
14
+ #
15
+ # Loads a Rails credential configuration setting
16
+ #
17
+ # @param [String] key Configuration key to load
18
+ # @param [Array] dig_keys Variable keys to use to load from providers that accept a dig structure
19
+ # defaults to the lowercase key split by underscores
20
+ # "MY_PASSWORD" => ["my", "password"]
21
+ # @param [Hash] options Options Hash
22
+ #
23
+ # @return [Object] configuration setting value
24
+ #
25
+ def load(key, *dig_keys, **options)
26
+ super
27
+ ::Rails.application.credentials.config.dig(*dig_keys.map(&:to_sym))
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "container_config/provider/base"
4
+
5
+ module ContainerConfig
6
+ module Provider
7
+ # Secret volume mount config value provider
8
+ class SecretVolume < Base
9
+ # Default secret volume mount path used when globbing secret files
10
+ DEFAULT_SECRET_PATH = "/etc/*-secrets"
11
+
12
+ attr_accessor :default_directory, :directory
13
+
14
+ # @see ContainerConfig::Provider::Base#name
15
+ def name
16
+ "Secret Volume"
17
+ end
18
+
19
+ #
20
+ # Initializes a new ContainerConfig::Provider::SecretVolume
21
+ #
22
+ def initialize
23
+ super
24
+ @default_directory = DEFAULT_SECRET_PATH
25
+ @directory = nil
26
+ end
27
+
28
+ #
29
+ # Loads a secret volume mount configuration setting
30
+ #
31
+ # @param [String] key Configuration key to load
32
+ # @param [Array] dig_keys Variable keys to use to load from providers that accept a dig structure
33
+ # defaults to the lowercase key split by underscores
34
+ # "MY_PASSWORD" => ["my", "password"]
35
+ # @param [Hash] options Options Hash
36
+ # @option options [String] :secret_mount_directory directory where secret files are mounted
37
+ #
38
+ # @return [Object] configuration setting value
39
+ #
40
+ def load(key, *dig_keys, **options)
41
+ super
42
+ secret_file = Dir.glob(File.join(secret_mount_directory(**options), "**", key)).first
43
+ return if secret_file.nil? || !File.exist?(secret_file)
44
+
45
+ File.read(secret_file)
46
+ end
47
+
48
+ private
49
+
50
+ def secret_mount_directory(options)
51
+ options[:secret_mount_directory] ||
52
+ directory ||
53
+ ENV["SECRET_MOUNT_DIRECTORY"] ||
54
+ default_directory
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "container_config"
4
+ require "container_config/rails/mailer"
5
+
6
+ module ContainerConfig
7
+ # Rails configuration module
8
+ module Rails
9
+ end
10
+ end
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "container_config"
4
+
5
+ module ContainerConfig
6
+ module Rails
7
+ # Rails ActionMailer config module
8
+ module Mailer
9
+ #
10
+ # loads Rails ActionMailer configuration settings from environment variables, mounted secrets, or the application credentials
11
+ #
12
+ # @param [String] key base key for the Mailer config ("MAILER")
13
+ # @param [Hash] options Options Hash
14
+ # @option options [Boolean] :required whether to raise an exception if the settings cannot be found
15
+ # @option options [String] :secret_mount_directory directory where secret files are mounted
16
+ #
17
+ # @return [Hash] Mailer configuration hash with :perform_deliveries, :perform_caching, :raise_delivery_errors,
18
+ # :delivery_method, :sendmail_settings, and :smtp_settings keys
19
+ #
20
+ def self.load(key, **options)
21
+ mail_config = {}
22
+
23
+ mail_config[:perform_deliveries] = ContainerConfig.load("#{key}_PERFORM_DELIVERIES", default: ::Rails.env.production?, type: :boolean)
24
+ mail_config[:perform_caching] = ContainerConfig.load("#{key}_PERFORM_CACHING", default: false, type: :boolean)
25
+ mail_config[:raise_delivery_errors] = ContainerConfig.load("#{key}_RAISE_DELIVERY_ERRORS", default: false, type: :boolean)
26
+ mail_config[:delivery_method] = ContainerConfig.load("#{key}_DELIVERY_METHOD", default: :sendmail, type: :symbol, enum: %i[smtp sendmail])
27
+ mail_config[:sendmail_settings] = mailer_sendmail_settings(key, **options)
28
+ mail_config[:smtp_settings] = mailer_smtp_settings(key, **options)
29
+
30
+ mail_config.compact
31
+ end
32
+
33
+ class << self
34
+ private
35
+
36
+ #
37
+ # load Mailer sendmail settings
38
+ #
39
+ # @param [String] key base key for the Mailer sendmail config
40
+ # @param [Hash] options Options Hash
41
+ # @option options [Boolean] :required whether to raise an exception if the settings cannot be found
42
+ # @option options [String] :secret_mount_directory directory where secret files are mounted
43
+ #
44
+ # @return [Hash] Sendmail settings hash with :location and :arguments keys
45
+ #
46
+ def mailer_sendmail_settings(key, **options)
47
+ {
48
+ location: ContainerConfig.load("#{key}_SENDMAIL_LOCATION", **options),
49
+ arguments: ContainerConfig.load("#{key}_SENDMAIL_ARGUMENTS", **options)
50
+ }.compact
51
+ end
52
+
53
+ #
54
+ # load Mailer SMTP settings
55
+ #
56
+ # @param [String] key base key for the Mailer SMTP config
57
+ # @param [Hash] options Options Hash
58
+ # @option options [Boolean] :required whether to raise an exception if the settings cannot be found
59
+ # @option options [String] :secret_mount_directory directory where secret files are mounted
60
+ #
61
+ # @return [Hash] SMTP settings hash with :address, :port, :domain, :user_name, :password, :authentication,
62
+ # :enable_starttls_auto, :openssl_verify_mode, :ssl, and :tls keys
63
+ #
64
+ def mailer_smtp_settings(key, **options)
65
+ {
66
+ address: ContainerConfig.load("#{key}_SMTP_ADDRESS", **options),
67
+ port: ContainerConfig.load("#{key}_SMTP_PORT", **options, default: 25, type: :integer),
68
+ domain: ContainerConfig.load("#{key}_SMTP_DOMAIN", **options),
69
+ user_name: ContainerConfig.load("#{key}_SMTP_USER_NAME", **options),
70
+ password: ContainerConfig.load("#{key}_SMTP_PASSWORD", **options),
71
+ authentication: ContainerConfig.load("#{key}_SMTP_AUTHENTICATION", **options, type: :symbol, enum: [nil, :plain, :login, :cram_md5]),
72
+ enable_starttls_auto: ContainerConfig.load("#{key}_SMTP_ENABLE_STARTTLS_AUTO", **options, coerce_nil: false, type: :boolean),
73
+ openssl_verify_mode: ContainerConfig.load("#{key}_SMTP_OPENSSL_VERIFY_MODE", **options, coerce_nil: false, type: :ssl_verify_mode),
74
+ ssl: ContainerConfig.load("#{key}_SMTP_SSL", **options, coerce_nil: false, type: :boolean),
75
+ tls: ContainerConfig.load("#{key}_SMTP_TLS", **options, coerce_nil: false, type: :boolean)
76
+ }.compact
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,95 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "container_config"
4
+
5
+ module ContainerConfig
6
+ # Redis configuration module
7
+ module Redis
8
+ #
9
+ # Loads Redis configuration settings from environment variables, mounted secrets, or the application credentials
10
+ #
11
+ # @param [String] key base key for the Redis config ("QUEUE", "CACHE", etc.)
12
+ # @param [Hash] options Options Hash
13
+ # @option options [Boolean] :required whether to raise an exception if the settings cannot be found
14
+ # @option options [String] :secret_mount_directory directory where secret files are mounted
15
+ #
16
+ # @return [Hash] Redis configuration hash with :url, :password, and :sentinels keys
17
+ # See https://github.com/redis/redis-rb for more information
18
+ #
19
+ def self.load(key, **options)
20
+ host = ContainerConfig.load("#{key}_HOST", **options, default: "localhost")
21
+ port = ContainerConfig.load("#{key}_PORT", **options, default: "6379")
22
+
23
+ url = ContainerConfig.load("#{key}_URL", **options, default: "redis://#{host}:#{port}")
24
+ sentinels = sentinel_info(key, **options)
25
+ password = ContainerConfig.load("#{key}_PASSWORD", **options)
26
+
27
+ # Ensure we never pass an empty string to Redis since it will be passed to the Redis AUTH
28
+ # command as-is and will cause an exception
29
+ password = nil if password.to_s.strip.empty?
30
+
31
+ redis_config = { url: url, password: password }
32
+ redis_config[:sentinels] = sentinels unless sentinels.empty?
33
+
34
+ # Add SSL configuration
35
+ redis_config[:ssl] = ContainerConfig.load("#{key}_SSL", **options, default: false)
36
+ redis_config[:ssl_params] = ssl_params(key, **options)
37
+
38
+ redis_config
39
+ end
40
+
41
+ class << self
42
+ private
43
+
44
+ #
45
+ # Load Redis Sentinel configuration settings
46
+ #
47
+ # @param [String] key base key for the Redis Sentinel config
48
+ # @param [Hash] options Options Hash
49
+ # @option options [Boolean] :required whether to raise an exception if the settings cannot be found
50
+ # @option options [String] :secret_mount_directory directory where secret files are mounted
51
+ #
52
+ # @return [Array] Redis sentinel configuration hashes, may be empty if no sentinel config exists
53
+ # Each hash will have :host, :port, and :password keys
54
+ #
55
+ def sentinel_info(key, **options)
56
+ sentinel_hosts = ContainerConfig.load("#{key}_SENTINELS", **options, default: [])
57
+ sentinel_hosts = sentinel_hosts.split(",").map(&:strip) if sentinel_hosts.is_a?(String)
58
+
59
+ sentinel_port = ContainerConfig.load("#{key}_SENTINEL_PORT", **options, default: "26379")
60
+ sentinel_password = ContainerConfig.load("#{key}_SENTINEL_PASSWORD", **options)
61
+
62
+ # Ensure we never pass an empty string to Redis since it will be passed to the Redis sentinel AUTH
63
+ # command as-is and will cause an exception
64
+ sentinel_password = nil if sentinel_password.to_s.strip.empty?
65
+
66
+ ssl_params = ssl_params("#{key}_SENTINEL", **options)
67
+
68
+ sentinel_hosts.map { |h| { host: h, port: sentinel_port, password: sentinel_password, ssl_params: ssl_params } }
69
+ end
70
+
71
+ #
72
+ # Load Redis SSL parameters
73
+ #
74
+ # @param [String] key base key for the Redis/Redis Sentinel config
75
+ # @param [Hash] options Options Hash
76
+ # @option options [Boolean] :required whether to raise an exception if the settings cannot be found
77
+ # @option options [String] :secret_mount_directory directory where secret files are mounted
78
+ #
79
+ # @return [Hash] SSL parameter hash (see OpenSSL::SSL::SSLContext documentation)
80
+ #
81
+ def ssl_params(key, **options)
82
+ ssl_params = {
83
+ ca_file: ContainerConfig.load("#{key}_SSL_CA_FILE", **options),
84
+ ca_path: ContainerConfig.load("#{key}_SSL_CA_PATH", **options),
85
+ cert: ContainerConfig.load("#{key}_SSL_CERT", **options, type: :ssl_certificate),
86
+ key: ContainerConfig.load("#{key}_SSL_KEY", **options, type: :ssl_key),
87
+ verify_mode: ContainerConfig.load("#{key}_SSL_VERIFY_MODE", **options, type: :ssl_verify_mode)
88
+ }
89
+
90
+ # Reject all nil key values
91
+ ssl_params.compact
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ContainerConfig
4
+ # ContainerConfig version
5
+ VERSION = "0.1.0"
6
+ end
metadata ADDED
@@ -0,0 +1,167 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: container_config
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Matthew Newell
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2021-03-08 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rake
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '13.0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '13.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rspec
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '3.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '3.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rubocop
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.7'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.7'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rubocop-rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '0.5'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '0.5'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rubocop-rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '2.2'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '2.2'
83
+ - !ruby/object:Gem::Dependency
84
+ name: yard
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '0.9'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '0.9'
97
+ description: Loads container configuration values from environment variables, secrets,
98
+ and credentials.
99
+ email:
100
+ - matthewtnewell@gmail.com
101
+ executables: []
102
+ extensions: []
103
+ extra_rdoc_files: []
104
+ files:
105
+ - ".github/workflows/main.yml"
106
+ - ".gitignore"
107
+ - ".rspec"
108
+ - ".rubocop.yml"
109
+ - CHANGELOG.md
110
+ - Gemfile
111
+ - Gemfile.lock
112
+ - LICENSE.txt
113
+ - README.md
114
+ - Rakefile
115
+ - bin/console
116
+ - bin/setup
117
+ - container_config.gemspec
118
+ - lib/container_config.rb
119
+ - lib/container_config/coercer.rb
120
+ - lib/container_config/coercer/base.rb
121
+ - lib/container_config/coercer/boolean.rb
122
+ - lib/container_config/coercer/float.rb
123
+ - lib/container_config/coercer/integer.rb
124
+ - lib/container_config/coercer/ssl_certificate.rb
125
+ - lib/container_config/coercer/ssl_key.rb
126
+ - lib/container_config/coercer/ssl_verify_mode.rb
127
+ - lib/container_config/coercer/string.rb
128
+ - lib/container_config/coercer/symbol.rb
129
+ - lib/container_config/logger.rb
130
+ - lib/container_config/provider.rb
131
+ - lib/container_config/provider/base.rb
132
+ - lib/container_config/provider/default.rb
133
+ - lib/container_config/provider/env.rb
134
+ - lib/container_config/provider/rails_credential.rb
135
+ - lib/container_config/provider/secret_volume.rb
136
+ - lib/container_config/rails.rb
137
+ - lib/container_config/rails/mailer.rb
138
+ - lib/container_config/redis.rb
139
+ - lib/container_config/version.rb
140
+ homepage: https://github.com/wheatevo/container_config
141
+ licenses:
142
+ - MIT
143
+ metadata:
144
+ homepage_uri: https://github.com/wheatevo/container_config
145
+ source_code_uri: https://github.com/wheatevo/container_config
146
+ changelog_uri: https://github.com/wheatevo/container_config/blob/master/CHANGELOG.md
147
+ post_install_message:
148
+ rdoc_options: []
149
+ require_paths:
150
+ - lib
151
+ required_ruby_version: !ruby/object:Gem::Requirement
152
+ requirements:
153
+ - - ">="
154
+ - !ruby/object:Gem::Version
155
+ version: 2.4.0
156
+ required_rubygems_version: !ruby/object:Gem::Requirement
157
+ requirements:
158
+ - - ">="
159
+ - !ruby/object:Gem::Version
160
+ version: '0'
161
+ requirements: []
162
+ rubygems_version: 3.1.4
163
+ signing_key:
164
+ specification_version: 4
165
+ summary: Loads container configuration values from environment variables, secrets,
166
+ and credentials.
167
+ test_files: []