Class: DevStructure::Puppet::Manifest

Inherits:
Object
  • Object
show all
Defined in:
lib/devstructure/puppet.rb

Overview

A Puppet manifest that contains a tree of classes that each contain some resources. Manifests are valid targets of dependencies and we use them heavily in the generated code to keep the inhumane-ness to a minimum. A Manifest object generates a Puppet ‘class`.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name, parent = nil, comment = nil) ⇒ Manifest

Each class must have a name and might have a parent. If a manifest has a parent, this signals it to ‘include` itself in the parent.



47
48
49
50
# File 'lib/devstructure/puppet.rb', line 47

def initialize(name, parent=nil, comment=nil)
  @name, @parent, @comment = name.gsub(".", "--"), parent, comment
  @manifests, @resources = {}, {}
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(symbol, *args) ⇒ Object



60
61
62
# File 'lib/devstructure/puppet.rb', line 60

def method_missing(symbol, *args)
  self[symbol]
end

Instance Attribute Details

#nameObject (readonly)

Returns the value of attribute name.



52
53
54
# File 'lib/devstructure/puppet.rb', line 52

def name
  @name
end

Instance Method Details

#<<(resource) ⇒ Object

Add a resource to this manifest. Order is never important in Puppet since all dependencies must be declared. Normal resources that have names are just added to the tree. Resources that are declaring defaults for an entire type have ‘nil` names so they behave more cumulatively.



69
70
71
72
73
74
75
76
77
78
# File 'lib/devstructure/puppet.rb', line 69

def <<(resource)
  @resources[resource.type] ||= {}
  if resource.name
    @resources[resource.type][resource.name] = resource
  elsif @resources[resource.type][resource.name]
    @resources[resource.type][resource.name].merge!(resource)
  else
    @resources[resource.type][resource.name] = resource
  end
end

#[](name) ⇒ Object

Manifests behave a bit like hashes in that their children can be traversed. Note the children can’t be assigned directly because we must maintain parent-child relationships.



57
58
59
# File 'lib/devstructure/puppet.rb', line 57

def [](name)
  @manifests[name.to_s] ||= self.class.new(name.to_s, @name)
end

#templatesObject

Return a hash of ‘pathname`s to `content`s for all the templates referenced in this manifest. `file` resources which define the `content` attribute must have a template containing the file itself.



83
84
85
86
87
88
89
90
# File 'lib/devstructure/puppet.rb', line 83

def templates
  out = {}
  (@resources["file"] || {}).select do |name, resource|
    next unless resource[:content] && resource.content
    out[name] = resource.content
  end
  out
end

#to_gz(io) ⇒ Object

Create a Puppet module containing a manifest and the files being distributed as templates.



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
171
# File 'lib/devstructure/puppet.rb', line 131

def to_gz(io)
  mtime = Time.now
  gz = Zlib::GzipWriter.new(io)
  tar = Archive::Tar::Minitar::Writer.new(gz)
  tar.mkdir @name, :mode => 0755, :mtime => mtime

  # Store the manifest in the tarball.
  manifest = to_s
  tar.mkdir "#{@name}/manifests", :mode => 0755, :mtime => mtime
  tar.add_file_simple("#{@name}/manifests/init.pp", {
    :mode => 0644,
    :size => manifest.length,
    :mtime => mtime
  }) { |w| w.write manifest }

  # Include as templates the content of any files in the module.
  templates = self.templates
  @manifests.each_value { |manifest| templates.merge! manifest.templates }
  if 0 < templates.length
    tar.mkdir "#{@name}/templates", :mode => 0755, :mtime => mtime
    templates.each do |pathname, content|
      dirnames = ::File.dirname(pathname).split("/")
      dirnames.shift
      (0..(dirnames.length - 1)).each do |i|
        tar.mkdir "#{@name}/templates/#{dirnames[0..i].join("/")}",
          :mode => 0755, :mtime => mtime
      end
      tar.add_file_simple("#{@name}/templates#{pathname}", {
        :mode => 0644,
        :size => content.length,
        :mtime => mtime
      }) { |w| w.write content }
    end
  end

  # Return the finalized tarball.
  tar.close
  gz.close
  io

end

#to_s(tab = "") ⇒ Object

Turn this manifest into a Puppet class. We start with a base level of indentation that we carry through our resources and manifests. Order is again not important so we don’t make much effort. The Puppet grammar prohibits dots in class names so we replace ‘.` with `–`.

Defaults for the entire type are handled first. Normal resources are grouped by type to reduce the total number of lines required. If this manifest has a parent, the last thing we do is include ourselves in the parent.



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
# File 'lib/devstructure/puppet.rb', line 102

def to_s(tab="")
  out = []
  out << @comment if @comment
  out << "#{tab}class #{@name} {"
  @manifests.each_value do |manifest|
    out << manifest.to_s("#{tab}\t")
  end
  @resources.sort.each do |type, resources|
    if resource = resources.delete(nil)
      out << resource.to_s("#{tab}\t")
    end
    if 1 < resources.length
      out << "#{tab}\t#{type} {"
      resources.sort.each do |name, resource|
        resource.style = :partial
        out << resource.to_s("#{tab}\t")
      end
      out << "#{tab}\t}"
    elsif 1 == resources.length
      out << resources.values.first.to_s("#{tab}\t")
    end
  end
  out << "#{tab}}"
  out << "#{tab}include #{@name}" if @parent
  out.join("\n")
end