diff options
author | Luke Kanies <luke@madstop.com> | 2005-05-16 17:09:08 +0000 |
---|---|---|
committer | Luke Kanies <luke@madstop.com> | 2005-05-16 17:09:08 +0000 |
commit | f9a223cdbebb43b4df527cae0c34a0ce938c02d6 (patch) | |
tree | 542b451b6511b1776c3b5e0d8766554e4ad1cde9 | |
parent | 00a620de88c593ffe841121c3a2e19504380b669 (diff) | |
download | puppet-f9a223cdbebb43b4df527cae0c34a0ce938c02d6.tar.gz puppet-f9a223cdbebb43b4df527cae0c34a0ce938c02d6.tar.xz puppet-f9a223cdbebb43b4df527cae0c34a0ce938c02d6.zip |
transformations from the client through to the transactional execution now works!
git-svn-id: https://reductivelabs.com/svn/puppet/library/trunk@251 980ebf18-57e1-0310-9a29-db15c13687c0
-rw-r--r-- | lib/blink/client.rb | 53 | ||||
-rw-r--r-- | lib/blink/transaction.rb | 50 | ||||
-rw-r--r-- | lib/blink/transportable.rb | 163 | ||||
-rw-r--r-- | lib/blink/type.rb | 37 | ||||
-rw-r--r-- | lib/blink/type/component.rb | 5 | ||||
-rw-r--r-- | lib/blink/type/state.rb | 10 | ||||
-rw-r--r-- | lib/blink/type/typegen/filerecord.rb | 1 | ||||
-rw-r--r-- | lib/blink/type/typegen/filetype.rb | 3 | ||||
-rw-r--r-- | test/types/tc_basic.rb | 35 |
9 files changed, 232 insertions, 125 deletions
diff --git a/lib/blink/client.rb b/lib/blink/client.rb index 014e2a33f..0c4c59bcf 100644 --- a/lib/blink/client.rb +++ b/lib/blink/client.rb @@ -8,6 +8,7 @@ require 'blink' require 'blink/function' require 'blink/type' require 'blink/transaction' +require 'blink/transportable' module Blink class ClientError < RuntimeError; end @@ -27,45 +28,19 @@ module Blink end end - def objects=(list) - objects = [] - list.collect { |object| - # create a Blink object from the list... - #puts "yayness" - if type = Blink::Type.type(object.type) - namevar = type.namevar - if namevar != :name - object[namevar] = object[:name] - object.delete(:name) - end - begin - # this will fail if the type already exists - # which may or may not be a good thing... - typeobj = type.new(object) - objects.push typeobj - rescue => detail - puts "Failed to create object: %s" % detail - #puts object.class - #puts object.inspect - exit - end - else - raise "Could not find object type %s" % object.type - end - } - - # okay, we have a list of all of the objects we're supposed - # to execute - # here's where we collect the rollbacks and record them - # that means that we need, at the least: - # - a standard mechanism for specifying that an object is no-op - # - a standard object that is considered a rollback object - #objects.each { |obj| - # obj.evaluate - #} - - transaction = Blink::Transaction.new(objects) - transaction.run + # this method is how the client receives the tree of Transportable + # objects + # for now, just descend into the tree and perform and necessary + # manipulations + def objects=(tree) + container = tree.to_type + + # for now we just evaluate the top-level container, but eventually + # there will be schedules and such associated with each object, + # and probably with the container itself + transaction = container.evaluate + #transaction = Blink::Transaction.new(objects) + transaction.evaluate end end end diff --git a/lib/blink/transaction.rb b/lib/blink/transaction.rb index 7c0a86407..9535cd712 100644 --- a/lib/blink/transaction.rb +++ b/lib/blink/transaction.rb @@ -14,46 +14,50 @@ require 'blink/statechange' #--------------------------------------------------------------- class Blink::Transaction - attr_accessor :collect # do we collect the changes and perform them - # all at once? - #--------------------------------------------------------------- # for now, just store the changes for executing linearly # later, we might execute them as we receive them def change(change) - @changes.push change + @children.push change end #--------------------------------------------------------------- #--------------------------------------------------------------- def evaluate - Blink.notice "evaluating %s changes" % @changes.length - @changes.each { |change| - msg = change.forward + Blink.notice "executing %s changes" % @children.length + + @children.each { |change| + if change.is_a?(Blink::StateChange) + begin + change.forward + rescue => detail + Blink.error("%s failed: %s" % [change,detail]) + # at this point, we would normally roll back the transaction + # but, um, i don't know how to do that yet + end + elsif change.is_a?(Blink::Transaction) + change.evaluate + else + raise "Transactions cannot handle objects of type %s" % child.class + end } end #--------------------------------------------------------------- #--------------------------------------------------------------- + # this should only be called by a Blink::Container object now + # and it should only receive an array def initialize(tree) @tree = tree - @collect = true - @changes = [] - end - #--------------------------------------------------------------- - #--------------------------------------------------------------- - def run - Blink.notice "running transaction" - if @tree.is_a?(Array) - @tree.each { |item| - item.evaluate(self) - } - else - @tree.evaluate(self) - end - Blink.notice "finished transaction" - self.evaluate + # change collection is in-band, and message generation is out-of-band + # of course, exception raising is also out-of-band + @children = @tree.collect { |child| + # not all of the children will return a change + child.evaluate + }.flatten.reject { |child| + child.nil? # remove empties + } end #--------------------------------------------------------------- end diff --git a/lib/blink/transportable.rb b/lib/blink/transportable.rb index 101d8d29f..8a9cdf397 100644 --- a/lib/blink/transportable.rb +++ b/lib/blink/transportable.rb @@ -8,58 +8,145 @@ # information and out of which we'll receive our host-specific configuration require 'blink' -require 'blink/parser/parser' module Blink - module Parser - #------------------------------------------------------------ - class TransObject < Hash - attr_accessor :type + #------------------------------------------------------------ + class TransObject < Hash + attr_accessor :type - @@ohash = {} - @@oarray = [] + @@ohash = {} + @@oarray = [] - def TransObject.clear - @@oarray.clear - end + def TransObject.clear + @@oarray.clear + end - def TransObject.list - return @@oarray - end + def TransObject.list + return @@oarray + end - def initialize(name,type) - self[:name] = name - @type = type - #if @@ohash.include?(name) - # raise "%s already exists" % name - #else - # @@ohash[name] = self - # @@oarray.push(self) - #end - @@oarray.push self - end + def initialize(name,type) + self[:name] = name + @type = type + #if @@ohash.include?(name) + # raise "%s already exists" % name + #else + # @@ohash[name] = self + # @@oarray.push(self) + #end + @@oarray.push self + end - def name - return self[:name] - end + def name + return self[:name] + end + + def to_s + return "%s(%s) => %s" % [@type,self[:name],super] + end - def to_s - return "%s(%s) => %s" % [@type,self[:name],super] + def to_type + retobj = nil + if type = Blink::Type.type(self.type) + namevar = type.namevar + if namevar != :name + object[namevar] = object[:name] + object.delete(:name) + end + begin + # this will fail if the type already exists + # which may or may not be a good thing... + retobj = type.new(object) + rescue => detail + Blink.error "Failed to create object: %s" % detail + #puts object.class + #puts object.inspect + #exit + end + else + raise "Could not find object type %s" % object.type end + + return retobj end - #------------------------------------------------------------ + end + #------------------------------------------------------------ - #------------------------------------------------------------ - class TransSetting - attr_accessor :type, :name, :args + #------------------------------------------------------------ + class TransSetting + attr_accessor :type, :name, :args, :evalcount + + def initialize + @evalcount = 0 end - #------------------------------------------------------------ - #------------------------------------------------------------ - # just a linear container for objects - class TransBucket < Array + def evaluate(transaction) + @evalcount += 0 + if type = Blink::Type.type(self.type) + # call the settings + type.send(self.name,self.args) + else + raise "Could not find object type %s" % setting.type + end end - #------------------------------------------------------------ end + #------------------------------------------------------------ + + #------------------------------------------------------------ + # just a linear container for objects + class TransBucket < Array + def to_type + # this container will contain the equivalent of all objects at + # this level + container = Blink::Container.new + nametable = {} + + self.each { |child| + # the fact that we descend here means that we are + # always going to execute depth-first + # which is _probably_ a good thing, but one never knows... + if child.is_a?(Blink::TransBucket) + # just perform the same operation on any children + container.push(child.to_type) + elsif child.is_a?(Blink::Setting) + # XXX this is wrong, but for now just evaluate the settings + child.evaluate + elsif child.is_a?(Blink::TransObject) + # do a simple little naming hack to see if the object already + # exists in our scope + # this assumes that type/name combinations are globally + # unique + name = [child[:name],child[:type]].join("--") + + if namecheck.include?(name) + object = namecheck[name] + child.each { |var,value| + # don't rename; this shouldn't be possible anyway + next if var == :name + + # override any existing values + object[var] = value + } + else # the object does not exist yet in our scope + # now we have the object instantiated, in our scope + object = child.to_type + namecheck[name] = object + + # this sets the order of the object + container.push object + end + else + raise "Client#mkobjects cannot handle objects of type %s" % + child.class + end + } + + # at this point, no objects at are level are still Transportable + # objects + return container + end + + end + #------------------------------------------------------------ end diff --git a/lib/blink/type.rb b/lib/blink/type.rb index 7caa6bd0a..1ea652182 100644 --- a/lib/blink/type.rb +++ b/lib/blink/type.rb @@ -126,6 +126,16 @@ class Blink::Type < Blink::Element #--------------------------------------------------------------- #--------------------------------------------------------------- + def Type.metaclass + if defined? @metaclass + return @metaclass + else + return false + end + end + #--------------------------------------------------------------- + + #--------------------------------------------------------------- # this is used for mapping object types (e.g., Blink::Type::File) # to names (e.g., "file") def Type.name @@ -340,7 +350,7 @@ class Blink::Type < Blink::Element #--------------------------------------------------------------- #--------------------------------------------------------------- - # instance methods related to instance intrinics + # instance methods related to instance intrinsics # e.g., initialize() and name() #--------------------------------------------------------------- #--------------------------------------------------------------- @@ -348,6 +358,7 @@ class Blink::Type < Blink::Element #--------------------------------------------------------------- def initialize(hash) @children = [] + @evalcount = 0 @parent = nil @noop = false @@ -481,9 +492,18 @@ class Blink::Type < Blink::Element # this method is responsible for collecting state changes # we always descend into the children before we evaluate our current # states - def evaluate(transaction) - self.each { |child| - child.evaluate(transaction) + # this returns any changes resulting from testing, thus 'collect' + # rather than 'each' + def evaluate + # if we're a metaclass and we've already evaluated once... + if self.metaclass and @evalcount > 0 + return + end + @evalcount += 1 + # these might return messages, but the main action is through + # setting changes in the transactions + self.collect { |child| + child.evaluate } end #--------------------------------------------------------------- @@ -506,6 +526,15 @@ class Blink::Type < Blink::Element #--------------------------------------------------------------- #--------------------------------------------------------------- + # do we actually do work, or do we modify the system instead? + # instances of a metaclass only get executed once per client process, + # while instances of normal classes get run every time + def metaclass + return self.class.metaclass + end + #--------------------------------------------------------------- + + #--------------------------------------------------------------- # this method is responsible for handling changes in dependencies # for instance, restarting a service if a config file is changed # in general, we just hand the method up to our parent, but for diff --git a/lib/blink/type/component.rb b/lib/blink/type/component.rb index 7d289e45f..43906f749 100644 --- a/lib/blink/type/component.rb +++ b/lib/blink/type/component.rb @@ -6,12 +6,11 @@ # this thing contains everything else, including itself require 'blink' -require 'blink/element' -require 'blink/transaction' require 'blink/type' +require 'blink/transaction' module Blink - class Container < Blink::Element + class Component < Blink::Element @name = :container def initialize diff --git a/lib/blink/type/state.rb b/lib/blink/type/state.rb index 57fcf5683..4518fdd9a 100644 --- a/lib/blink/type/state.rb +++ b/lib/blink/type/state.rb @@ -31,16 +31,16 @@ class Blink::State < Blink::Element #--------------------------------------------------------------- #--------------------------------------------------------------- - # this assumes the controlling process will actually execute the change - # which will demonstrably not work with states that are part of a larger - # whole, like FileRecordStates - def evaluate(transaction) + # if we're not in sync, return a statechange capable of putting us + # in sync + def evaluate Blink.verbose "evaluating %s" % self self.retrieve if self.insync? Blink.verbose "%s is in sync" % self + return nil else - transaction.change(Blink::StateChange.new(self)) + return Blink::StateChange.new(self) end end #--------------------------------------------------------------- diff --git a/lib/blink/type/typegen/filerecord.rb b/lib/blink/type/typegen/filerecord.rb index e7d145d81..8c7c042b5 100644 --- a/lib/blink/type/typegen/filerecord.rb +++ b/lib/blink/type/typegen/filerecord.rb @@ -14,6 +14,7 @@ class Blink::Type::FileRecord < Blink::Type::TypeGenerator @options = [:name, :splitchar, :fields, :namevar, :filetype, :regex, :joinchar] @abstract = true + @metaclass = true @name = :filerecord diff --git a/lib/blink/type/typegen/filetype.rb b/lib/blink/type/typegen/filetype.rb index 23854ade9..44cb76826 100644 --- a/lib/blink/type/typegen/filetype.rb +++ b/lib/blink/type/typegen/filetype.rb @@ -12,9 +12,12 @@ class Blink::Type::FileType < Blink::Type::TypeGenerator @options = [:name, :linesplit, :escapednewlines] @abstract = true + @metaclass = true @name = :filetype + @modsystem = true + #--------------------------------------------------------------- def FileType.newtype(hash) unless hash.include?(:linesplit) diff --git a/test/types/tc_basic.rb b/test/types/tc_basic.rb index fae4168ce..f0030b950 100644 --- a/test/types/tc_basic.rb +++ b/test/types/tc_basic.rb @@ -21,12 +21,7 @@ class TestBasic < Test::Unit::TestCase Blink[:debug] = 1 assert_nothing_raised() { - unless Blink::Component.has_key?("sleeper") - Blink::Component.new( - :name => "sleeper" - ) - end - @component = Blink::Component["sleeper"] + @component = Blink::Component.new } assert_nothing_raised() { @@ -62,7 +57,7 @@ class TestBasic < Test::Unit::TestCase end def test_name_calls - [@component,@sleeper,@configfile].each { |obj| + [@sleeper,@configfile].each { |obj| assert_nothing_raised(){ obj.name } @@ -72,11 +67,6 @@ class TestBasic < Test::Unit::TestCase def test_name_equality #puts "Component is %s, id %s" % [@component, @component.object_id] assert_equal( - "sleeper", - @component.name - ) - - assert_equal( File.join($blinkbase,"examples/root/etc/configfile"), @configfile.name ) @@ -88,11 +78,30 @@ class TestBasic < Test::Unit::TestCase end def test_object_retrieval - [@component,@sleeper,@configfile].each { |obj| + [@sleeper,@configfile].each { |obj| assert_equal( obj.class[obj.name].object_id, obj.object_id ) } end + + def test_transaction + transaction = nil + assert_nothing_raised() { + transaction = @component.evaluate + } + assert_nothing_raised() { + transaction.evaluate + } + assert_nothing_raised() { + @sleeper[:running] = 0 + } + assert_nothing_raised() { + transaction = @component.evaluate + } + assert_nothing_raised() { + transaction.evaluate + } + end end |