Class: ExternalNode

Inherits:
Object show all
Defined in:
ext/regexp_nodes/regexp_nodes.rb

Overview

This class holds all the methods for creating and accessing the properties of an external node. There are really only two public methods: initialize and a special version of to_yaml

Direct Known Subclasses

MyExternalNode

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(hostname, classdir = 'classes/', parameterdir = 'parameters/', environmentdir = 'environment/') ⇒ ExternalNode

initialize takes three arguments:

hostname

usually passed in via ARGV but it could be anything

classdir

directory under WORKINGDIR to look for files named after

classes

parameterdir

directory under WORKINGDIR to look for directories to set

parameters


90
91
92
93
94
95
96
97
98
99
100
# File 'ext/regexp_nodes/regexp_nodes.rb', line 90

def initialize(hostname, classdir = 'classes/', parameterdir = 'parameters/', environmentdir = 'environment/')
  # instance variables that contain the lists of classes and parameters
  @classes = Set.new
  @parameters = Hash.new("unknown")  # sets a default value of "unknown"
  @environment = "production"

  self.parse_argv(hostname)
  self.match_classes("#{WORKINGDIR}/#{classdir}")
  self.match_parameters("#{WORKINGDIR}/#{parameterdir}")
  self.match_environment("#{WORKINGDIR}/#{environmentdir}")
end

Instance Attribute Details

#classesObject

Make these instance variables get/set-able with eponymous methods


82
83
84
# File 'ext/regexp_nodes/regexp_nodes.rb', line 82

def classes
  @classes
end

#environmentObject

Make these instance variables get/set-able with eponymous methods


82
83
84
# File 'ext/regexp_nodes/regexp_nodes.rb', line 82

def environment
  @environment
end

#hostnameObject

Make these instance variables get/set-able with eponymous methods


82
83
84
# File 'ext/regexp_nodes/regexp_nodes.rb', line 82

def hostname
  @hostname
end

#parametersObject

Make these instance variables get/set-able with eponymous methods


82
83
84
# File 'ext/regexp_nodes/regexp_nodes.rb', line 82

def parameters
  @parameters
end

Instance Method Details

#match_classes(fullpath) ⇒ Object

private method - takes a path to look for files, iterates through all readable, regular files it finds, and matches this instance's @hostname against each line; if any match, the class will be set for this node.


175
176
177
178
179
180
181
182
183
184
185
186
187
# File 'ext/regexp_nodes/regexp_nodes.rb', line 175

def match_classes(fullpath)
  Dir.foreach(fullpath) do |patternfile|
    filepath = "#{fullpath}/#{patternfile}"
    next unless File.file?(filepath) and
      File.readable?(filepath)
      next if patternfile =~ /^\./
    log("Attempting to match [#{@hostname}] in [#{filepath}]")
    if matched_in_patternfile?(filepath,@hostname)
      @classes << patternfile.to_s
      log("Appended #{patternfile} to classes instance variable")
    end
  end
end

#match_environment(fullpath) ⇒ Object

match_environment is similar to match_classes but it overwrites any previously set value (usually just the default, 'production') with a match


192
193
194
195
196
197
198
199
200
201
202
203
204
# File 'ext/regexp_nodes/regexp_nodes.rb', line 192

def match_environment(fullpath)
  Dir.foreach(fullpath) do |patternfile|
    filepath = "#{fullpath}/#{patternfile}"
    next unless File.file?(filepath) and
      File.readable?(filepath)
      next if patternfile =~ /^\./
    log("Attempting to match [#{@hostname}] in [#{filepath}]")
    if matched_in_patternfile?(filepath,@hostname)
      @environment = patternfile.to_s
      log("Wrote #{patternfile} to environment instance variable")
    end
  end
end

#match_parameters(fullpath) ⇒ Object

Parameters are handled slightly differently; we make another level of directories to get the parameter name, then use the names of the files contained in there for the values of those parameters.

ex: cat ./parameters/service/production ^prodweb would set parameters = “production” for prodweb001


214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
# File 'ext/regexp_nodes/regexp_nodes.rb', line 214

def match_parameters(fullpath)
  Dir.foreach(fullpath) do |parametername|

    filepath = "#{fullpath}/#{parametername}"
    next if File.basename(filepath) =~ /^\./   # skip over dotfiles

    next unless File.directory?(filepath) and
      File.readable?(filepath)        # skip over non-directories

    log("Considering contents of #{filepath}")

    Dir.foreach("#{filepath}") do |patternfile|
      secondlevel = "#{filepath}/#{patternfile}"
      log("Found parameters patternfile at #{secondlevel}")
      next unless File.file?(secondlevel) and
        File.readable?(secondlevel)
      log("Attempting to match [#{@hostname}] in [#{secondlevel}]")
      if matched_in_patternfile?(secondlevel, @hostname)
        @parameters[ parametername.to_s ] = patternfile.to_s
        log("Set @parameters[#{parametername}] = #{patternfile}")
      end
    end
  end
end

#matched_in_patternfile?(filepath, matchthis) ⇒ Boolean

Private method that expects an absolute path to a file and a string to match - it returns true if the string was matched by any of the lines in the file


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
168
169
170
# File 'ext/regexp_nodes/regexp_nodes.rb', line 131

def matched_in_patternfile?(filepath, matchthis)

  patternlist = []

  begin
    open(filepath).each do |l|
      l.chomp!

      next if l =~ /^$/
      next if l =~ /^#/

      if l =~ /^\s*(\S+)/
        m = Regexp.last_match
        log("found a non-comment line, transforming [#{l}] into [#{m[1]}]")
        l.gsub!(l,m[1])
      else
        next l
      end

      pattern = %r{#{l}}
      patternlist <<  pattern
      log("appending [#{pattern}] to patternlist for [#{filepath}]")
    end
  rescue StandardError
    log("Problem reading #{filepath}: #{$!}",:err)
    exit(1)
  end

  log("list of patterns for #{filepath}: #{patternlist}")

  if matchthis =~ Regexp.union(patternlist)
    log("matched #{$~} in #{matchthis}, returning true")
    return true

  else  # hostname didn't match anything in patternlist
    log("#{matchthis} unmatched, returning false")
    return nil
  end

end

#parse_argv(hostname) ⇒ Object

private method called by initialize which sanity-checks our hostname. good candidate for overriding in a subclass if you need different checks


104
105
106
107
108
109
110
111
112
113
114
# File 'ext/regexp_nodes/regexp_nodes.rb', line 104

def parse_argv(hostname)
  if hostname =~ /^([-\w]+?)\.([-\w\.]+)/  # non-greedy up to the first . is hostname
    @hostname = $1
  elsif hostname =~ /^([-\w]+)$/     # sometimes puppet's @name is just a name
    @hostname = hostname
    log("got shortname for [#{hostname}]")
  else
    log("didn't receive parsable hostname, got: [#{hostname}]",:err)
    exit(1)
  end
end

#to_yamlObject

to_yaml massages a copy of the object and outputs clean yaml so we don't feed weird things back to puppet []<


118
119
120
121
122
123
124
125
126
# File 'ext/regexp_nodes/regexp_nodes.rb', line 118

def to_yaml
  classes = self.classes.to_a
  if self.parameters.empty? # otherwise to_yaml prints "parameters: {}"
    parameters = nil
  else
    parameters = self.parameters
  end
  ({ 'classes' => classes, 'parameters' => parameters, 'environment' => environment}).to_yaml
end