Class Puppet::Util::Settings
In: lib/puppet/util/settings.rb
Parent: Object

The class for handling configuration files.

Methods

Included Modules

Enumerable Puppet::Util

Classes and Modules

Class Puppet::Util::Settings::CBoolean
Class Puppet::Util::Settings::CElement
Class Puppet::Util::Settings::CFile

Attributes

file  [RW] 
timer  [R] 

Public Class methods

Create a new collection of config settings.

[Source]

     # File lib/puppet/util/settings.rb, line 197
197:     def initialize
198:         @config = {}
199:         @shortnames = {}
200:         
201:         @created = []
202:         @searchpath = nil
203: 
204:         # Mutex-like thing to protect @values
205:         @sync = Sync.new
206: 
207:         # Keep track of set values.
208:         @values = Hash.new { |hash, key| hash[key] = {} }
209: 
210:         # And keep a per-environment cache
211:         @cache = Hash.new { |hash, key| hash[key] = {} }
212: 
213:         # A central concept of a name.
214:         @name = nil
215: 
216:         # The list of sections we've used.
217:         @used = []
218:     end

Public Instance methods

Retrieve a config value

[Source]

    # File lib/puppet/util/settings.rb, line 16
16:     def [](param)
17:         value(param)
18:     end

Set a config value. This doesn‘t set the defaults, it sets the value itself.

[Source]

    # File lib/puppet/util/settings.rb, line 21
21:     def []=(param, value)
22:         param = symbolize(param)
23:         unless element = @config[param]
24:             raise ArgumentError,
25:                 "Attempt to assign a value to unknown configuration parameter %s" % param.inspect
26:         end
27:         if element.respond_to?(:munge)
28:             value = element.munge(value)
29:         end
30:         if element.respond_to?(:handle)
31:             element.handle(value)
32:         end
33:         # Reset the name, so it's looked up again.
34:         if param == :name
35:             @name = nil
36:         end
37:         @sync.synchronize do # yay, thread-safe
38:             @values[:memory][param] = value
39:             @cache.clear
40:         end
41: 
42:         return value
43:     end

Generate the list of valid arguments, in a format that GetoptLong can understand, and add them to the passed option list.

[Source]

    # File lib/puppet/util/settings.rb, line 47
47:     def addargs(options)
48:         # Hackish, but acceptable.  Copy the current ARGV for restarting.
49:         Puppet.args = ARGV.dup
50: 
51:         # Add all of the config parameters as valid options.
52:         self.each { |name, element|
53:             element.getopt_args.each { |args| options << args }
54:         }
55: 
56:         return options
57:     end

[Source]

    # File lib/puppet/util/settings.rb, line 59
59:     def apply
60:         trans = self.to_transportable
61:         begin
62:             config = trans.to_catalog
63:             config.store_state = false
64:             config.apply
65:             config.clear
66:         rescue => detail
67:             if Puppet[:trace]
68:                 puts detail.backtrace
69:             end
70:             Puppet.err "Could not configure myself: %s" % detail
71:         end
72:     end

Is our parameter a boolean parameter?

[Source]

    # File lib/puppet/util/settings.rb, line 75
75:     def boolean?(param)
76:         param = symbolize(param)
77:         if @config.include?(param) and @config[param].kind_of? CBoolean
78:             return true
79:         else
80:             return false
81:         end
82:     end

Remove all set values, potentially skipping cli values.

[Source]

     # File lib/puppet/util/settings.rb, line 85
 85:     def clear(exceptcli = false)
 86:         @sync.synchronize do
 87:             @values.each do |name, values|
 88:                 @values.delete(name) unless exceptcli and name == :cli
 89:             end
 90: 
 91:             # Don't clear the 'used' in this case, since it's a config file reparse,
 92:             # and we want to retain this info.
 93:             unless exceptcli
 94:                 @used = []
 95:             end
 96: 
 97:             @cache.clear
 98: 
 99:             @name = nil
100:         end
101:     end

This is mostly just used for testing.

[Source]

     # File lib/puppet/util/settings.rb, line 104
104:     def clearused
105:         @cache.clear
106:         @used = []
107:     end

Do variable interpolation on the value.

[Source]

     # File lib/puppet/util/settings.rb, line 110
110:     def convert(value, environment = nil)
111:         return value unless value
112:         return value unless value.is_a? String
113:         newval = value.gsub(/\$(\w+)|\$\{(\w+)\}/) do |value|
114:             varname = $2 || $1
115:             if varname == "environment" and environment
116:                 environment
117:             elsif pval = self.value(varname)
118:                 pval
119:             else
120:                 raise Puppet::DevError, "Could not find value for %s" % value
121:             end
122:         end
123: 
124:         return newval
125:     end

Return a value‘s description.

[Source]

     # File lib/puppet/util/settings.rb, line 128
128:     def description(name)
129:         if obj = @config[symbolize(name)]
130:             obj.desc
131:         else
132:             nil
133:         end
134:     end

[Source]

     # File lib/puppet/util/settings.rb, line 136
136:     def each
137:         @config.each { |name, object|
138:             yield name, object
139:         }
140:     end

Iterate over each section name.

[Source]

     # File lib/puppet/util/settings.rb, line 143
143:     def eachsection
144:         yielded = []
145:         @config.each do |name, object|
146:             section = object.section
147:             unless yielded.include? section
148:                 yield section
149:                 yielded << section
150:             end
151:         end
152:     end

Return an object by name.

[Source]

     # File lib/puppet/util/settings.rb, line 155
155:     def element(param)
156:         param = symbolize(param)
157:         @config[param]
158:     end

[Source]

     # File lib/puppet/util/settings.rb, line 258
258:     def generate_config
259:         puts to_config
260:         true
261:     end

[Source]

     # File lib/puppet/util/settings.rb, line 263
263:     def generate_manifest
264:         puts to_manifest
265:         true
266:     end

Handle a command-line argument.

[Source]

     # File lib/puppet/util/settings.rb, line 161
161:     def handlearg(opt, value = nil)
162:         @cache.clear
163:         value = munge_value(value) if value
164:         str = opt.sub(/^--/,'')
165:         bool = true
166:         newstr = str.sub(/^no-/, '')
167:         if newstr != str
168:             str = newstr
169:             bool = false
170:         end
171:         str = str.intern
172:         if self.valid?(str)
173:             @sync.synchronize do
174:                 if self.boolean?(str)
175:                     @values[:cli][str] = bool
176:                 else
177:                     @values[:cli][str] = value
178:                 end
179:             end
180:         else
181:             raise ArgumentError, "Invalid argument %s" % opt
182:         end
183:     end

[Source]

     # File lib/puppet/util/settings.rb, line 185
185:     def include?(name)
186:         name = name.intern if name.is_a? String
187:         @config.include?(name)
188:     end

Return a given object‘s file metadata.

[Source]

     # File lib/puppet/util/settings.rb, line 279
279:     def metadata(param)
280:         if obj = @config[symbolize(param)] and obj.is_a?(CFile)
281:             return [:owner, :group, :mode].inject({}) do |meta, p|
282:                 if v = obj.send(p)
283:                     meta[p] = v
284:                 end
285:                 meta
286:             end
287:         else
288:             nil
289:         end
290:     end

Make a directory with the appropriate user, group, and mode

[Source]

     # File lib/puppet/util/settings.rb, line 293
293:     def mkdir(default)
294:         obj = get_config_file_default(default)
295: 
296:         Puppet::Util::SUIDManager.asuser(obj.owner, obj.group) do
297:             mode = obj.mode || 0750
298:             Dir.mkdir(obj.value, mode)
299:         end
300:     end

Figure out our name.

[Source]

     # File lib/puppet/util/settings.rb, line 303
303:     def name
304:         unless @name
305:             unless @config[:name]
306:                 return nil
307:             end
308:             searchpath.each do |source|
309:                 next if source == :name
310:                 @sync.synchronize do
311:                     @name = @values[source][:name]
312:                 end
313:                 break if @name
314:             end
315:             unless @name
316:                 @name = convert(@config[:name].default).intern
317:             end
318:         end
319:         @name
320:     end

Parse the configuration file. As of May 2007, this is a backward-compatibility method and will be deprecated soon.

[Source]

     # File lib/puppet/util/settings.rb, line 390
390:     def old_parse(file)
391:         text = nil
392: 
393:         if file.is_a? Puppet::Util::LoadedFile
394:             @file = file
395:         else
396:             @file = Puppet::Util::LoadedFile.new(file)
397:         end
398: 
399:         # Don't create a timer for the old style parsing.
400:         # settimer()
401: 
402:         begin
403:             text = File.read(@file.file)
404:         rescue Errno::ENOENT
405:             raise Puppet::Error, "No such file %s" % file
406:         rescue Errno::EACCES
407:             raise Puppet::Error, "Permission denied to file %s" % file
408:         end
409: 
410:         @sync.synchronize do
411:             @values = Hash.new { |names, name|
412:                 names[name] = {}
413:             }
414:         end
415: 
416:         # Get rid of the values set by the file, keeping cli values.
417:         self.clear(true)
418: 
419:         section = "puppet"
420:         metas = %w{owner group mode}
421:         values = Hash.new { |hash, key| hash[key] = {} }
422:         @sync.synchronize do
423:             text.split(/\n/).each { |line|
424:                 case line
425:                 when /^\[(\w+)\]$/: section = $1 # Section names
426:                 when /^\s*#/: next # Skip comments
427:                 when /^\s*$/: next # Skip blanks
428:                 when /^\s*(\w+)\s*=\s*(.+)$/: # settings
429:                     var = $1.intern
430:                     if var == :mode
431:                         value = $2
432:                     else
433:                         value = munge_value($2)
434:                     end
435: 
436:                     # Only warn if we don't know what this config var is.  This
437:                     # prevents exceptions later on.
438:                     unless @config.include?(var) or metas.include?(var.to_s)
439:                         Puppet.warning "Discarded unknown configuration parameter %s" % var.inspect
440:                         next # Skip this line.
441:                     end
442: 
443:                     # Mmm, "special" attributes
444:                     if metas.include?(var.to_s)
445:                         unless values.include?(section)
446:                             values[section] = {}
447:                         end
448:                         values[section][var.to_s] = value
449: 
450:                         # If the parameter is valid, then set it.
451:                         if section == Puppet[:name] and @config.include?(var)
452:                             #@config[var].value = value
453:                             @values[:main][var] = value
454:                         end
455:                         next
456:                     end
457: 
458:                     # Don't override set parameters, since the file is parsed
459:                     # after cli arguments are handled.
460:                     unless @config.include?(var) and @config[var].setbycli
461:                         Puppet.debug "%s: Setting %s to '%s'" % [section, var, value]
462:                         @values[:main][var] = value
463:                     end
464:                     @config[var].section = symbolize(section)
465: 
466:                     metas.each { |meta|
467:                         if values[section][meta]
468:                             if @config[var].respond_to?(meta + "=")
469:                                 @config[var].send(meta + "=", values[section][meta])
470:                             end
471:                         end
472:                     }
473:                 else
474:                     raise Puppet::Error, "Could not match line %s" % line
475:                 end
476:             }
477:         end
478:     end

Return all of the parameters associated with a given section.

[Source]

     # File lib/puppet/util/settings.rb, line 323
323:     def params(section = nil)
324:         if section
325:             section = section.intern if section.is_a? String
326:             @config.find_all { |name, obj|
327:                 obj.section == section
328:             }.collect { |name, obj|
329:                 name
330:             }
331:         else
332:             @config.keys
333:         end
334:     end

Parse the configuration file. Just provides thread safety.

[Source]

     # File lib/puppet/util/settings.rb, line 338
338:     def parse(file)
339:         # We have to clear outside of the sync, because it's
340:         # also using synchronize().
341:         clear(true)
342: 
343:         @sync.synchronize do
344:             unsafe_parse(file)
345:         end
346:     end

Iterate across all of the objects in a given section.

[Source]

     # File lib/puppet/util/settings.rb, line 506
506:     def persection(section)
507:         section = symbolize(section)
508:         self.each { |name, obj|
509:             if obj.section == section
510:                 yield obj
511:             end
512:         }
513:     end

Prints the contents of a config file with the available config elements, or it prints a single value of a config element.

[Source]

     # File lib/puppet/util/settings.rb, line 227
227:     def print_config_options
228:         env = value(:environment)
229:         val = value(:configprint)
230:         if val == "all"
231:             hash = {}
232:             each do |name, obj|
233:                 val = value(name,env)
234:                 val = val.inspect if val == ""
235:                 hash[name] = val
236:             end
237:             hash.sort { |a,b| a[0].to_s <=> b[0].to_s }.each do |name, val|
238:                 puts "%s = %s" % [name, val]
239:             end
240:         else
241:             val.split(/\s*,\s*/).sort.each do |v|
242:                 if include?(v)
243:                     #if there is only one value, just print it for back compatibility
244:                     if v == val
245:                          puts value(val,env)
246:                          break
247:                     end
248:                     puts "%s = %s" % [v, value(v,env)]
249:                 else
250:                     puts "invalid parameter: %s" % v
251:                     return false
252:                 end
253:             end
254:         end
255:         true
256:     end

[Source]

     # File lib/puppet/util/settings.rb, line 268
268:     def print_configs
269:         return print_config_options if value(:configprint) != ""
270:         return generate_config if value(:genconfig)
271:         return generate_manifest if value(:genmanifest)
272:     end

[Source]

     # File lib/puppet/util/settings.rb, line 274
274:     def print_configs?
275:         return (value(:configprint) != "" || value(:genconfig) || value(:genmanifest)) && true
276:     end

[Source]

     # File lib/puppet/util/settings.rb, line 843
843:     def readwritelock(default, *args, &bloc)
844:         file = value(get_config_file_default(default).name)
845:         tmpfile = file + ".tmp"
846:         sync = Sync.new
847:         unless FileTest.directory?(File.dirname(tmpfile))
848:             raise Puppet::DevError, "Cannot create %s; directory %s does not exist" %
849:                 [file, File.dirname(file)]
850:         end
851: 
852:         sync.synchronize(Sync::EX) do
853:             File.open(file, "r+", 0600) do |rf|
854:                 rf.lock_exclusive do
855:                     if File.exist?(tmpfile)
856:                         raise Puppet::Error, ".tmp file already exists for %s; Aborting locked write. Check the .tmp file and delete if appropriate" %
857:                             [file]
858:                     end
859: 
860:                     writesub(default, tmpfile, *args, &bloc)
861: 
862:                     begin
863:                         File.rename(tmpfile, file)
864:                     rescue => detail
865:                         Puppet.err "Could not rename %s to %s: %s" %
866:                             [file, tmpfile, detail]
867:                     end
868:                 end
869:             end
870:         end
871:     end

Reparse our config file, if necessary.

[Source]

     # File lib/puppet/util/settings.rb, line 516
516:     def reparse
517:         if defined? @file and @file.changed?
518:             Puppet.notice "Reparsing %s" % @file.file
519:             @sync.synchronize do
520:                 parse(@file)
521:             end
522:             reuse()
523:         end
524:     end

[Source]

     # File lib/puppet/util/settings.rb, line 526
526:     def reuse
527:         return unless defined? @used
528:         @sync.synchronize do # yay, thread-safe
529:             @used.each do |section|
530:                 @used.delete(section)
531:                 self.use(section)
532:             end
533:         end
534:     end

The order in which to search for values.

[Source]

     # File lib/puppet/util/settings.rb, line 537
537:     def searchpath(environment = nil)
538:         if environment
539:             [:cli, :memory, environment, :name, :main]
540:         else
541:             [:cli, :memory, :name, :main]
542:         end
543:     end

Convert a single section into transportable objects.

[Source]

     # File lib/puppet/util/settings.rb, line 561
561:     def section_to_transportable(section, done = nil)
562:         done ||= Hash.new { |hash, key| hash[key] = {} }
563:         objects = []
564:         persection(section) do |obj|
565:             if @config[:mkusers] and value(:mkusers)
566:                 objects += add_user_resources(section, obj, done)
567:             end
568: 
569:             value = obj.value
570: 
571:             # Only files are convertable to transportable resources.
572:             next unless obj.respond_to? :to_transportable and transobjects = obj.to_transportable
573: 
574:             transobjects = [transobjects] unless transobjects.is_a? Array
575:             transobjects.each do |trans|
576:                 # transportable could return nil
577:                 next unless trans
578:                 unless done[:file].include? trans.name
579:                     @created << trans.name
580:                     objects << trans
581:                     done[:file][trans.name] = trans
582:                 end
583:             end
584:         end
585: 
586:         bucket = Puppet::TransBucket.new
587:         bucket.type = "Settings"
588:         bucket.name = section
589:         bucket.push(*objects)
590:         bucket.keyword = "class"
591: 
592:         return bucket
593:     end

Get a list of objects per section

[Source]

     # File lib/puppet/util/settings.rb, line 546
546:     def sectionlist
547:         sectionlist = []
548:         self.each { |name, obj|
549:             section = obj.section || "puppet"
550:             sections[section] ||= []
551:             unless sectionlist.include?(section)
552:                 sectionlist << section
553:             end
554:             sections[section] << obj
555:         }
556: 
557:         return sectionlist, sections
558:     end

Set a bunch of defaults in a given section. The sections are actually pretty pointless, but they help break things up a bit, anyway.

[Source]

     # File lib/puppet/util/settings.rb, line 597
597:     def setdefaults(section, defs)
598:         section = symbolize(section)
599:         call = []
600:         defs.each { |name, hash|
601:             if hash.is_a? Array
602:                 unless hash.length == 2
603:                     raise ArgumentError, "Defaults specified as an array must contain only the default value and the decription"
604:                 end
605:                 tmp = hash
606:                 hash = {}
607:                 [:default, :desc].zip(tmp).each { |p,v| hash[p] = v }
608:             end
609:             name = symbolize(name)
610:             hash[:name] = name
611:             hash[:section] = section
612:             if @config.include?(name)
613:                 raise ArgumentError, "Parameter %s is already defined" % name
614:             end
615:             tryconfig = newelement(hash)
616:             if short = tryconfig.short
617:                 if other = @shortnames[short]
618:                     raise ArgumentError, "Parameter %s is already using short name '%s'" % [other.name, short]
619:                 end
620:                 @shortnames[short] = tryconfig
621:             end
622:             @config[name] = tryconfig
623: 
624:             # Collect the settings that need to have their hooks called immediately.
625:             # We have to collect them so that we can be sure we're fully initialized before
626:             # the hook is called.
627:             call << tryconfig if tryconfig.call_on_define
628:         }
629: 
630:         call.each { |setting| setting.handle(self.value(setting.name)) }
631:     end

Create a timer to check whether the file should be reparsed.

[Source]

     # File lib/puppet/util/settings.rb, line 634
634:     def settimer
635:         if Puppet[:filetimeout] > 0
636:             @timer = Puppet.newtimer(
637:                 :interval => Puppet[:filetimeout],
638:                 :tolerance => 1,
639:                 :start? => true
640:             ) do
641:                 self.reparse()
642:             end
643:         end
644:     end

check to see if a short name is already defined

[Source]

     # File lib/puppet/util/settings.rb, line 191
191:     def shortinclude?(short)
192:         short = short.intern if name.is_a? String
193:         @shortnames.include?(short)
194:     end

Convert our list of config elements into a configuration file.

[Source]

     # File lib/puppet/util/settings.rb, line 653
653:     def to_config
654:         str = %{The configuration file for #{Puppet[:name]}.  Note that this file
655: is likely to have unused configuration parameters in it; any parameter that's
656: valid anywhere in Puppet can be in any config file, even if it's not used.
657: 
658: Every section can specify three special parameters: owner, group, and mode.
659: These parameters affect the required permissions of any files specified after
660: their specification.  Puppet will sometimes use these parameters to check its
661: own configured state, so they can be used to make Puppet a bit more self-managing.
662: 
663: Generated on #{Time.now}.
664: 
665: }.gsub(/^/, "# ")
666: 
667:         # Add a section heading that matches our name.
668:         if @config.include?(:name)
669:             str += "[%s]\n" % self[:name]
670:         end
671:         eachsection do |section|
672:             persection(section) do |obj|
673:                 str += obj.to_config + "\n"
674:             end
675:         end
676: 
677:         return str
678:     end

Convert our list of objects into a component that can be applied.

[Source]

     # File lib/puppet/util/settings.rb, line 647
647:     def to_configuration
648:         transport = self.to_transportable
649:         return transport.to_catalog
650:     end

Convert to a parseable manifest

[Source]

     # File lib/puppet/util/settings.rb, line 710
710:     def to_manifest
711:         transport = self.to_transportable
712: 
713:         manifest = transport.to_manifest + "\n"
714:         eachsection { |section|
715:             manifest += "include #{section}\n"
716:         }
717: 
718:         return manifest
719:     end

Convert our configuration into a list of transportable objects.

[Source]

     # File lib/puppet/util/settings.rb, line 681
681:     def to_transportable(*sections)
682:         done = Hash.new { |hash, key|
683:             hash[key] = {}
684:         }
685: 
686:         topbucket = Puppet::TransBucket.new
687:         if defined? @file.file and @file.file
688:             topbucket.name = @file.file
689:         else
690:             topbucket.name = "top"
691:         end
692:         topbucket.type = "Settings"
693:         topbucket.top = true
694: 
695:         # Now iterate over each section
696:         if sections.empty?
697:             eachsection do |section|
698:                 sections << section
699:             end
700:         end
701:         sections.each do |section|
702:             obj = section_to_transportable(section, done)
703:             topbucket.push obj
704:         end
705: 
706:         topbucket
707:     end

Create the necessary objects to use a section. This is idempotent; you can ‘use’ a section as many times as you want.

[Source]

     # File lib/puppet/util/settings.rb, line 723
723:     def use(*sections)
724:         @sync.synchronize do # yay, thread-safe
725:             sections = sections.reject { |s| @used.include?(s.to_sym) }
726: 
727:             return if sections.empty?
728: 
729:             bucket = to_transportable(*sections)
730: 
731:             begin
732:                 catalog = bucket.to_catalog
733:             rescue => detail
734:                 puts detail.backtrace if Puppet[:trace]
735:                 Puppet.err "Could not create resources for managing Puppet's files and directories: %s" % detail
736: 
737:                 # We need some way to get rid of any resources created during the catalog creation
738:                 # but not cleaned up.
739:                 return
740:             end
741: 
742:             begin
743:                 catalog.host_config = false
744:                 catalog.apply do |transaction|
745:                     if transaction.any_failed?
746:                         report = transaction.report
747:                         failures = report.logs.find_all { |log| log.level == :err }
748:                         raise "Got %s failure(s) while initializing: %s" % [failures.length, failures.collect { |l| l.to_s }.join("; ")] 
749:                     end
750:                 end
751:             ensure
752:                 catalog.clear
753:             end
754: 
755:             sections.each { |s| @used << s }
756:             @used.uniq!
757:         end
758:     end

[Source]

     # File lib/puppet/util/settings.rb, line 760
760:     def valid?(param)
761:         param = symbolize(param)
762:         @config.has_key?(param)
763:     end

Find the correct value using our search path. Optionally accept an environment in which to search before the other configuration sections.

[Source]

     # File lib/puppet/util/settings.rb, line 767
767:     def value(param, environment = nil)
768:         param = symbolize(param)
769:         environment = symbolize(environment) if environment
770: 
771:         # Short circuit to nil for undefined parameters.
772:         return nil unless @config.include?(param)
773: 
774:         # Yay, recursion.
775:         self.reparse() unless param == :filetimeout
776: 
777:         # Check the cache first.  It needs to be a per-environment
778:         # cache so that we don't spread values from one env
779:         # to another.
780:         if cached = @cache[environment||"none"][param]
781:             return cached
782:         end
783: 
784:         # See if we can find it within our searchable list of values
785:         val = catch :foundval do
786:             each_source(environment) do |source|
787:                 # Look for the value.  We have to test the hash for whether
788:                 # it exists, because the value might be false.
789:                 @sync.synchronize do
790:                     if @values[source].include?(param)
791:                         throw :foundval, @values[source][param]
792:                     end
793:                 end
794:             end
795:             throw :foundval, nil
796:         end
797:         
798:         # If we didn't get a value, use the default
799:         val = @config[param].default if val.nil?
800: 
801:         # Convert it if necessary
802:         val = convert(val, environment)
803: 
804:         # And cache it
805:         @cache[environment||"none"][param] = val
806:         return val
807:     end

Open a file with the appropriate user, group, and mode

[Source]

     # File lib/puppet/util/settings.rb, line 810
810:     def write(default, *args, &bloc)
811:         obj = get_config_file_default(default)
812: