Class: CemAcpt::Config::Base

Inherits:
Object
  • Object
show all
Defined in:
lib/cem_acpt/config/base.rb

Overview

Base class for other config classes Child classes should provide the following constant:

- VALID_KEYS - provide an array of valid top-level keys for the config as symbols

Child classes should implement the following methods:

- defaults - provide a hash of default values for the config
- env_var_prefix - provide a string to prefix environment variables with (defaults to 'CEM_ACPT').
                   This will be converted to uppercase, have all non-alphanumeric characters replaced with
                   underscores, and be joined with the key name with an underscore to form the environment
                   variable name.

However, they can override any of the methods in this class.

Direct Known Subclasses

CemAcpt, CemAcptImage

Constant Summary collapse

BASE_VALID_KEYS =
%i[
  ci_mode
  config_file
  log_level
  log_file
  log_format
  no_destroy_nodes
  no_ephemeral_ssh_key
  platform
  provisioner
  puppet
  quiet
  secrets
  terraform
  user_config
  verbose
].freeze
DEEP_MERGE_OPTS =
{
  overwrite_arrays: true,
  merge_nil_values: true,
}.freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(opts: {}, config_file: nil, load_user_config: true) ⇒ Base

Returns a new instance of Base.



85
86
87
88
89
# File 'lib/cem_acpt/config/base.rb', line 85

def initialize(opts: {}, config_file: nil, load_user_config: true)
  @load_user_config = load_user_config
  @explanation = {}
  load(opts: opts, config_file: config_file)
end

Instance Attribute Details

#configObject Also known as: to_h

Returns the value of attribute config.



83
84
85
# File 'lib/cem_acpt/config/base.rb', line 83

def config
  @config
end

#env_varsObject (readonly)

Returns the value of attribute env_vars.



83
84
85
# File 'lib/cem_acpt/config/base.rb', line 83

def env_vars
  @env_vars
end

Class Method Details

.inherited(subclass) ⇒ Object



69
70
71
# File 'lib/cem_acpt/config/base.rb', line 69

def self.inherited(subclass)
  subclass.instance_variable_set(:@load_hook, nil)
end

.load_hook(&block) ⇒ Object

Add a block to be called after the config is loaded but before it is validated and frozen. The block will be passed the config hash and can be used to modify the config before it is finalized.



75
76
77
78
79
80
81
# File 'lib/cem_acpt/config/base.rb', line 75

def self.load_hook(&block)
  if block_given?
    @load_hook = block
  else
    @load_hook
  end
end

Instance Method Details

#[](key) ⇒ Object



165
166
167
168
169
170
171
172
173
# File 'lib/cem_acpt/config/base.rb', line 165

def [](key)
  if key.is_a?(Symbol)
    @config[key].dup
  elsif key.is_a?(String)
    get(key)
  else
    raise ArgumentError, "Invalid key type '#{key.class}'"
  end
end

#ci_mode?Boolean Also known as: ci?

Returns:

  • (Boolean)


188
189
190
# File 'lib/cem_acpt/config/base.rb', line 188

def ci_mode?
  !!get('ci_mode') || !!(ENV['GITHUB_ACTIONS'] || ENV['CI'])
end

#debug_mode?Boolean Also known as: debug?

Returns:

  • (Boolean)


193
194
195
# File 'lib/cem_acpt/config/base.rb', line 193

def debug_mode?
  get('log_level') == 'debug'
end

#defaultsHash

Returns The default configuration.

Returns:

  • (Hash)

    The default configuration



110
111
112
# File 'lib/cem_acpt/config/base.rb', line 110

def defaults
  {}
end

#empty?Boolean

Returns:

  • (Boolean)


184
185
186
# File 'lib/cem_acpt/config/base.rb', line 184

def empty?
  @config.empty?
end

#env_var_prefixString

Returns The prefix for environment variables.

Returns:

  • (String)

    The prefix for environment variables



96
97
98
# File 'lib/cem_acpt/config/base.rb', line 96

def env_var_prefix
  'CEM_ACPT'
end

#explainObject

Returns a string representation of how the config was loaded



159
160
161
162
163
# File 'lib/cem_acpt/config/base.rb', line 159

def explain
  @explanation.each_with_object([]) { |(key, values), ary|
    ary << "#{key}:\n  -->#{values.join("\n  -->")}"
  }.join("\n")
end

#get(dot_key) ⇒ Object Also known as: dget



175
176
177
# File 'lib/cem_acpt/config/base.rb', line 175

def get(dot_key)
  @dot_key_cache[dot_key] ||= @config.dget(dot_key).dup
end

#has?(dot_key) ⇒ Boolean

Returns:

  • (Boolean)


180
181
182
# File 'lib/cem_acpt/config/base.rb', line 180

def has?(dot_key)
  !!get(dot_key)
end

#inspectObject



91
92
93
# File 'lib/cem_acpt/config/base.rb', line 91

def inspect
  "#<#{self.class}:#{object_id.to_s(16)}>"
end

#load(opts: {}, config_file: nil) ⇒ self

Load the configuration from the environment variables, config file, and opts The order of precedence is:

1. static options (set in this class)
2. Runtime options
3. Runtime config file
4. User config file
5. Environment variables
6. Defaults

Parameters:

  • opts (Hash) (defaults to: {})

    The options to load

  • config_file (String) (defaults to: nil)

    The config file to load

Returns:

  • (self)

    This object with the config loaded



125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
# File 'lib/cem_acpt/config/base.rb', line 125

def load(opts: {}, config_file: nil)
  create_config_dirs!
  init_config!(opts: opts, config_file: config_file)
  add_env_vars!(@config)
  @config.deep_merge!(user_config, **DEEP_MERGE_OPTS) if user_config && @load_user_config
  @config.deep_merge!(config_from_file, **DEEP_MERGE_OPTS) if config_from_file
  if @options
    @config.deep_merge!(@options, **DEEP_MERGE_OPTS)
    @options.each do |key, _value|
      add_config_explanation(key, "runtime option")
    end
  end
  add_static_options!(@config)
  # Run the load hook if it is defined. This allows child classes to modify the config after it has been loaded
  # but before it is validated and frozen.
  block = self.class.load_hook
  instance_eval(&block) if block
  @config.format! # Symbolize keys of all hashes
  # Remove any keys that are not in the valid keys list for this config. This prevents invalid config options
  # from being set.
  @config.select! { |key, _| valid_keys.include?(key) }
  # Wrap secrets in the config with the Secret class to prevent them from being accidentally printed in logs
  # or error messages. WARNING: Secrets can leak from Terraform logging.
  wrap_secrets!
  validate_config!
  @dot_key_cache = {}
  # Freeze the config so it can't be modified
  # This helps with thread safety and deterministic behavior
  @config.freeze
  self
end

#quiet_mode?Boolean Also known as: quiet?

Returns:

  • (Boolean)


203
204
205
# File 'lib/cem_acpt/config/base.rb', line 203

def quiet_mode?
  !!get('quiet')
end

#to_json(*args, expose_secrets: false) ⇒ Object



215
216
217
218
219
220
# File 'lib/cem_acpt/config/base.rb', line 215

def to_json(*args, expose_secrets: false)
  return @config.to_json(*args) unless @config.key?(:secrets)

  serializable_secrets = @config[:secrets].transform_values { |v| v.is_a?(Secret) ? (expose_secrets ? v.value : v.to_s) : v }
  @config.merge(secrets: serializable_secrets).to_json(*args)
end

#to_yaml(expose_secrets: false) ⇒ Object



208
209
210
211
212
213
# File 'lib/cem_acpt/config/base.rb', line 208

def to_yaml(expose_secrets: false)
  return @config.to_yaml unless @config.key?(:secrets)

  serializable_secrets = @config[:secrets].transform_values { |v| v.is_a?(Secret) ? (expose_secrets ? v.value : v.to_s) : v }
  @config.merge(secrets: serializable_secrets).to_yaml
end

#valid_keysArray<Symbol>

Returns Valid top-level keys for the config.

Returns:

  • (Array<Symbol>)

    Valid top-level keys for the config



101
102
103
104
105
106
107
# File 'lib/cem_acpt/config/base.rb', line 101

def valid_keys
  if self.class.const_defined?(:VALID_KEYS)
    (BASE_VALID_KEYS + self.class.const_get(:VALID_KEYS)).uniq
  else
    BASE_VALID_KEYS
  end
end

#verbose_mode?Boolean Also known as: verbose?

Returns:

  • (Boolean)


198
199
200
# File 'lib/cem_acpt/config/base.rb', line 198

def verbose_mode?
  !!get('verbose')
end