diff --git a/REFERENCE.md b/REFERENCE.md index 7d7b672790..9b460e543e 100644 --- a/REFERENCE.md +++ b/REFERENCE.md @@ -1526,7 +1526,6 @@ The following parameters are available in the `postgresql::server::config_entry` * [`key`](#-postgresql--server--config_entry--key) * [`value`](#-postgresql--server--config_entry--value) * [`path`](#-postgresql--server--config_entry--path) -* [`comment`](#-postgresql--server--config_entry--comment) ##### `ensure` @@ -1560,14 +1559,6 @@ Path for postgresql.conf Default value: `$postgresql::server::postgresql_conf_path` -##### `comment` - -Data type: `Optional[String[1]]` - -Defines the comment for the setting. The # is added by default. - -Default value: `undef` - ### `postgresql::server::database` Define for creating a database. @@ -4309,12 +4300,6 @@ This type allows puppet to manage postgresql.conf parameters. The following properties are available in the `postgresql_conf` type. -##### `comment` - -Valid values: `%r{^[\w\W]+$}` - -The comment to set for this parameter. - ##### `ensure` Valid values: `present`, `absent` @@ -4323,9 +4308,11 @@ The basic property that the resource should be in. Default value: `present` -##### `value` +##### `target` -Valid values: `%r{^\S(.*\S)?$}` +The path to postgresql.conf + +##### `value` The value to set for this parameter. @@ -4333,16 +4320,8 @@ The value to set for this parameter. The following parameters are available in the `postgresql_conf` type. -* [`key`](#-postgresql_conf--key) * [`name`](#-postgresql_conf--name) * [`provider`](#-postgresql_conf--provider) -* [`target`](#-postgresql_conf--target) - -##### `key` - -Valid values: `%r{^[\w.]+$}` - -The Postgresql parameter to manage. ##### `name` @@ -4350,19 +4329,13 @@ Valid values: `%r{^[\w.]+$}` namevar -A unique title for the resource. +The postgresql parameter name to manage. ##### `provider` The specific backend to use for this `postgresql_conf` resource. You will seldom need to specify this --- Puppet will usually discover the appropriate provider for your platform. -##### `target` - -Valid values: `%r{^/\S+[a-z0-9(/)-]*\w+.conf$}` - -The path to the postgresql config file - ### `postgresql_conn_validator` Verify that a connection can be successfully established between a node diff --git a/examples/multiple_confs.pp b/examples/multiple_confs.pp new file mode 100644 index 0000000000..954f25eb52 --- /dev/null +++ b/examples/multiple_confs.pp @@ -0,0 +1,20 @@ +postgresql_conf { '/tmp/first-postgresql.conf:other': + value => 'bla', +} + +postgresql_conf { '/tmp/first-postgresql.conf:port': + value => 5432, +} + +postgresql_conf { '/tmp/second-postgresql.conf:other': + value => 'bla', +} + +postgresql_conf { '/tmp/second-postgresql.conf:port': + value => 5433, +} + +# TODO: make target optional +#postgresql_conf { 'port': +# value => 5434, +#} diff --git a/lib/puppet/provider/postgresql_conf/parsed.rb b/lib/puppet/provider/postgresql_conf/parsed.rb new file mode 100644 index 0000000000..787125072c --- /dev/null +++ b/lib/puppet/provider/postgresql_conf/parsed.rb @@ -0,0 +1,45 @@ +# frozen_string_literal: true + +require 'puppet/provider/parsedfile' + +Puppet::Type.type(:postgresql_conf).provide( + :parsed, + parent: Puppet::Provider::ParsedFile, + default_target: '/etc/postgresql.conf', + filetype: :flat, +) do + desc 'Set key/values in postgresql.conf.' + + text_line :comment, match: %r{^\s*#} + text_line :blank, match: %r{^\s*$} + + record_line :parsed, + fields: ['key', 'value', 'comment'], + optional: ['comment'], + match: %r{^\s*([\w.]+)\s*=?\s*(.*?)(?:\s*#\s*(.*))?\s*$}, + to_line: proc { |h| + # simple string and numeric values don't need to be enclosed in quotes + val = if h[:value].is_a?(Numeric) + h[:value].to_s + elsif h[:value].is_a?(Array) + # multiple listen_addresses specified as a string containing a comma-speparated list + h[:value].join(', ') + else + h[:value] + end + dontneedquote = val.match(%r{^(\d+.?\d+|\w+)$}) + dontneedequal = h[:key].match(%r{^(include|include_if_exists)$}i) + + str = h[:key].downcase # normalize case + str += dontneedequal ? ' ' : ' = ' + str += "'" unless dontneedquote && !dontneedequal + str += val + str += "'" unless dontneedquote && !dontneedequal + str += " # #{h[:comment]}" unless h[:comment].nil? || h[:comment] == :absent + str + }, + post_parse: proc { |h| + h[:key].downcase! # normalize case + h[:value].gsub!(%r{(^'|'$)}, '') # strip out quotes + } +end diff --git a/lib/puppet/provider/postgresql_conf/ruby.rb b/lib/puppet/provider/postgresql_conf/ruby.rb deleted file mode 100644 index 63b87478d1..0000000000 --- a/lib/puppet/provider/postgresql_conf/ruby.rb +++ /dev/null @@ -1,167 +0,0 @@ -# frozen_string_literal: true - -# This provider is used to manage postgresql.conf files -# It uses ruby to parse the config file and -# to add, remove or modify settings. -# -# The provider is able to parse postgresql.conf files with the following format: -# key = value # comment - -Puppet::Type.type(:postgresql_conf).provide(:ruby) do - desc 'Set keys, values and comments in a postgresql config file.' - confine kernel: 'Linux' - - # The function pareses the postgresql.conf and figures out which active settings exist in a config file and returns an array of hashes - # - def parse_config - # open the config file - file = File.open(resource[:target]) - # regex to match active keys, values and comments - active_values_regex = %r{^\s*(?[\w.]+)\s*=?\s*(?.*?)(?:\s*#\s*(?.*))?\s*$} - # empty array to be filled with hashes - active_settings = [] - # iterate the file and construct a hash for every matching/active setting - # the hash is pushed to the array and the array is returned - File.foreach(file).with_index do |line, index| - line_number = index + 1 - matches = line.match(active_values_regex) - if matches - value = if matches[:value].to_i.to_s == matches[:value] - matches[:value].to_i - elsif matches[:value].to_f.to_s == matches[:value] - matches[:value].to_f - else - matches[:value].delete("'") - end - attributes_hash = { line_number: line_number, key: matches[:key], ensure: 'present', value: value, comment: matches[:comment] } - active_settings.push(attributes_hash) - end - end - Puppet.debug("DEBUG: parse_config Active Settings found in Postgreql config file: #{active_settings}") - active_settings - end - - # Deletes an existing header from a parsed postgresql.conf configuration file - # - # @param [Array] lines of the parsed postgresql configuration file - def delete_header(lines) - header_regex = %r{^# HEADER:.*} - lines.delete_if do |entry| - entry.match?(header_regex) - end - end - - # Adds a header to a parsed postgresql.conf configuration file, after all other changes are made - # - # @param [Array] lines of the parsed postgresql configuration file - def add_header(lines) - timestamp = Time.now.strftime('%F %T %z') - header = ["# HEADER: This file was autogenerated at #{timestamp}\n", - "# HEADER: by puppet. While it can still be managed manually, it\n", - "# HEADER: is definitely not recommended.\n"] - header + lines - end - - # This function writes the config file, it removes the old header, adds a new one and writes the file - # - # @param [File] the file object of the postgresql configuration file - # @param [Array] lines of the parsed postgresql configuration file - def write_config(file, lines) - lines = delete_header(lines) - lines = add_header(lines) - File.write(file, lines.join) - end - - # check, if resource exists in postgresql.conf file - def exists? - select = parse_config.select { |hash| hash[:key] == resource[:key] } - raise ParserError, "found multiple config items of #{resource[:key]} found, please fix this" if select.length > 1 - return false if select.empty? - - @result = select.first - Puppet.debug("DEBUG: exists? @result: #{@result}") - true - end - - # remove resource if exists and is set to absent - def destroy - entry_regex = %r{#{resource[:key]}.*=.*#{resource[:value]}} - file = File.open(resource[:target]) - lines = File.readlines(file) - - lines.delete_if do |entry| - entry.match?(entry_regex) - end - write_config(file, lines) - end - - # create resource if it does not exists - def create - file = File.open(resource[:target]) - lines = File.readlines(file) - new_line = line(key: resource[:key], value: resource[:value], comment: resource[:comment]) - - lines.push(new_line) - write_config(file, lines) - end - - # getter - get value of a resource - def value - @result[:value] - end - - # getter - get comment of a resource - def comment - @result[:comment] - end - - # setter - set value of a resource - def value=(_value) - file = File.open(resource[:target]) - lines = File.readlines(file) - active_values_regex = %r{^\s*(?[\w.]+)\s*=?\s*(?.*?)(?:\s*#\s*(?.*))?\s*$} - new_line = line(key: resource[:key], value: resource[:value], comment: resource[:comment]) - - lines.each_with_index do |line, index| - matches = line.to_s.match(active_values_regex) - lines[index] = new_line if matches && (matches[:key] == resource[:key] && matches[:value] != resource[:value]) - end - write_config(file, lines) - end - - # setter - set comment of a resource - def comment=(_comment) - file = File.open(resource[:target]) - lines = File.readlines(file) - active_values_regex = %r{^\s*(?[\w.]+)\s*=?\s*(?.*?)(?:\s*#\s*(?.*))?\s*$} - new_line = line(key: resource[:key], value: resource[:value], comment: resource[:comment]) - - lines.each_with_index do |line, index| - matches = line.to_s.match(active_values_regex) - lines[index] = new_line if matches && (matches[:key] == resource[:key] && matches[:comment] != resource[:comment]) - end - write_config(file, lines) - end - - private - - # Takes elements for a postgresql.conf configuration line and formats them properly - # - # @param [String] key postgresql.conf configuration option - # @param [String] value the value for the configuration option - # @param [String] comment optional comment that will be added at the end of the line - # @return [String] line the whole line for the config file, with \n - def line(key: '', value: '', comment: nil) - value = value.to_s if value.is_a?(Numeric) - dontneedquote = value.match(%r{^(\d+.?\d+|\w+)$}) - dontneedequal = key.match(%r{^(include|include_if_exists)$}i) - line = key.downcase # normalize case - line += dontneedequal ? ' ' : ' = ' - line += "'" unless dontneedquote && !dontneedequal - line += value - line += "'" unless dontneedquote && !dontneedequal - line += " # #{comment}" unless comment.nil? || comment == :absent - line += "\n" - line - end -end diff --git a/lib/puppet/type/postgresql_conf.rb b/lib/puppet/type/postgresql_conf.rb index 432f5aa877..cf0c0bb172 100644 --- a/lib/puppet/type/postgresql_conf.rb +++ b/lib/puppet/type/postgresql_conf.rb @@ -2,40 +2,36 @@ Puppet::Type.newtype(:postgresql_conf) do @doc = 'This type allows puppet to manage postgresql.conf parameters.' + ensurable - newparam(:name) do - desc 'A unique title for the resource.' - newvalues(%r{^[\w.]+$}) + def self.title_patterns + [ + [ /^(.+\.conf):([\w.]+)$/m, [ [:target], [:key] ] ], + # TODO: make target optional + #[ /^([\w.]+)$/m, [ [:key] ] ], + ] end - newparam(:key) do - desc 'The Postgresql parameter to manage.' + + newparam(:key, namevar: true) do + desc 'The postgresql parameter name to manage.' + isrequired newvalues(%r{^[\w.]+$}) end newproperty(:value) do desc 'The value to set for this parameter.' - newvalues(%r{^\S(.*\S)?$}) + end - munge do |value| - if value.to_i.to_s == value - value.to_i - elsif value.to_f.to_s == value - value.to_f + newparam(:target, namevar: true) do + desc 'The path to postgresql.conf' + defaultto do + if @resource.class.defaultprovider.ancestors.include?(Puppet::Provider::ParsedFile) + @resource.class.defaultprovider.default_target else - value + nil end end end - - newproperty(:comment) do - desc 'The comment to set for this parameter.' - newvalues(%r{^[\w\W]+$}) - end - - newparam(:target) do - desc 'The path to the postgresql config file' - newvalues(%r{^/\S+[a-z0-9(/)-]*\w+.conf$}) - end end diff --git a/manifests/server/config_entry.pp b/manifests/server/config_entry.pp index d17b844a18..65cd68315c 100644 --- a/manifests/server/config_entry.pp +++ b/manifests/server/config_entry.pp @@ -4,14 +4,12 @@ # @param key Defines the key/name for the setting. Defaults to $name # @param value Defines the value for the setting. # @param path Path for postgresql.conf -# @param comment Defines the comment for the setting. The # is added by default. # define postgresql::server::config_entry ( - Enum['present', 'absent'] $ensure = 'present', - String[1] $key = $name, - Optional[Variant[String[1], Numeric, Array[String[1]]]] $value = undef, - Stdlib::Absolutepath $path = $postgresql::server::postgresql_conf_path, - Optional[String[1]] $comment = undef, + Enum['present', 'absent'] $ensure = 'present', + String[1] $key = $name, + Optional[Variant[String[1], Numeric, Array[String[1]]]] $value = undef, + Stdlib::Absolutepath $path = $postgresql::server::postgresql_conf_path ) { # Those are the variables that are marked as "(change requires restart)" # on postgresql.conf. Items are ordered as on postgresql.conf. @@ -87,9 +85,8 @@ postgresql_conf { $name: ensure => $ensure, target => $path, - key => $key, + name => $key, value => $value, - comment => $comment, require => Class['postgresql::server::initdb'], } } diff --git a/spec/unit/provider/postgresql_conf/parsed_spec.rb b/spec/unit/provider/postgresql_conf/parsed_spec.rb new file mode 100644 index 0000000000..7f6fdaef05 --- /dev/null +++ b/spec/unit/provider/postgresql_conf/parsed_spec.rb @@ -0,0 +1,151 @@ +# frozen_string_literal: true + +require 'spec_helper' +require 'tempfile' + +provider_class = Puppet::Type.type(:postgresql_conf).provider(:parsed) + +describe provider_class do + let(:title) { 'postgresql_conf' } + let(:provider) do + conf_class = Puppet::Type.type(:postgresql_conf) + provider = conf_class.provider(:parsed) + conffile = tmpfilename('postgresql.conf') + allow_any_instance_of(provider).to receive(:target).and_return conffile # rubocop:disable RSpec/AnyInstance + provider + end + + after :each do + provider.initvars + end + + describe 'simple configuration that should be allowed' do + it 'parses a simple ini line' do + expect(provider.parse_line("listen_addreses = '*'")).to eq( + name: 'listen_addreses', value: '*', comment: nil, record_type: :parsed, + ) + end + + it 'parses a simple ini line (2)' do + expect(provider.parse_line(" listen_addreses = '*'")).to eq( + name: 'listen_addreses', value: '*', comment: nil, record_type: :parsed, + ) + end + + it 'parses a simple ini line (3)' do + expect(provider.parse_line("listen_addreses = '*' # dont mind me")).to eq( + name: 'listen_addreses', value: '*', comment: 'dont mind me', record_type: :parsed, + ) + end + + it 'parses a comment' do + expect(provider.parse_line('# dont mind me')).to eq( + line: '# dont mind me', record_type: :comment, + ) + end + + it 'parses a comment (2)' do + expect(provider.parse_line(" \t# dont mind me")).to eq( + line: " \t# dont mind me", record_type: :comment, + ) + end + + it 'allows includes' do + expect(provider.parse_line('include puppetextra')).to eq( + name: 'include', value: 'puppetextra', comment: nil, record_type: :parsed, + ) + end + + it 'allows numbers through without quotes' do + expect(provider.parse_line('wal_keep_segments = 32')).to eq( + name: 'wal_keep_segments', value: '32', comment: nil, record_type: :parsed, + ) + end + + it 'allows blanks through' do + expect(provider.parse_line('')).to eq( + line: '', record_type: :blank, + ) + end + + it 'parses keys with dots' do + expect(provider.parse_line('auto_explain.log_min_duration = 1ms')).to eq( + name: 'auto_explain.log_min_duration', value: '1ms', comment: nil, record_type: :parsed, + ) + end + end + + describe 'configuration that should be set' do + it 'sets comment lines' do + expect(provider.to_line(line: '# dont mind me', record_type: :comment)).to eq( + '# dont mind me', + ) + end + + it 'sets blank lines' do + expect(provider.to_line(line: '', record_type: :blank)).to eq( + '', + ) + end + + it 'sets simple configuration' do + expect(provider.to_line(name: 'listen_addresses', value: '*', comment: nil, record_type: :parsed)).to eq( + "listen_addresses = '*'", + ) + end + + it 'sets simple configuration with period in name' do + expect(provider.to_line(name: 'auto_explain.log_min_duration', value: '100ms', comment: nil, record_type: :parsed)).to eq( + 'auto_explain.log_min_duration = 100ms', + ) + end + + it 'sets simple configuration even with comments' do + expect(provider.to_line(name: 'listen_addresses', value: '*', comment: 'dont mind me', record_type: :parsed)).to eq( + "listen_addresses = '*' # dont mind me", + ) + end + + it 'quotes includes' do + expect(provider.to_line(name: 'include', value: 'puppetextra', comment: nil, record_type: :parsed)).to eq( + "include 'puppetextra'", + ) + end + + it 'quotes multiple words' do + expect(provider.to_line(name: 'archive_command', value: 'rsync up', comment: nil, record_type: :parsed)).to eq( + "archive_command = 'rsync up'", + ) + end + + it 'does not quote numbers' do + expect(provider.to_line(name: 'wal_segments', value: '32', comment: nil, record_type: :parsed)).to eq( + 'wal_segments = 32', + ) + end + + it 'allows numbers' do + expect(provider.to_line(name: 'integer', value: 42, comment: nil, record_type: :parsed)).to eq( + 'integer = 42', + ) + end + + it 'allows floats' do + expect(provider.to_line(name: 'float', value: 2.71828182845, comment: nil, record_type: :parsed)).to eq( + 'float = 2.71828182845', + ) + end + + it 'quotes single string address' do + expect(provider.to_line(name: 'listen_addresses', value: '0.0.0.0', comment: nil, record_type: :parsed)).to eq( + "listen_addresses = '0.0.0.0'", + ) + end + + it 'quotes an array of addresses' do + expect(provider.to_line(name: 'listen_addresses', value: ['0.0.0.0', '127.0.0.1'], comment: nil, record_type: :parsed)).to eq( + "listen_addresses = '0.0.0.0, 127.0.0.1'", + ) + end + end +end diff --git a/spec/unit/provider/postgresql_conf/ruby_spec.rb b/spec/unit/provider/postgresql_conf/ruby_spec.rb deleted file mode 100644 index 11800b0fc7..0000000000 --- a/spec/unit/provider/postgresql_conf/ruby_spec.rb +++ /dev/null @@ -1,60 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' -provider_class = Puppet::Type.type(:postgresql_conf).provider(:ruby) - -describe provider_class do - let(:resource) { Puppet::Type.type(:postgresql_conf).new(name: 'foo', value: 'bar') } - let(:provider) { resource.provider } - - before(:each) do - allow(provider).to receive(:file_path).and_return('/tmp/foo') - allow(provider).to receive(:read_file).and_return('foo = bar') - allow(provider).to receive(:write_file).and_return(true) - end - # rubocop:enable RSpec/ReceiveMessages - - it 'has a method parse_config' do - expect(provider).to respond_to(:parse_config) - end - - it 'has a method delete_header' do - expect(provider).to respond_to(:delete_header) - end - - it 'has a method add_header' do - expect(provider).to respond_to(:add_header) - end - - it 'has a method exists?' do - expect(provider).to respond_to(:exists?) - end - - it 'has a method create' do - expect(provider).to respond_to(:create) - end - - it 'has a method destroy' do - expect(provider).to respond_to(:destroy) - end - - it 'has a method value' do - expect(provider).to respond_to(:value) - end - - it 'has a method value=' do - expect(provider).to respond_to(:value=) - end - - it 'has a method comment' do - expect(provider).to respond_to(:comment) - end - - it 'has a method comment=' do - expect(provider).to respond_to(:comment=) - end - - it 'is an instance of the Provider Ruby' do - expect(provider).to be_an_instance_of Puppet::Type::Postgresql_conf::ProviderRuby - end -end diff --git a/spec/unit/type/postgresql_conf_spec.rb b/spec/unit/type/postgresql_conf_spec.rb index 9ce4269bfa..179c369740 100644 --- a/spec/unit/type/postgresql_conf_spec.rb +++ b/spec/unit/type/postgresql_conf_spec.rb @@ -24,13 +24,13 @@ end describe 'when validating attributes' do - [:name, :provider, :target].each do |param| + [:name, :provider].each do |param| it "has a #{param} parameter" do expect(described_class.attrtype(param)).to eq(:param) end end - [:value, :comment].each do |property| + [:value, :target].each do |property| it "has a #{property} property" do expect(described_class.attrtype(property)).to eq(:property) end pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy