-
Notifications
You must be signed in to change notification settings - Fork 611
/
Copy pathruby.rb
167 lines (147 loc) · 6.05 KB
/
ruby.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
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
156
157
158
159
160
161
162
163
164
165
166
167
# 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*(?<key>[\w.]+)\s*=?\s*(?<value>.*?)(?:\s*#\s*(?<comment>.*))?\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*(?<key>[\w.]+)\s*=?\s*(?<value>.*?)(?:\s*#\s*(?<comment>.*))?\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*(?<key>[\w.]+)\s*=?\s*(?<value>.*?)(?:\s*#\s*(?<comment>.*))?\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