summaryrefslogtreecommitdiff
path: root/lib/chef/experimental/resource2.rb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/chef/experimental/resource2.rb')
-rw-r--r--lib/chef/experimental/resource2.rb134
1 files changed, 134 insertions, 0 deletions
diff --git a/lib/chef/experimental/resource2.rb b/lib/chef/experimental/resource2.rb
new file mode 100644
index 0000000000..2c91f79097
--- /dev/null
+++ b/lib/chef/experimental/resource2.rb
@@ -0,0 +1,134 @@
+class Chef
+ module Experimental
+ class Resource2 < Chef::Resource
+ def current_resource
+ return @current_resource if instance_variable_defined?(:@current_resource)
+ provider = provider_for_action(self.class.default_action)
+ provider.load_current_resource
+ @current_resource = provider.current_resource
+ end
+
+ def self.property_type(type=NOT_PASSED,**options,&block)
+ # Combine the type with "is"
+ if type != NOT_PASSED
+ if options[:is]
+ options[:is] = ([ type ] + [ options[:is] ]).flatten(1)
+ else
+ options[:is] = type
+ end
+ end
+
+ ReadProperty.new(**options)
+ end
+
+ def self.load(&block)
+ new_action_provider_class.load_block = block
+ end
+
+ def self.new_action_provider_class
+ return @action_provider_class if @action_provider_class
+
+ unless self == Resource2
+ base_provider = superclass.action_provider_class
+ end
+
+ base_provider ||= ActionProviderClass
+
+ resource_class = self
+ action_provider_class = Class.new(base_provider) do
+ use_inline_resources
+ include_resource_dsl true
+ end
+ action_provider_class.resource_class = self
+ @action_provider_class = action_provider_class
+ end
+
+ class ActionProviderClass < Chef::Provider
+ def initialize(*args)
+ super
+ remove_instance_variable(:@current_resource)
+ end
+
+ def load_current_resource
+ # Copy over all non-desired-state
+ self.current_resource = self.class.resource_class.new(new_resource.name, run_context)
+ current_resource.instance_eval { @current_resource = nil }
+ self.class.resource_class.state_properties.each do |property|
+ if property.is_set?(new_resource)
+ property.set(current_resource, property.get(new_resource))
+ end
+ end
+ begin
+ current_resource.instance_eval(&self.class.load_block)
+ rescue ResourceDoesNotExistError
+ self.current_resource = nil
+ end
+ end
+
+ def converge(*properties, &converge_block)
+ properties = new_resource.state_properties if properties.empty?
+ modified = properties.map do |property|
+ property = new_resource.properties[property] if !property.is_a?(Property)
+ new_value = property.get(new_resource)
+ if current_resource.nil?
+ " set #{property.name} to #{new_value}"
+ elsif property.is_set?(new_resource)
+ current_value = property.get(current_resource)
+ if new_value != current_value
+ " set #{property.name} to #{new_value} (was #{current_value})"
+ end
+ end
+ end.compact
+
+ if !modified.empty?
+ if current_resource.nil?
+ converge_by([ "create #{current_resource}", **modified ], &converge_block)
+ else
+ converge_by([ "update #{current_resource}", **modified ], &converge_block)
+ end
+ end
+ end
+
+ def resource_does_not_exist!
+ raise ResourceDoesNotExistError, new_resource
+ end
+
+ def self.resource_class
+ @resource_class
+ end
+ def self.resource_class=(value)
+ raise "Cannot set resource_class on #{self} to two different resources! (Setting to #{value}, was #{resource_class})" if resource_class && resource_class != value
+ @resource_class = value
+ end
+
+ def self.load_block
+ return @load_block if @load_block
+ return superclass.load_block if superclass.respond_to?(:load_block)
+ end
+ def self.load_block=(value)
+ @load_block = value
+ end
+
+ def self.to_s
+ "#{resource_class} action provider"
+ end
+ def self.inspect
+ to_s
+ end
+ end
+
+ class ReadProperty < Property
+ def get(resource)
+ if !is_set?(resource) && desired_state? && resource.current_resource
+ super(resource.current_resource)
+ else
+ super(resource)
+ end
+ end
+ end
+ end
+ end
+
+ class ResourceDoesNotExistError < StandardError
+ end
+end