From 9c76b6af1200c71e7ae72e0e2f349919a3081738 Mon Sep 17 00:00:00 2001 From: Chris Price Date: Sat, 28 Jul 2012 21:59:54 -0700 Subject: First (basic) working version of ini_setting provider --- lib/puppet/provider/ini_setting/ruby.rb | 19 +++++ lib/puppet/type/ini_setting.rb | 26 +++++++ lib/puppet/util/external_iterator.rb | 24 ++++++ lib/puppet/util/ini_file.rb | 132 ++++++++++++++++++++++++++++++++ lib/puppet/util/ini_file/section.rb | 34 ++++++++ 5 files changed, 235 insertions(+) create mode 100644 lib/puppet/util/external_iterator.rb create mode 100644 lib/puppet/util/ini_file.rb create mode 100644 lib/puppet/util/ini_file/section.rb (limited to 'lib') diff --git a/lib/puppet/provider/ini_setting/ruby.rb b/lib/puppet/provider/ini_setting/ruby.rb index e69de29..e44a107 100644 --- a/lib/puppet/provider/ini_setting/ruby.rb +++ b/lib/puppet/provider/ini_setting/ruby.rb @@ -0,0 +1,19 @@ +require 'puppet/util/ini_file' + +Puppet::Type.type(:ini_setting).provide(:ruby) do + def exists? + ini_file.get_value(resource[:section], resource[:setting]) == resource[:value] + end + + def create + ini_file.set_value(resource[:section], resource[:setting], resource[:value]) + ini_file.save + @ini_file = nil + end + + + private + def ini_file + @ini_file ||= Puppet::Util::IniFile.new(resource[:path]) + end +end diff --git a/lib/puppet/type/ini_setting.rb b/lib/puppet/type/ini_setting.rb index fb7f6e2..9af47c1 100644 --- a/lib/puppet/type/ini_setting.rb +++ b/lib/puppet/type/ini_setting.rb @@ -4,4 +4,30 @@ Puppet::Type.newtype(:ini_setting) do defaultvalues defaultto :present end + + newparam(:name, :namevar => true) do + desc 'An arbitrary name used as the identity of the resource.' + end + + newparam(:section) do + desc 'The name of the section in the ini file in which the setting should be defined.' + end + + newparam(:setting) do + desc 'The name of the setting to be defined.' + end + + newparam(:value) do + desc 'The value of the setting to be defined.' + end + + newparam(:path) do + desc 'The ini file Puppet will ensure contains the specified setting.' + validate do |value| + unless (Puppet.features.posix? and value =~ /^\//) or (Puppet.features.microsoft_windows? and (value =~ /^.:\// or value =~ /^\/\/[^\/]+\/[^\/]+/)) + raise(Puppet::Error, "File paths must be fully qualified, not '#{value}'") + end + end + end + end \ No newline at end of file diff --git a/lib/puppet/util/external_iterator.rb b/lib/puppet/util/external_iterator.rb new file mode 100644 index 0000000..67b3375 --- /dev/null +++ b/lib/puppet/util/external_iterator.rb @@ -0,0 +1,24 @@ +module Puppet +module Util + class ExternalIterator + def initialize(coll) + @coll = coll + @cur_index = 0 + end + + def next + @cur_index = @cur_index + 1 + item_at(@cur_index) + end + + def peek + item_at(@cur_index + 1) + end + + private + def item_at(index) + [@coll[index], index] + end + end +end +end diff --git a/lib/puppet/util/ini_file.rb b/lib/puppet/util/ini_file.rb new file mode 100644 index 0000000..75d8a9f --- /dev/null +++ b/lib/puppet/util/ini_file.rb @@ -0,0 +1,132 @@ +require 'puppet/util/external_iterator' +require 'puppet/util/ini_file/section' + +module Puppet +module Util + class IniFile + + SECTION_REGEX = /^\s*\[([\w\d\.]+)\]\s*$/ + SETTING_REGEX = /^\s*([\w\d\.]+)\s*=\s*([\w\d\.]+)\s*$/ + + def initialize(path) + @path = path + @section_names = [] + @sections_hash = {} + + parse_file + end + + def section_names + @section_names + end + + def get_value(section_name, setting) + if (@sections_hash.has_key?(section_name)) + @sections_hash[section_name].get_value(setting) + end + end + + def set_value(section_name, setting, value) + unless (@sections_hash.has_key?(section_name)) + add_section(Section.new(section_name, nil, nil, nil)) + end + + section = @sections_hash[section_name] + if (section.has_existing_setting?(setting)) + update_line(section, setting, value) + section.update_existing_setting(setting, value) + else + section.set_additional_setting(setting, value) + end + end + + def save + File.open(@path, 'w') do |fh| + first_section = @sections_hash[@section_names[0]] + (0..first_section.start_line - 1).each do |line_num| + fh.puts(lines[line_num]) + end + + @section_names.each do |name| + section = @sections_hash[name] + + if (section.start_line.nil?) + fh.puts("\n[#{section.name}]") + else + (section.start_line..section.end_line).each do |line_num| + fh.puts(lines[line_num]) + end + end + + section.additional_settings.each_pair do |key, value| + fh.puts("#{key} = #{value}") + end + end + end + end + + + private + def add_section(section) + @sections_hash[section.name] = section + @section_names << section.name + end + + def parse_file + line_iter = create_line_iter + line, line_num = line_iter.next + while line + if (match = SECTION_REGEX.match(line)) + section = read_section(match[1], line_num, line_iter) + add_section(section) + end + line, line_num = line_iter.next + end + end + + def read_section(name, start_line, line_iter) + settings = {} + while true + line, line_num = line_iter.peek + if (line.nil? or match = SECTION_REGEX.match(line)) + return Section.new(name, start_line, line_num - 1, settings) + elsif (match = SETTING_REGEX.match(line)) + settings[match[1]] = match[2] + end + + line_iter.next + end + end + + def update_line(section, setting, value) + (section.start_line..section.end_line).each do |line_num| + if (match = SETTING_REGEX.match(lines[line_num])) + if (match[1] == setting) + lines[line_num] = "#{setting} = #{value}" + end + end + end + end + + def create_line_iter + ExternalIterator.new(lines) + end + + def lines + @lines ||= IniFile.readlines(@path) + end + + # This is mostly here because it makes testing easier--we don't have + # to try to stub any methods on File. + def self.readlines(path) + # If this type is ever used with very large files, we should + # write this in a different way, using a temp + # file; for now assuming that this type is only used on + # small-ish config files that can fit into memory without + # too much trouble. + File.readlines(path) + end + + end +end +end \ No newline at end of file diff --git a/lib/puppet/util/ini_file/section.rb b/lib/puppet/util/ini_file/section.rb new file mode 100644 index 0000000..39f2959 --- /dev/null +++ b/lib/puppet/util/ini_file/section.rb @@ -0,0 +1,34 @@ +module Puppet +module Util +class IniFile + class Section + def initialize(name, start_line, end_line, settings) + @name = name + @start_line = start_line + @end_line = end_line + @existing_settings = settings.nil? ? {} : settings + @additional_settings = {} + end + + attr_reader :name, :start_line, :end_line, :additional_settings + + def get_value(setting_name) + @existing_settings[setting_name] || @additional_settings[setting_name] + end + + def has_existing_setting?(setting_name) + @existing_settings.has_key?(setting_name) + end + + def update_existing_setting(setting_name, value) + @existing_settings[setting_name] = value + end + + def set_additional_setting(setting_name, value) + @additional_settings[setting_name] = value + end + + end +end +end +end \ No newline at end of file -- cgit v1.2.3