summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/blink/client.rb4
-rw-r--r--lib/blink/fact.rb2
-rw-r--r--lib/blink/types.rb333
-rw-r--r--lib/blink/types/file.rb8
-rw-r--r--lib/blink/types/package.rb12
-rw-r--r--lib/blink/types/process.rb8
-rw-r--r--lib/blink/types/service.rb8
-rw-r--r--lib/blink/types/symlink.rb8
8 files changed, 255 insertions, 128 deletions
diff --git a/lib/blink/client.rb b/lib/blink/client.rb
index 7ebc43c71..69594fd40 100644
--- a/lib/blink/client.rb
+++ b/lib/blink/client.rb
@@ -27,12 +27,12 @@ module Blink
end
def objects=(list)
- Blink::Types.buildtypehash # refresh the list of available types
+ Blink::Type.buildtypehash # refresh the list of available types
objects = list.collect { |object|
# create a Blink object from the list...
#puts "yayness"
- if type = Blink::Types.type(object.type)
+ if type = Blink::Type.type(object.type)
namevar = type.namevar
if namevar != :name
object[namevar] = object[:name]
diff --git a/lib/blink/fact.rb b/lib/blink/fact.rb
index de7d7aae0..375e09386 100644
--- a/lib/blink/fact.rb
+++ b/lib/blink/fact.rb
@@ -39,7 +39,7 @@ module Blink
return :name
end
- Blink::Types.newtype(self)
+ Blink::Type.newtype(self)
# we're adding a new resolution mechanism here; this is just how
# types work
diff --git a/lib/blink/types.rb b/lib/blink/types.rb
index 01b4f2d57..f55700c42 100644
--- a/lib/blink/types.rb
+++ b/lib/blink/types.rb
@@ -5,8 +5,6 @@
# included so we can test object types
require 'blink/types/state'
-# this is our base class
-require 'blink/interface'
# XXX see the bottom of the file for the rest of the inclusions
@@ -16,13 +14,36 @@ require 'blink/interface'
# the subclasses include states which do the actual work.
# See state.rb for how work is actually done.
+# our duck type interface -- if your object doesn't match this interface,
+# it won't work
+
+# all of our first-class objects (objects, states, and components) will
+# respond to these methods
+# although states don't inherit from Blink::Type
+# although maybe Blink::State should...
+
+# the default behaviour that this class provides is to just call a given
+# method on each contained object, e.g., in calling 'sync', we just run:
+# object.each { |subobj| subobj.sync() }
+
+# to use this interface, just define an 'each' method and 'include Blink::Type'
+
module Blink
- class Types < Blink::Interface
+ class Type
include Enumerable
- @objects = Hash.new
- @@allobjects = Array.new # and then an array for all objects
+ # this is a bit of a hack, but it'll work for now
+ attr_accessor :performoperation
+ attr_writer :noop
+ @@allobjects = Array.new # an array for all objects
+ #---------------------------------------------------------------
+ #---------------------------------------------------------------
+ # these objects are used for mapping type names (e.g., 'file')
+ # to actual object classes; because Type.inherited is
+ # called before the <subclass>.name method is defined, we need
+ # to store each class in an array, and then later actually iterate
+ # across that array and make a map
@@typeary = []
@@typehash = Hash.new { |hash,key|
if key.is_a?(String)
@@ -36,37 +57,100 @@ module Blink
}
#---------------------------------------------------------------
- # the class methods
+ def Type.newtype(type)
+ @@typeary.push(type)
+ if @@typehash.has_key?(type.name)
+ Blink.notice("Redefining object type %s" % type.name)
+ end
+ @@typehash[type.name] = type
+ end
+ #---------------------------------------------------------------
- #-----------------------------------
- # all objects total
- def Types.push(object)
- @@allobjects.push object
- #Blink.debug("adding %s of type %s to master list" %
- # [object.name,object.class])
- end
- #-----------------------------------
+ #---------------------------------------------------------------
+ def Type.type(type)
+ unless @@typeary.length == @@typehash.length
+ Type.buildtypehash
+ end
+ @@typehash[type]
+ end
+ #---------------------------------------------------------------
- #-----------------------------------
+ #---------------------------------------------------------------
# this is meant to be run multiple times, e.g., when a new
# type is defined at run-time
- def Types.buildtypehash
+ def Type.buildtypehash
@@typeary.each { |otype|
if @@typehash.include?(otype.name)
if @@typehash[otype.name] != otype
- Blink.warning("Object type %s is already defined" % otype.name)
+ Blink.warning("Object type %s is already defined" %
+ otype.name)
end
else
@@typehash[otype.name] = otype
end
}
end
- #-----------------------------------
+ #---------------------------------------------------------------
+ #---------------------------------------------------------------
- #-----------------------------------
+ #---------------------------------------------------------------
+ # retrieve a named object
+ def Type.[](name)
+ if @objects.has_key?(name)
+ return @objects[name]
+ else
+ raise "Object '#{name}' does not exist"
+ end
+ end
+ #---------------------------------------------------------------
+
+ #---------------------------------------------------------------
+ def Type.[]=(name,object)
+ newobj = nil
+ if object.is_a?(Blink::Type)
+ newobj = object
+ else
+ raise "must pass a Blink::Type object"
+ end
+
+ if @objects.has_key?(newobj.name)
+ puts @objects
+ raise "'#{newobj.name}' already exists in " +
+ "class '#{newobj.class}': #{@objects[newobj.name]}"
+ else
+ #Blink.debug("adding %s of type %s to class list" %
+ # [object.name,object.class])
+ @objects[newobj.name] = newobj
+ end
+ end
+ #---------------------------------------------------------------
+
+ #---------------------------------------------------------------
+ # all objects total
+ def Type.push(object)
+ @@allobjects.push object
+ #Blink.debug("adding %s of type %s to master list" %
+ # [object.name,object.class])
+ end
+ #---------------------------------------------------------------
+
+ #---------------------------------------------------------------
+ # some simple stuff to make it easier to get a name from everyone
+ def Type.namevar
+ return @namevar
+ end
+ #---------------------------------------------------------------
+
+ #---------------------------------------------------------------
+ def Type.has_key?(name)
+ return @objects.has_key?(name)
+ end
+ #---------------------------------------------------------------
+
+ #---------------------------------------------------------------
# this should make it so our subclasses don't have to worry about
# defining these class instance variables
- def Types.inherited(sub)
+ def Type.inherited(sub)
sub.module_eval %q{
@objects = Hash.new
@actions = Hash.new
@@ -78,50 +162,103 @@ module Blink
# get executed, which, um, sucks
@@typeary.push(sub)
end
- #-----------------------------------
+ #---------------------------------------------------------------
- #-----------------------------------
- # this is used for mapping object types (e.g., Blink::Types::File)
+ #---------------------------------------------------------------
+ # this is used for mapping object types (e.g., Blink::Type::File)
# to names (e.g., "file")
- def Types.name
+ def Type.name
return @name
end
- #-----------------------------------
-
- #-----------------------------------
- # some simple stuff to make it easier to get a name from everyone
- def Types.namevar
- return @namevar
- end
- #-----------------------------------
+ #---------------------------------------------------------------
- #-----------------------------------
- def Types.newtype(type)
- @@typeary.push(type)
- if @@typehash.has_key?(type.name)
- Blink.notice("Redefining object type %s" % type.name)
+ #---------------------------------------------------------------
+ def evaluate
+ self.retrieve
+ unless self.insync?
+ if @performoperation == :sync
+ self.sync
+ else
+ # we, uh, don't do anything
+ end
end
- @@typehash[type.name] = type
+ self.retrieve
end
- #-----------------------------------
+ #---------------------------------------------------------------
- #-----------------------------------
- def Types.type(type)
- @@typehash[type]
+ #---------------------------------------------------------------
+ # return the full path to us, for logging and rollback
+ # some classes (e.g., FileTypeRecords) will have to override this
+ def fqpath
+ return self.class, self.name
end
- #-----------------------------------
+ #---------------------------------------------------------------
- #-----------------------------------
+ #---------------------------------------------------------------
+ # if all contained objects are in sync, then we're in sync
+ def insync?
+ insync = true
+
+ self.each { |obj|
+ unless obj.insync?
+ Blink.debug("%s is not in sync" % obj)
+ insync = false
+ end
+ }
+
+ Blink.debug("%s sync status is %s" % [self,insync])
+ return insync
+ end
+ #---------------------------------------------------------------
+
+ #---------------------------------------------------------------
+ # should we actually do anything?
+ def noop
+ return self.noop || Blink[:noop] || false
+ end
+ #---------------------------------------------------------------
+
+ #---------------------------------------------------------------
+ # set up the "interface" methods
+ [:sync,:retrieve].each { |method|
+ self.send(:define_method,method) {
+ self.each { |subobj|
+ #Blink.debug("sending '%s' to '%s'" % [method,subobj])
+ subobj.send(method)
+ }
+ }
+ }
+ #---------------------------------------------------------------
+
+ #---------------------------------------------------------------
+ def presync
+ self.each { |contained|
+ # this gets right to the heart of our question:
+ # do all subclasses of Type contain all of their
+ # content in contained objects?
+ Blink::Modification.new(contained)
+ }
+ end
+ #---------------------------------------------------------------
+ end
+end
+ #---------------------------------------------------------------
+ #---------------------------------------------------------------
+ # the class methods
+ #---------------------------------------------------------------
+ #---------------------------------------------------------------
+
+ #---------------------------------------------------------------
# accessor for the list of acceptable params
- def Types.classparams
+ def Type.classparams
return @params
end
- #-----------------------------------
+ #---------------------------------------------------------------
- #-----------------------------------
+ #---------------------------------------------------------------
# our param list is by class, so we need to convert it to names
# (see blink/objects/file.rb for an example of how params are defined)
- def Types.classparambyname
+ def Type.classparambyname
unless defined? @paramsbyname
@paramsbyname = Hash.new { |hash,key|
if key.is_a?(String)
@@ -155,12 +292,15 @@ module Blink
end
return @paramsbyname
end
- #-----------------------------------
+ #---------------------------------------------------------------
#---------------------------------------------------------------
+ #---------------------------------------------------------------
# the instance methods
+ #---------------------------------------------------------------
+ #---------------------------------------------------------------
- #-----------------------------------
+ #---------------------------------------------------------------
# parameter access and stuff
def [](param)
if @states.has_key?(param)
@@ -169,9 +309,9 @@ module Blink
raise "Undefined parameter '#{param}' in #{self}"
end
end
- #-----------------------------------
+ #---------------------------------------------------------------
- #-----------------------------------
+ #---------------------------------------------------------------
# because all object parameters are actually states, we
# have to do some shenanigans to make it look from the outside
# like @states is just a simple hash
@@ -207,9 +347,9 @@ module Blink
end
end
end
- #-----------------------------------
+ #---------------------------------------------------------------
- #-----------------------------------
+ #---------------------------------------------------------------
# return action array
# these are actions to use for responding to events
# no, this probably isn't the best way, because we're providing
@@ -221,9 +361,9 @@ module Blink
end
@actions
end
- #-----------------------------------
+ #---------------------------------------------------------------
- #-----------------------------------
+ #---------------------------------------------------------------
# removing states
def delete(attr)
if @states.has_key?(attr)
@@ -232,9 +372,9 @@ module Blink
raise "Undefined state '#{attr}' in #{self}"
end
end
- #-----------------------------------
+ #---------------------------------------------------------------
- #-----------------------------------
+ #---------------------------------------------------------------
# XXX this won't work -- too simplistic
# a given object can be in multiple components
# which means... what? that i have to delete things from components?
@@ -243,13 +383,13 @@ module Blink
#def delete
# self.class.delete[self.name]
#end
- #-----------------------------------
+ #---------------------------------------------------------------
- #-----------------------------------
+ #---------------------------------------------------------------
# this can only be used with blocks that are
# valid on operations and objects, as it iterates over both of
# them
- # essentially, the interface defined by Blink::Interface is used here
+ # essentially, the interface defined by Blink::Type is used here
def each
ret = false
nodepth = 0
@@ -286,9 +426,9 @@ module Blink
#end
#return ret
end
- #-----------------------------------
+ #---------------------------------------------------------------
- #-----------------------------------
+ #---------------------------------------------------------------
# this allows each object to act like both a node and
# a branch
# but each object contains two types of objects: operations and other
@@ -301,39 +441,40 @@ module Blink
yield(object)
}
end
- #-----------------------------------
+ #---------------------------------------------------------------
+ #---------------------------------------------------------------
#-----------------------------------
# store the object that immediately encloses us
def enclosedby(obj)
@enclosedby.push(obj)
end
- #-----------------------------------
+ #---------------------------------------------------------------
- #-----------------------------------
+ #---------------------------------------------------------------
def enclosed?
defined? @enclosedby
end
- #-----------------------------------
+ #---------------------------------------------------------------
- #-----------------------------------
+ #---------------------------------------------------------------
# store a enclosed object
def encloses(obj)
obj.enclosedby(self)
#obj.subscribe(self,'*')
@encloses.push(obj)
end
- #-----------------------------------
+ #---------------------------------------------------------------
- #-----------------------------------
+ #---------------------------------------------------------------
# this is a wrapper, doing all of the work that should be done
# and none that shouldn't
def evaluate
raise "don't call evaluate; it's disabled"
end
- #-----------------------------------
+ #---------------------------------------------------------------
- #-----------------------------------
+ #---------------------------------------------------------------
# call an event
# this is called on subscribers by the trigger method from the obj
# which sent the event
@@ -348,9 +489,9 @@ module Blink
p @actions
end
end
- #-----------------------------------
+ #---------------------------------------------------------------
- #-----------------------------------
+ #---------------------------------------------------------------
# yay
def initialize(*args)
# params are for classes, states are for instances
@@ -402,38 +543,24 @@ module Blink
self.class[name] = self
# and then add it to the master list
- Blink::Types.push(self)
+ Blink::Type.push(self)
@notify = Hash.new
#@encloses = Array.new
#@enclosedby = Array.new
@actions = Hash.new
#@opsgenned = false
-
- # XXX i've no idea wtf is going on with enclosures
- #if self.class == Blink::Types::Root
- # Blink.debug "not enclosing root (#{self.class}) in self"
- #else
- # Blink::Types.root.encloses(self)
- #end
end
# initialize
- #-----------------------------------
+ #---------------------------------------------------------------
- #-----------------------------------
+ #---------------------------------------------------------------
def name
- #namevar = self.class.namevar
- #Blink.debug "namevar is '%s'" % namevar
- #nameattr = @states[namevar]
- #Blink.debug "nameattr is '%s'" % nameattr
- #name = nameattr.value
- #Blink.debug "returning %s from attr %s and namevar %s" % [name,nameattr,namevar]
- #return name
return @states[self.class.namevar].is
end
- #-----------------------------------
+ #---------------------------------------------------------------
- #-----------------------------------
+ #---------------------------------------------------------------
def newevent(args)
if args[:event].nil?
raise "newevent called wrong on #{self}"
@@ -444,9 +571,9 @@ module Blink
:object => self
)
end
- #-----------------------------------
+ #---------------------------------------------------------------
- #-----------------------------------
+ #---------------------------------------------------------------
# subscribe to an event or all events
# this entire event system is a hack job and needs to
# be replaced with a central event handler
@@ -469,15 +596,15 @@ module Blink
#else
# @notify['*'.intern].push(obj)
end
- #-----------------------------------
+ #---------------------------------------------------------------
- #-----------------------------------
+ #---------------------------------------------------------------
def to_s
self.name
end
- #-----------------------------------
+ #---------------------------------------------------------------
- #-----------------------------------
+ #---------------------------------------------------------------
# initiate a response to an event
def trigger(event)
subscribers = Array.new
@@ -493,9 +620,9 @@ module Blink
obj.event(event,self)
}
end
- #-----------------------------------
+ #---------------------------------------------------------------
- #-----------------------------------
+ #---------------------------------------------------------------
def validparam(param)
if (self.class.operparams.include?(param) or
self.class.staticparams.include?(param))
@@ -504,10 +631,10 @@ module Blink
return false
end
end
- #-----------------------------------
+ #---------------------------------------------------------------
#---------------------------------------------------------------
- end # Blink::Types
+ end # Blink::Type
end
require 'blink/types/service'
require 'blink/types/file'
diff --git a/lib/blink/types/file.rb b/lib/blink/types/file.rb
index 71ef3315c..77c322c95 100644
--- a/lib/blink/types/file.rb
+++ b/lib/blink/types/file.rb
@@ -193,8 +193,8 @@ module Blink
end
end
end
- class Types
- class File < Types
+ class Type
+ class File < Type
attr_reader :stat, :path, :params
# class instance variable
@params = [
@@ -207,7 +207,7 @@ module Blink
@name = :file
@namevar = :path
- end # Blink::Types::File
- end # Blink::Types
+ end # Blink::Type::File
+ end # Blink::Type
end
diff --git a/lib/blink/types/package.rb b/lib/blink/types/package.rb
index a012816a0..6b09abc17 100644
--- a/lib/blink/types/package.rb
+++ b/lib/blink/types/package.rb
@@ -24,11 +24,11 @@ module Blink
end
end
- class Types
+ class Type
# packages are complicated because each package format has completely
# different commands. We need some way to convert specific packages
# into the general package object...
- class Package < Types
+ class Package < Type
attr_reader :version, :format
@params = [
Blink::State::PackageInstalled,
@@ -45,7 +45,7 @@ module Blink
@name = :package
@namevar = :name
- end # Blink::Types::Package
+ end # Blink::Type::Package
class PackagingType
attr_writer :list, :install, :remove, :check
@@ -120,7 +120,7 @@ module Blink
fields.zip(match.captures) { |field,value|
hash[field] = value
}
- packages.push Blink::Types::Package.new(hash)
+ packages.push Blink::Type::Package.new(hash)
else
raise "failed to match dpkg line %s" % line
end
@@ -174,7 +174,7 @@ module Blink
process.each { |line|
case line
when /^$/ then
- packages.push Blink::Types::Package.new(hash)
+ packages.push Blink::Type::Package.new(hash)
hash.clear
when /\s*(\w+):\s+(.+)/
name = $1
@@ -250,5 +250,5 @@ module Blink
end
}
}
- end # Blink::Types
+ end # Blink::Type
end
diff --git a/lib/blink/types/process.rb b/lib/blink/types/process.rb
index ff0870dba..7cc7169b4 100644
--- a/lib/blink/types/process.rb
+++ b/lib/blink/types/process.rb
@@ -57,8 +57,8 @@ module Blink
end
end
end
- class Types
- class BProcess < Types
+ class Type
+ class BProcess < Type
attr_reader :stat, :path
@params = [:start, :stop, :user, :pattern, :binary, :arguments]
@name = :process
@@ -77,7 +77,7 @@ module Blink
:pattern => :pattern
})
- end # Blink::Types::BProcess
- end # Blink::Types
+ end # Blink::Type::BProcess
+ end # Blink::Type
end
diff --git a/lib/blink/types/service.rb b/lib/blink/types/service.rb
index be2f4eb4d..280bc7fc7 100644
--- a/lib/blink/types/service.rb
+++ b/lib/blink/types/service.rb
@@ -69,8 +69,8 @@ module Blink
end
end
end
- class Types
- class Service < Types
+ class Type
+ class Service < Type
attr_reader :stat
@params = [
Blink::State::ServiceRunning,
@@ -133,6 +133,6 @@ module Blink
@initscript = Service.search(self.name)
end
end
- end # Blink::Types::BProcess
- end # Blink::Types
+ end # Blink::Type::Service
+ end # Blink::Type
end
diff --git a/lib/blink/types/symlink.rb b/lib/blink/types/symlink.rb
index 98ecd7f3c..0e85c2e85 100644
--- a/lib/blink/types/symlink.rb
+++ b/lib/blink/types/symlink.rb
@@ -86,8 +86,8 @@ module Blink
end
end
- class Types
- class Symlink < Types
+ class Type
+ class Symlink < Type
attr_reader :stat, :path, :params
# class instance variable
@params = [
@@ -100,7 +100,7 @@ module Blink
@name = :symlink
@namevar = :path
- end # Blink::Types::File
- end # Blink::Types
+ end # Blink::Type::Symlink
+ end # Blink::Type
end