So if I understand this correctly, we can now force an apt-get update
before all the other apt-commands without explicit requires?

Awesome.

--Michael

On Fri, May 14, 2010 at 5:03 PM, Luke Kanies <[email protected]> wrote:
> This allows you to specify a run stage for either
> a class or a resource.
>
> By default, all classes get directly added to the
> 'main' stage.  You can create new stages as resources:
>
>    stage { [pre, post]: }
>
> To order stages, use standard relationships:
>
>    stage { pre: before => Stage[main] }
>
> Or use the new relationship syntax:
>
>    stage { pre: } -> Stage[main] -> stage { post: }
>
> Then use the new class parameters to specify a stage:
>
>    class { foo: stage => pre }
>
> If you set a stage on an individual resource, it will
> break its normal containment relationship.  For instance:
>
>    class foo {
>        file { '/foo': stage => pre }
>    }
>    service { bar: require => Class[foo] }
>
> This likely will not behave as you expect, because 'File[/foo]' is no
> longer in the class foo but has been moved directly into the 'pre' stage,
> thus losing its containment relationship with Class[foo].
>
> Signed-off-by: Luke Kanies <[email protected]>
> ---
>  lib/puppet/parser/compiler.rb                |   26 ++++----
>  lib/puppet/parser/resource.rb                |    4 +-
>  lib/puppet/simple_graph.rb                   |    3 +-
>  lib/puppet/type.rb                           |    9 +++
>  lib/puppet/type/stage.rb                     |    7 ++
>  spec/integration/parser/functions/include.rb |   25 --------
>  spec/unit/parser/compiler.rb                 |   86 
> ++++++++++++++++++++------
>  spec/unit/simple_graph.rb                    |    8 +++
>  spec/unit/type.rb                            |    7 ++-
>  spec/unit/type/stage.rb                      |    9 +++
>  10 files changed, 123 insertions(+), 61 deletions(-)
>  create mode 100644 lib/puppet/type/stage.rb
>  delete mode 100755 spec/integration/parser/functions/include.rb
>  create mode 100644 spec/unit/type/stage.rb
>
> diff --git a/lib/puppet/parser/compiler.rb b/lib/puppet/parser/compiler.rb
> index 8e84f5a..9f1acad 100644
> --- a/lib/puppet/parser/compiler.rb
> +++ b/lib/puppet/parser/compiler.rb
> @@ -47,11 +47,14 @@ class Puppet::Parser::Compiler
>         # Note that this will fail if the resource is not unique.
>         @catalog.add_resource(resource)
>
> -        # And in the resource graph.  At some point, this might supercede
> -        # the global resource table, but the table is a lot faster
> -        # so it makes sense to maintain for now.
> -        if resource.type.to_s.downcase == "class" and main = 
> @catalog.resource(:class, :main)
> -           �[email protected]_edge(main, resource)
> +        # Add our container edge.  If we're a class, then we get treated 
> specially - we can
> +        # control the stage that the class is applied in.  Otherwise, we just
> +        # get added to our parent container.
> +        return if resource.type.to_s.downcase == "stage"
> +        #if resource.type.to_s.downcase == "class" and stage = 
> @catalog.resource(:stage, resource[:stage] || :main)
> +        if resource.type.to_s.downcase == "class" or resource[:stage]
> +            stage = @catalog.resource(:stage, resource[:stage] || :main)
> +           �[email protected]_edge(stage, resource)
>         else
>             @catalog.add_edge(scope.resource, resource)
>         end
> @@ -161,7 +164,6 @@ class Puppet::Parser::Compiler
>         end
>
>         initvars()
> -        init_main()
>     end
>
>     # Create a new scope, with either a specified parent scope or
> @@ -353,12 +355,6 @@ class Puppet::Parser::Compiler
>         end
>     end
>
> -    # Initialize the top-level scope, class, and resource.
> -    def init_main
> -        # Create our initial scope and a resource that will evaluate main.
> -       �...@topscope = Puppet::Parser::Scope.new(:compiler => self)
> -    end
> -
>     # Set up all of our internal variables.
>     def initvars
>         # The list of objects that will available for export.
> @@ -378,6 +374,12 @@ class Puppet::Parser::Compiler
>         @catalog = Puppet::Resource::Catalog.new(@node.name)
>         @catalog.version = known_resource_types.version
>
> +        # Create our initial scope and a resource that will evaluate main.
> +       �...@topscope = Puppet::Parser::Scope.new(:compiler => self)
> +
> +       �...@main_stage_resource = Puppet::Parser::Resource.new("stage", 
> :main, :scope => @topscope)
> +       �[email protected]_resource(@main_stage_resource)
> +
>         # local resource array to maintain resource ordering
>         @resources = []
>
> diff --git a/lib/puppet/parser/resource.rb b/lib/puppet/parser/resource.rb
> index 7fcb7c1..7b9d0df 100644
> --- a/lib/puppet/parser/resource.rb
> +++ b/lib/puppet/parser/resource.rb
> @@ -22,9 +22,9 @@ class Puppet::Parser::Resource < Puppet::Resource
>     include Puppet::Parser::YamlTrimmer
>
>     attr_accessor :source, :scope, :rails_id
> -    attr_accessor :virtual, :override, :translated, :catalog
> +    attr_accessor :virtual, :override, :translated, :catalog, :evaluated
>
> -    attr_reader :exported, :evaluated, :parameters
> +    attr_reader :exported, :parameters
>
>     # Determine whether the provided parameter name is a relationship 
> parameter.
>     def self.relationship_parameter?(name)
> diff --git a/lib/puppet/simple_graph.rb b/lib/puppet/simple_graph.rb
> index 9160394..cf0eff3 100644
> --- a/lib/puppet/simple_graph.rb
> +++ b/lib/puppet/simple_graph.rb
> @@ -323,7 +323,8 @@ class Puppet::SimpleGraph
>         # graph.  We could get a similar affect by only setting relationships
>         # to container leaves, but that would result in many more
>         # relationships.
> -        containers = other.topsort.find_all { |v| v.is_a?(type) and 
> vertex?(v) }
> +        stage_class = Puppet::Type.type(:stage)
> +        containers = other.topsort.find_all { |v| (v.is_a?(type) or 
> v.is_a?(stage_class)) and vertex?(v) }
>         containers.each do |container|
>             # Get the list of children from the other graph.
>             children = other.adjacent(container, :direction => :out)
> diff --git a/lib/puppet/type.rb b/lib/puppet/type.rb
> index 33d2d03..d4aabad 100644
> --- a/lib/puppet/type.rb
> +++ b/lib/puppet/type.rb
> @@ -1402,6 +1402,15 @@ class Type
>             This will restart the sshd service if the sshd config file 
> changes.}
>     end
>
> +    newmetaparam(:stage) do
> +        desc %{Which run stage a given resource should reside in.  This just 
> creates
> +            a dependency on or from the named milestone.  For instance, 
> saying that
> +            this is in the 'bootstrap' stage creates a dependency on the 
> 'bootstrap'
> +            milestone.}
> +
> +        defaultto :main
> +    end
> +
>     ###############################
>     # All of the provider plumbing for the resource types.
>     require 'puppet/provider'
> diff --git a/lib/puppet/type/stage.rb b/lib/puppet/type/stage.rb
> new file mode 100644
> index 0000000..5f19b61
> --- /dev/null
> +++ b/lib/puppet/type/stage.rb
> @@ -0,0 +1,7 @@
> +Puppet::Type.newtype(:stage) do
> +    desc "A resource type for specifying run stages."
> +
> +    newparam :name do
> +        desc "The name of the stage. This will be used as the 'stage' for 
> each resource."
> +    end
> +end
> diff --git a/spec/integration/parser/functions/include.rb 
> b/spec/integration/parser/functions/include.rb
> deleted file mode 100755
> index f84d432..0000000
> --- a/spec/integration/parser/functions/include.rb
> +++ /dev/null
> @@ -1,25 +0,0 @@
> -#!/usr/bin/env ruby
> -
> -require File.dirname(__FILE__) + '/../../../spec_helper'
> -
> -describe "The include function" do
> -    before :each do
> -       �...@node = Puppet::Node.new("mynode")
> -       �...@compiler = Puppet::Parser::Compiler.new(@node)
> -       �[email protected](:evaluate_main)
> -       �...@scope = @compiler.topscope
> -        # preload our functions
> -        Puppet::Parser::Functions.function(:include)
> -        Puppet::Parser::Functions.function(:require)
> -    end
> -
> -    it "should add a containment relationship between the 'included' class 
> and our class" do
> -       �[email protected]_resource_types.add 
> Puppet::Resource::Type.new(:hostclass, "includedclass")
> -
> -       �[email protected]_include("includedclass")
> -
> -        klass_resource = @compiler.findresource(:class,"includedclass")
> -        klass_resource.should be_instance_of(Puppet::Parser::Resource)
> -       �[email protected] be_edge(@scope.resource, klass_resource)
> -    end
> -end
> diff --git a/spec/unit/parser/compiler.rb b/spec/unit/parser/compiler.rb
> index 6fd4d1f..7dd72e8 100755
> --- a/spec/unit/parser/compiler.rb
> +++ b/spec/unit/parser/compiler.rb
> @@ -10,6 +10,10 @@ class CompilerTestResource
>         @title = title
>     end
>
> +    def [](attr)
> +        :main
> +    end
> +
>     def ref
>         "%s[%s]" % [type.to_s.capitalize, title]
>     end
> @@ -31,13 +35,17 @@ class CompilerTestResource
>  end
>
>  describe Puppet::Parser::Compiler do
> +    def resource(type, title)
> +        Puppet::Parser::Resource.new(type, title, :scope => @scope)
> +    end
> +
>     before :each do
>         @node = Puppet::Node.new "testnode"
>         @known_resource_types = Puppet::Resource::TypeCollection.new 
> "development"
>
>         @scope_resource = stub 'scope_resource', :builtin? => true, :finish 
> => nil, :ref => 'Class[main]', :type => "class"
> -       �...@scope = stub 'scope', :resource => @scope_resource, :source => 
> mock("source")
>         @compiler = Puppet::Parser::Compiler.new(@node)
> +       �...@scope = Puppet::Parser::Scope.new(:compiler => @compiler, 
> :source => stub('source'))
>         @compiler.environment.stubs(:known_resource_types).returns 
> @known_resource_types
>     end
>
> @@ -99,6 +107,10 @@ describe Puppet::Parser::Compiler do
>             compiler.classlist.should include("foo")
>             compiler.classlist.should include("bar")
>         end
> +
> +        it "should add a 'main' stage to the catalog" do
> +           �[email protected](:stage, :main).should 
> be_instance_of(Puppet::Parser::Resource)
> +        end
>     end
>
>     describe "when managing scopes" do
> @@ -208,7 +220,7 @@ describe Puppet::Parser::Compiler do
>         end
>
>         it "should ignore builtin resources" do
> -            resource = stub 'builtin', :ref => "File[testing]", :builtin? => 
> true, :type => "file"
> +            resource = resource(:file, "testing")
>
>             @compiler.add_resource(@scope, resource)
>             resource.expects(:evaluate).never
> @@ -228,7 +240,9 @@ describe Puppet::Parser::Compiler do
>         end
>
>         it "should not evaluate already-evaluated resources" do
> -            resource = stub 'already_evaluated', :ref => "File[testing]", 
> :builtin? => false, :evaluated? => true, :virtual? => false, :type => "file"
> +            resource = resource(:file, "testing")
> +            resource.stubs(:evaluated?).returns true
> +
>             @compiler.add_resource(@scope, resource)
>             resource.expects(:evaluate).never
>
> @@ -257,7 +271,7 @@ describe Puppet::Parser::Compiler do
>             @compiler.add_resource(@scope, resource)
>
>             # And one that does not
> -            dnf = stub "dnf", :ref => "File[dnf]", :type => "file"
> +            dnf = stub "dnf", :ref => "File[dnf]", :type => "file", :[] => 
> nil
>
>             @compiler.add_resource(@scope, dnf)
>
> @@ -281,16 +295,16 @@ describe Puppet::Parser::Compiler do
>         end
>
>         it "should return added resources in add order" do
> -            resource1 = stub "1", :ref => "File[yay]", :type => "file"
> +            resource1 = resource(:file, "yay")
>             @compiler.add_resource(@scope, resource1)
> -            resource2 = stub "2", :ref => "File[youpi]", :type => "file"
> +            resource2 = resource(:file, "youpi")
>             @compiler.add_resource(@scope, resource2)
>
>             @compiler.resources.should == [resource1, resource2]
>         end
>
>         it "should add resources that do not conflict with existing 
> resources" do
> -            resource = CompilerTestResource.new(:file, "yay")
> +            resource = resource(:file, "yay")
>             @compiler.add_resource(@scope, resource)
>
>             @compiler.catalog.should be_vertex(resource)
> @@ -305,42 +319,74 @@ describe Puppet::Parser::Compiler do
>         end
>
>         it "should add an edge from the scope resource to the added resource" 
> do
> -            resource = stub "noconflict", :ref => "File[yay]", :type => 
> "file"
> +            resource = resource(:file, "yay")
>             @compiler.add_resource(@scope, resource)
>
>             @compiler.catalog.should be_edge(@scope.resource, resource)
>         end
>
> -        it "should add edges from the class resources to the main class" do
> -            main = CompilerTestResource.new(:class, :main)
> -           �[email protected]_resource(@scope, main)
> -            resource = CompilerTestResource.new(:class, "foo")
> +        it "should add an edge to any specified stage for resources" do
> +            other_stage = resource(:stage, "other")
> +           �[email protected]_resource(@scope, other_stage)
> +            resource = resource(:file, "foo")
> +            resource[:stage] = 'other'
> +
> +           �[email protected]_resource(@scope, resource)
> +
> +           �[email protected]?(other_stage, resource).should be_true
> +        end
> +
> +        it "should add edges from the class resources to the main stage if 
> no stage is specified" do
> +            main = @compiler.catalog.resource(:stage, :main)
> +            resource = resource(:class, "foo")
>             @compiler.add_resource(@scope, resource)
>
>             @compiler.catalog.should be_edge(main, resource)
>         end
>
> -        it "should just add edges to the scope resource for the class 
> resources when no main class can be found" do
> -            resource = CompilerTestResource.new(:class, "foo")
> +        it "should not add non-class resources that don't specify a stage to 
> the 'main' stage" do
> +            main = @compiler.catalog.resource(:stage, :main)
> +            resource = resource(:file, "foo")
>             @compiler.add_resource(@scope, resource)
>
> -           �[email protected] be_edge(@scope.resource, resource)
> +           �[email protected]_not be_edge(main, resource)
> +        end
> +
> +        it "should not add any parent-edges to stages" do
> +            stage = resource(:stage, "other")
> +           �[email protected]_resource(@scope, stage)
> +
> +           �[email protected] = resource(:class, "foo")
> +
> +           �[email protected]?(@scope.resource, stage).should 
> be_false
> +        end
> +
> +        it "should not attempt to add stages to other stages" do
> +            other_stage = resource(:stage, "other")
> +            second_stage = resource(:stage, "second")
> +           �[email protected]_resource(@scope, other_stage)
> +           �[email protected]_resource(@scope, second_stage)
> +
> +            second_stage[:stage] = "other"
> +
> +           �[email protected]?(other_stage, second_stage).should 
> be_false
>         end
>
>         it "should have a method for looking up resources" do
> -            resource = stub 'resource', :ref => "Yay[foo]", :type => "file"
> +            resource = resource(:yay, "foo")
>             @compiler.add_resource(@scope, resource)
>             @compiler.findresource("Yay[foo]").should equal(resource)
>         end
>
>         it "should be able to look resources up by type and title" do
> -            resource = stub 'resource', :ref => "Yay[foo]", :type => "file"
> +            resource = resource(:yay, "foo")
>             @compiler.add_resource(@scope, resource)
>             @compiler.findresource("Yay", "foo").should equal(resource)
>         end
>
>         it "should not evaluate virtual defined resources" do
> -            resource = stub 'notevaluated', :ref => "File[testing]", 
> :builtin? => false, :evaluated? => false, :virtual? => true, :type => "file"
> +            resource = resource(:file, "testing")
> +            resource.virtual = true
>             @compiler.add_resource(@scope, resource)
>
>             resource.expects(:evaluate).never
> @@ -565,8 +611,8 @@ describe Puppet::Parser::Compiler do
>     describe "when managing resource overrides" do
>
>         before do
> -           �...@override = stub 'override', :ref => "My[ref]", :type => "my"
> -           �...@resource = stub 'resource', :ref => "My[ref]", :builtin? => 
> true, :type => "my"
> +           �...@override = stub 'override', :ref => "File[/foo]", :type => 
> "my"
> +           �...@resource = resource(:file, "/foo")
>         end
>
>         it "should be able to store overrides" do
> diff --git a/spec/unit/simple_graph.rb b/spec/unit/simple_graph.rb
> index f8596c7..234a2fc 100755
> --- a/spec/unit/simple_graph.rb
> +++ b/spec/unit/simple_graph.rb
> @@ -440,6 +440,8 @@ describe Puppet::SimpleGraph do
>             @top = Container.new("top", ["g", "h", @middle, @one, @three])
>             @empty = Container.new("empty", [])
>
> +           �...@stage = Puppet::Type.type(:stage).new(:name => "foo")
> +
>             @contgraph = @top.to_graph
>
>             # We have to add the container to the main graph, else it won't
> @@ -477,6 +479,12 @@ describe Puppet::SimpleGraph do
>             @depgraph.vertices.find_all { |v| v.is_a?(Container) }.should 
> be_empty
>         end
>
> +        # This is a bit hideous, but required to make stages work with 
> relationships - they're
> +        # the top of the graph.
> +        it "should remove all Stage resources from the dependency graph" do
> +           �[email protected]_all { |v| 
> v.is_a?(Puppet::Type.type(:stage)) }.should be_empty
> +        end
> +
>         it "should add container relationships to contained objects" do
>             @contgraph.leaves(@middle).each do |leaf|
>                 @depgraph.should be_edge("h", leaf)
> diff --git a/spec/unit/type.rb b/spec/unit/type.rb
> index 9381c0a..42d6ae9 100755
> --- a/spec/unit/type.rb
> +++ b/spec/unit/type.rb
> @@ -445,7 +445,12 @@ describe Puppet::Type do
>         end
>     end
>
> -    describe "when managing relationships" do
> +    it "should have a 'stage' metaparam" do
> +        Puppet::Type.metaparamclass(:stage).should be_instance_of(Class)
> +    end
> +
> +    it "should default to 'main' for 'stage'" do
> +        Puppet::Type.metaparamclass(:stage).new(:resource => 
> stub('resource')).default.should == :main
>     end
>  end
>
> diff --git a/spec/unit/type/stage.rb b/spec/unit/type/stage.rb
> new file mode 100644
> index 0000000..6884652
> --- /dev/null
> +++ b/spec/unit/type/stage.rb
> @@ -0,0 +1,9 @@
> +#!/usr/bin/env ruby
> +
> +require File.dirname(__FILE__) + '/../../spec_helper'
> +
> +describe Puppet::Type.type(:stage) do
> +    it "should have a 'name' parameter'" do
> +        Puppet::Type.type(:stage).new(:name => :foo)[:name].should == :foo
> +    end
> +end
> --
> 1.6.1
>
> --
> You received this message because you are subscribed to the Google Groups 
> "Puppet Developers" group.
> To post to this group, send email to [email protected].
> To unsubscribe from this group, send email to 
> [email protected].
> For more options, visit this group at 
> http://groups.google.com/group/puppet-dev?hl=en.
>
>

-- 
You received this message because you are subscribed to the Google Groups 
"Puppet Developers" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/puppet-dev?hl=en.

Reply via email to