Class: ShadowPuppet::Manifest

Inherits:
Object
  • Object
show all
Defined in:
lib/shadow_puppet/test.rb,
lib/shadow_puppet/manifest.rb

Overview

A Manifest is an executable collection of Puppet Resources.

Example

class ManifestExample < ShadowPuppet::Manifest
  recipe :sample
  recipe :lamp, :ruby               # queue calls to self.lamp and
                                    # self.ruby when executing

  recipe :mysql, {                  # queue a call to self.mysql
    :root_password => 'OMGSEKRET'   # passing the provided hash
  }                                 # as an option

  def sample
    exec :foo, :command => 'echo "foo" > /tmp/foo.txt'

    package :foo, :ensure => :installed

    file '/tmp/example.txt',
      :ensure   => :present,
      :contents => Facter.to_hash_inspect,
      :require  => package(:foo)
  end

  def lamp
    # install a basic LAMP stack
  end

  def ruby
    # install a ruby interpreter and tools
  end

  def mysql(options)
     # install a mysql server and set the root password to options[:root_password]
  end

end

To execute the above manifest, instantiate it and call execute on it:

m = ManifestExample.new
m.execute

As shown in the sample method in ManifestExample above, instance methods are created for each Puppet::Type available on your system. These methods behave identally to the Puppet Resources methods. See here for documentation on these methods.

To view a list of all defined methods on your system, run:

ruby -rubygems -e 'require "shadow_puppet";puts ShadowPuppet::Manifest.puppet_type_methods'

The use of methods (sample, lamp, ruby, and mysql above) as a container for resources facilitates recipie re-use through the use of Ruby Modules. For example:

module ApachePuppet
  # Required options:
  #   domain
  #   path
  def php_vhost(options)
    #...
  end
 end

class MyWebMainfest < ShadowPuppet::Manifest
  include ApachePuppet
  recipe :php_vhost, {
    :domain => 'foo.com',
    :path => '/var/www/apps/foo'
  }
end

Direct Known Subclasses

Setup

Defined Under Namespace

Classes: Setup

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(config = {}) ⇒ Manifest

Initialize a new instance of this manifest. This can take a config hash, which is immediately passed on to the configure method



85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/shadow_puppet/manifest.rb', line 85

def initialize(config = {})
  if Process.uid == 0
    Puppet[:confdir] = File.expand_path("/etc/shadow_puppet")
    Puppet[:vardir] = File.expand_path("/var/shadow_puppet")
    Puppet[:codedir] = File.expand_path("/etc/shadow_puppet/code")
    Puppet[:logdir] = File.expand_path("/var/log/shadow_puppet")
  else
    Puppet[:confdir] = File.expand_path("~/.shadow_puppet")
    Puppet[:vardir] = File.expand_path("~/.shadow_puppet/var")
    Puppet[:codedir] = File.expand_path("~/.shadow_puppet/code")
    Puppet[:logdir] = File.expand_path("~/shadow_puppet/log")
  end
  Puppet[:user] = Process.uid
  Puppet[:group] = Process.gid
  Puppet::Util::Log.newdestination(:console)
  Puppet[:diff_args] = "-u"
  Puppet.push_context(Puppet.base_context(Puppet.settings), "Update for application's settings")

  configure(config)
  @executed = false
  @catalog = Puppet::Resource::Catalog.new
  @catalog.host_config = false
  @catalog.name = self.name
end

Instance Attribute Details

#catalogObject (readonly)

Returns the value of attribute catalog.



78
79
80
# File 'lib/shadow_puppet/manifest.rb', line 78

def catalog
  @catalog
end

Class Method Details

.configurationObject

A HashWithIndifferentAccess describing any configuration that has been performed on the class. Modify this hash by calling configure:

class SampleManifest < ShadowPuppet::Manifest
  configure(:name => 'test')
end

>> SampleManifest.configuration
=> {:name => 'test'}
 #

Subclasses of the Manifest class properly inherit the parent classes’ configuration.



151
152
153
# File 'lib/shadow_puppet/manifest.rb', line 151

def self.configuration
  __config__.with_indifferent_access
end

.configure(hash) ⇒ Object

Define configuration on this manifest. This is useful for storing things such as hostnames, password, or usernames that may change between different implementations of a shared manifest. Access this hash by calling configuration:

class SampleManifest < ShadowPuppet::Manifest
  configure('name' => 'test')
end

>> SampleManifest.configuration
=> {:name => 'test'}
 #

Subsequent calls to configure perform a deep_merge of the provided hash into the pre-existing configuration.



181
182
183
# File 'lib/shadow_puppet/manifest.rb', line 181

def self.configure(hash)
  __config__.replace(__config__.deep_symbolize_keys.deep_merge(hash.deep_symbolize_keys))
end

.puppet_type_methodsObject

An array of all methods defined for creation of Puppet Resources



200
201
202
# File 'lib/shadow_puppet/manifest.rb', line 200

def self.puppet_type_methods
  Puppet::Type.eachtype { |t| t.name }.keys.map { |n| n.to_s }.sort.inspect
end

.recipe(*methods) ⇒ Object

Declares that the named method or methods will be called whenever execute is called on an instance of this class. If the last argument is a Hash, this hash is passed as an argument to all provided methods. If no options hash is provided, each method is passed the contents of configuration[method].

Subclasses of the Manifest class properly inherit the parent classes’ calls to recipe.



118
119
120
121
122
123
124
125
126
# File 'lib/shadow_puppet/manifest.rb', line 118

def self.recipe(*methods)
  return nil if methods.nil? || methods == [] # TODO can probably replace with if methods.blank?
  methods.each do |meth|
    options = methods.extract_options!
    options = configuration[meth.to_sym] if options == {} # TODO can probably be replaced with options.blank?
    options ||= {}
    recipes << [meth.to_sym, options]
  end
end

.register_puppet_typesObject

Create an instance method for every type that either creates or references a resource



210
211
212
213
214
215
216
217
218
219
# File 'lib/shadow_puppet/manifest.rb', line 210

def self.register_puppet_types
  Puppet::Type.loadall
  Puppet::Type.eachtype do |type|
    # remove the method rdoc placeholders
    remove_method(type.name) rescue nil
    define_method(type.name) do |*args|
      resource_or_reference(type, *args)
    end
  end
end

.register_puppet_types_for_testingObject

Creates an instance method for every puppet type that either creates or references a resource



52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/shadow_puppet/test.rb', line 52

def self.register_puppet_types_for_testing
  Puppet::Type.loadall
  Puppet::Type.eachtype do |type|
    plural_type = type.name.to_s.downcase.pluralize
    #undefine the method rdoc placeholders
    undef_method(plural_type) rescue nil
    define_method(plural_type) do |*args|
      catalog.resources.select { |r| r.type == type.name }.inject({}) do |hash, resource|
        hash[resource.title] = resource; hash
      end
    end
  end
end

Instance Method Details

#configurationObject

Access to the configuration of the class of this instance.

class SampleManifest < ShadowPuppet::Manifest
  configure(:name => 'test')
end

@manifest = SampleManifest.new
@manifest.configuration[:name] => "test"


163
164
165
# File 'lib/shadow_puppet/manifest.rb', line 163

def configuration
  self.class.configuration
end

#configure(hash) ⇒ Object Also known as: configuration=

Update the configuration of this manifest instance’s class.

class SampleManifest < ShadowPuppet::Manifest
  configure({})
end

@manifest = SampleManifest.new
@manifest.configure(:name => "test")
@manifest.configuration[:name] => "test"


194
195
196
# File 'lib/shadow_puppet/manifest.rb', line 194

def configure(hash)
  self.class.configure(hash)
end

#executable?Boolean

Returns true if this Manifest respond_to? all methods named by calls to recipe, and if this Manifest has not been executed before.

Returns:

  • (Boolean)


224
225
226
227
228
229
230
# File 'lib/shadow_puppet/manifest.rb', line 224

def executable?
  self.class.recipes.each do |meth,args|
    return false unless respond_to?(meth)
  end
  return false if executed?
  true
end

#execute(force = false) ⇒ Object

Execute this manifest, applying all resources defined. Execute returns true if successfull, and false if unsucessfull. By default, this will only execute a manifest that has not already been executed?. The force argument, if true, removes this check.



242
243
244
245
246
247
248
249
250
251
252
# File 'lib/shadow_puppet/manifest.rb', line 242

def execute(force=false)
  return false if executed? && !force
  evaluate_recipes
  transaction = apply
rescue Exception => e
  false
else
  not transaction.any_failed?
ensure
  @executed = true
end

#execute!(force = false) ⇒ Object

Execute this manifest, applying all resources defined. Execute returns true if successfull, and raises an exception if not. By default, this will only execute a manifest that has not already been executed?. The force argument, if true, removes this check.



258
259
260
261
262
263
264
265
266
267
268
# File 'lib/shadow_puppet/manifest.rb', line 258

def execute!(force=false)
  return false if executed? && !force
  evaluate_recipes
  transaction = apply
rescue Exception => e
  raise e
else
  not transaction.any_failed?
ensure
  @executed = true
end

#graph_to(name, destination) ⇒ Object



270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
# File 'lib/shadow_puppet/manifest.rb', line 270

def graph_to(name, destination)
  evaluate_recipes

  relationship_graph = @catalog.relationship_graph

  graph = relationship_graph.to_dot_graph("name" => "#{name} Relationships".gsub(/\W+/, '_'))
  graph.options['label'] = "#{name} Relationships"

  # The graph ends up having all of the edges backwards
  graph.each_node do |node|
    next unless node.is_a?(DOT::DOTEdge)
    node.to, node.from = node.from, node.to
  end

  File.open(destination, "w") { |f|
      f.puts graph.to_s
  }
end

#missing_recipesObject



232
233
234
235
236
# File 'lib/shadow_puppet/manifest.rb', line 232

def missing_recipes
  missing = self.class.recipes.each do |meth,args|
    !respond_to?(meth)
  end
end

#nameObject



204
205
206
# File 'lib/shadow_puppet/manifest.rb', line 204

def name
  @name ||= "#{self.class}##{self.object_id}"
end

#recipe(*methods) ⇒ Object

Access to a recipe of the class of this instance.

class SampleManifest < ShadowPuppet::Manifest
  def my_recipe
    recipe :other_recipe
  end
end


135
136
137
# File 'lib/shadow_puppet/manifest.rb', line 135

def recipe(*methods)
  self.class.recipe *methods
end