Class: PDK::Config

Inherits:
Object
  • Object
show all
Defined in:
lib/pdk/config.rb,
lib/pdk/config/json.rb,
lib/pdk/config/yaml.rb,
lib/pdk/config/errors.rb,
lib/pdk/config/setting.rb,
lib/pdk/config/ini_file.rb,
lib/pdk/config/namespace.rb,
lib/pdk/config/validator.rb,
lib/pdk/config/ini_file_setting.rb,
lib/pdk/config/json_with_schema.rb,
lib/pdk/config/yaml_with_schema.rb,
lib/pdk/config/json_schema_setting.rb,
lib/pdk/config/json_schema_namespace.rb

Defined Under Namespace

Modules: Validator Classes: IniFile, IniFileSetting, JSON, JSONSchemaNamespace, JSONSchemaSetting, JSONWithSchema, LoadError, Namespace, Setting, YAML, YAMLWithSchema

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = nil) ⇒ Config

Create a new instance of the PDK Configuration

Parameters:

  • options (Hash[String => Object]) (defaults to: nil)

    Optional hash to override configuration options

Options Hash (options):

  • 'system.path' (String)

    Path to the system PDK configuration file

  • 'system.module_defaults.path' (String)

    Path to the system module answers PDK configuration file

  • 'user.path' (String)

    Path to the user PDK configuration file

  • 'user.module_defaults.path' (String)

    Path to the user module answers PDK configuration file

  • 'user.analytics.path' (String)

    Path to the user analytics PDK configuration file

  • 'context' (PDK::Context::AbstractContext)

    The context that the configuration should be created in



24
25
26
27
28
29
30
31
32
33
34
# File 'lib/pdk/config.rb', line 24

def initialize(options = nil)
  options = {} if options.nil?
  @config_options = {
    'system.path' => PDK::Config.system_config_path,
    'system.module_defaults.path' => PDK::Config.system_answers_path,
    'user.path' => PDK::Config.user_config_path,
    'user.module_defaults.path' => PDK::AnswerFile.default_answer_file_path,
    'user.analytics.path' => PDK::Config.analytics_config_path,
    'context' => PDK.context
  }.merge(options)
end

Class Method Details

.analytics_config_exist?Boolean

Returns:

  • (Boolean)


227
228
229
# File 'lib/pdk/config.rb', line 227

def self.analytics_config_exist?
  PDK::Util::Filesystem.file?(analytics_config_path)
end

.analytics_config_interview!Object



231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
# File 'lib/pdk/config.rb', line 231

def self.analytics_config_interview!
  require 'pdk/cli/util'

  return unless PDK::CLI::Util.interactive?

  pre_message =
    format('PDK collects anonymous usage information to help us understand how ' \
           'it is being used and make decisions on how to improve it. You can ' \
           'find out more about what data we collect and how it is used in the ' \
           "PDK documentation at %{url}.\n", url: 'https://puppet.com/docs/pdk/latest/pdk_install.html')
  post_message =
    format('You can opt in or out of the usage data collection at any time by ' \
           'editing the analytics configuration file at %{path} and changing ' \
           "the '%{key}' value.", path: PDK::Config.analytics_config_path, key: 'disabled')

  questions = [
    {
      name: 'enabled',
      question: 'Do you consent to the collection of anonymous PDK usage information?',
      type: :yes
    }
  ]

  require 'pdk/cli/util/interview'

  PDK.logger.info(text: pre_message, wrap: true)
  prompt = TTY::Prompt.new(help_color: :cyan)
  interview = PDK::CLI::Util::Interview.new(prompt)
  interview.add_questions(questions)
  answers = interview.run

  if answers.nil?
    PDK.logger.info 'No answer given, opting out of analytics collection.'
    PDK.config.set(['user', 'analytics', 'disabled'], true)
  else
    PDK.config.set(['user', 'analytics', 'disabled'], !answers['enabled'])
  end

  PDK.logger.info(text: post_message, wrap: true)
end

.analytics_config_pathObject



202
203
204
# File 'lib/pdk/config.rb', line 202

def self.analytics_config_path
  PDK::Util::Env['PDK_ANALYTICS_CONFIG'] || File.join(File.dirname(PDK::Util.configdir), 'puppet', 'analytics.yml')
end

.bolt_analytics_configObject



194
195
196
197
198
199
200
# File 'lib/pdk/config.rb', line 194

def self.bolt_analytics_config
  file = PDK::Util::Filesystem.expand_path('~/.puppetlabs/bolt/analytics.yaml')
  PDK::Config::YAML.new(file: file)
rescue PDK::Config::LoadError => e
  PDK.logger.debug format('Unable to load %{file}: %{message}', file: file, message: e.message)
  PDK::Config::YAML.new
end

.json_schema(name) ⇒ Object

return nil if not exist



223
224
225
# File 'lib/pdk/config.rb', line 223

def self.json_schema(name)
  File.join(json_schemas_path, "#{name}_schema.json")
end

.json_schemas_pathObject



218
219
220
# File 'lib/pdk/config.rb', line 218

def self.json_schemas_path
  File.join(__dir__, 'config')
end

.system_answers_pathObject



214
215
216
# File 'lib/pdk/config.rb', line 214

def self.system_answers_path
  File.join(PDK::Util.system_configdir, 'answers.json')
end

.system_config_pathObject



210
211
212
# File 'lib/pdk/config.rb', line 210

def self.system_config_path
  File.join(PDK::Util.system_configdir, 'system_config.json')
end

.user_config_pathObject



206
207
208
# File 'lib/pdk/config.rb', line 206

def self.user_config_path
  File.join(PDK::Util.configdir, 'user_config.json')
end

Instance Method Details

#get(root, *keys) ⇒ PDK::Config::Namespace, ...

Returns a configuration setting by name. This name can either be a String, Array or parameters e.g. These are equivalent

  • PDK.config.get(‘user.a.b.c’)

  • PDK.config.get([‘user’, ‘a’, ‘b’, ‘c’])

  • PDK.config.get(‘user’, ‘a’, ‘b’, ‘c’)

Parameters:

  • root (Array[String], String)

    The root setting name or the entire setting name as a single string

  • keys (String)

    The child names of the setting

Returns:

  • (PDK::Config::Namespace, Object, nil)

    The value of the configuration setting. Returns nil if it does no exist



121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# File 'lib/pdk/config.rb', line 121

def get(root, *keys)
  return nil if root.nil? || root.empty?

  if keys.empty?
    case root
    when Array
      name = root
    when String
      name = split_key_string(root)
    else
      return nil
    end
  else
    name = [root].concat(keys)
  end

  get_within_scopes(name[1..], [name[0]])
end

#get_within_scopes(setting_name, scopes = nil) ⇒ PDK::Config::Namespace, ...

Returns a configuration setting by name, using scope precedence rules. If no scopes are passed, then all scopes are queried using the default precedence rules

Returns:

  • (PDK::Config::Namespace, Object, nil)

    The value of the configuration setting. Returns nil if it does no exist

Raises:

  • (ArgumentError)


144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
# File 'lib/pdk/config.rb', line 144

def get_within_scopes(setting_name, scopes = nil)
  raise ArgumentError, format('Expected an Array but got \'%{klass}\' for scopes', klass: scopes.class) unless scopes.nil? || scopes.is_a?(Array)
  raise ArgumentError, format('Expected an Array or String but got \'%{klass}\' for setting_name', klass: setting_name.class) unless setting_name.is_a?(Array) || setting_name.is_a?(String)

  setting_arr = setting_name.is_a?(String) ? split_key_string(setting_name) : setting_name
  all_scope_names = all_scopes.keys

  # Use only valid scope names
  scopes = scopes.nil? ? all_scope_names : scopes & all_scope_names

  scopes.each do |scope_name|
    value = traverse_object(send(all_scopes[scope_name]), *setting_arr)
    return value unless value.nil?
  end
  nil
end

#project_configPDK::Config::Namespace

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

The project level configuration settings.



91
92
93
94
95
96
97
98
99
100
101
102
# File 'lib/pdk/config.rb', line 91

def project_config
  context = @config_options['context']
  @project ||= PDK::Config::Namespace.new('project') do
    mount :environment, PDK::ControlRepo.environment_conf_as_config(File.join(context.root_path, 'environment.conf')) if context.is_a?(PDK::Context::ControlRepo)

    mount :validate, PDK::Config::YAML.new('validate', file: File.join(context.root_path, 'pdk.yaml'), persistent_defaults: true) do
      setting 'ignore' do
        default_to { [] }
      end
    end
  end
end

#resolve(filter = nil) ⇒ Hash{String => Object}

Resolves all filtered settings from all namespaces

Parameters:

  • filter (String) (defaults to: nil)

    Only resolve setting names which match the filter. See PDK::Config::Namespace.be_resolved? for matching rules

Returns:

  • (Hash{String => Object})

    All resolved settings for example => ‘johndoe’



108
109
110
111
112
# File 'lib/pdk/config.rb', line 108

def resolve(filter = nil)
  all_scopes.values.reverse.reduce({}) do |result, method_name|
    result.merge(send(method_name).resolve(filter))
  end
end

#set(key, value, options = {}) ⇒ Object

Sets a configuration setting by name. This name can either be a String or an Array

  • PDK.config.set(‘user.a.b.c’, …)

  • PDK.config.set([‘user’, ‘a’, ‘b’, ‘c’], …)

Parameters:

  • key (String, Array[String])

    The name of the configuration key to change

  • value (Object)

    The value to set the configuration setting to

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

    Changes the behaviour of the setting process

Options Hash (options):

  • :force (Boolean)

    Disables any munging or array processing, and sets the value as it is. Default is false

Returns:

  • (Object)

    The new value of the configuration setting

Raises:

  • (ArgumentError)


180
181
182
183
184
185
186
187
188
189
190
191
192
# File 'lib/pdk/config.rb', line 180

def set(key, value, options = {})
  options = {
    force: false
  }.merge(options)

  names = key.is_a?(String) ? split_key_string(key) : key
  raise ArgumentError, 'Invalid configuration names' if names.nil? || !names.is_a?(Array) || names.empty?

  scope_name = names[0]
  raise ArgumentError, format("Unknown configuration root '%{name}'", name: scope_name) if all_scopes[scope_name].nil?

  deep_set_object(value, options[:force], send(all_scopes[scope_name]), *names[1..])
end

#system_configPDK::Config::Namespace

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

The system level configuration settings.



39
40
41
42
43
44
# File 'lib/pdk/config.rb', line 39

def system_config
  local_options = @config_options
  @system_config ||= PDK::Config::JSON.new('system', file: local_options['system.path']) do
    mount :module_defaults, PDK::Config::JSON.new(file: local_options['system.module_defaults.path'])
  end
end

#user_configPDK::Config::Namespace

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

The user level configuration settings.



49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/pdk/config.rb', line 49

def user_config
  local_options = @config_options
  @user_config ||= PDK::Config::JSON.new('user', file: local_options['user.path']) do
    mount :module_defaults, PDK::Config::JSON.new(file: local_options['user.module_defaults.path'])

    # Due to the json-schema gem having issues with Windows based paths, and only supporting Draft 05 (or less) do
    # not use JSON validation yet.  Once PDK drops support for EOL rubies, we will be able to use the json_schemer gem
    # Which has much more modern support
    # Reference - https://github.com/puppetlabs/pdk/pull/777
    # Reference - https://tickets.puppetlabs.com/browse/PDK-1526
    mount :analytics, PDK::Config::YAML.new(file: local_options['user.analytics.path'], persistent_defaults: true) do
      setting :disabled do
        validate PDK::Config::Validator.boolean
        default_to { PDK::Config.bolt_analytics_config.fetch('disabled', true) }
      end

      setting 'user-id' do
        validate PDK::Config::Validator.uuid
        default_to do
          require 'securerandom'

          PDK::Config.bolt_analytics_config.fetch('user-id', SecureRandom.uuid)
        end
      end
    end

    # Display the feature flags
    mount :pdk_feature_flags, PDK::Config::Namespace.new('pdk_feature_flags') do
      setting 'available' do
        default_to { PDK.available_feature_flags }
      end

      setting 'requested' do
        default_to { PDK.requested_feature_flags }
      end
    end
  end
end

#with_scoped_value(setting_name, scopes = nil) {|PDK::Config::Namespace, Object| ... } ⇒ Object

Yields a configuration setting value by name, using scope precedence rules. If no scopes are passed, then all scopes are queried using the default precedence rules

Yields:

  • (PDK::Config::Namespace, Object)

    The value of the configuration setting. Does not yield if the setting does not exist or is nil

Raises:

  • (ArgumentError)


165
166
167
168
169
170
# File 'lib/pdk/config.rb', line 165

def with_scoped_value(setting_name, scopes = nil)
  raise ArgumentError, 'must be passed a block' unless block_given?

  value = get_within_scopes(setting_name, scopes)
  yield value unless value.nil?
end