From: David Lutterkort <lut...@redhat.com> Extension attributes now need to be mentioned twice: in the model class they are declared like any other attribute. In the service class, resource metadata can be added using
metadata attr_name, :type => TYPE, :constraints => PROC --- server/lib/cimi/models/cloud_entry_point.rb | 4 +- server/lib/cimi/models/machine.rb | 8 +-- server/lib/cimi/models/machine_template.rb | 3 +- server/lib/cimi/models/resource_metadata.rb | 10 --- server/lib/cimi/models/schema.rb | 9 --- server/lib/cimi/service.rb | 10 ++- server/lib/cimi/service/base.rb | 58 ++++++++++++++++++ server/lib/cimi/service/cloud_entry_point.rb | 3 + server/lib/cimi/service/machine.rb | 7 +++ server/lib/cimi/service/machine_template.rb | 4 +- server/lib/cimi/service/resource_metadata.rb | 92 ++++------------------------ 11 files changed, 98 insertions(+), 110 deletions(-) diff --git a/server/lib/cimi/models/cloud_entry_point.rb b/server/lib/cimi/models/cloud_entry_point.rb index a016004..a1ec0a7 100644 --- a/server/lib/cimi/models/cloud_entry_point.rb +++ b/server/lib/cimi/models/cloud_entry_point.rb @@ -15,8 +15,8 @@ class CIMI::Model::CloudEntryPoint < CIMI::Model::Base - resource_attr :driver, :required => true - resource_attr :provider, :required => true + text :driver, :required => true + text :provider, :required => true # All possible CIMI collections, in the order in which they should appear # in the CEP diff --git a/server/lib/cimi/models/machine.rb b/server/lib/cimi/models/machine.rb index 6990fb9..3d1369c 100644 --- a/server/lib/cimi/models/machine.rb +++ b/server/lib/cimi/models/machine.rb @@ -17,10 +17,10 @@ class CIMI::Model::Machine < CIMI::Model::Base acts_as_root_entity - resource_attr :realm, :required => false, - :constraints => lambda { |c| c.driver.realms(c.credentials).map { |r| r.id } } - - resource_attr :machine_image, :required => false, :type => :href + # DC-specific Extension + text :realm, :required => false + # DC-specific extension + href :machine_image, :required => false text :state text :cpu diff --git a/server/lib/cimi/models/machine_template.rb b/server/lib/cimi/models/machine_template.rb index 812ad15..68e865b 100644 --- a/server/lib/cimi/models/machine_template.rb +++ b/server/lib/cimi/models/machine_template.rb @@ -22,8 +22,7 @@ class CIMI::Model::MachineTemplate < CIMI::Model::Base ref :machine_image ref :credential - resource_attr :realm, :required => false, - :constraints => lambda { |c| c.driver.realms(c.credentials).map { |r| r.id }} + text :realm, :required => false array :volumes do scalar :href, :initial_location diff --git a/server/lib/cimi/models/resource_metadata.rb b/server/lib/cimi/models/resource_metadata.rb index 2c4ee08..0a2ab5d 100644 --- a/server/lib/cimi/models/resource_metadata.rb +++ b/server/lib/cimi/models/resource_metadata.rb @@ -51,14 +51,4 @@ class CIMI::Model::ResourceMetadata < CIMI::Model::Base array :operations do scalar :rel, :href end - - def self.add_resource_attribute!(klass, name, opts={}) - resource_attributes[klass.name] ||= {} - resource_attributes[klass.name][name] = opts - end - - def self.resource_attributes - @resource_attributes ||= {} - end - end diff --git a/server/lib/cimi/models/schema.rb b/server/lib/cimi/models/schema.rb index 9c27c6f..b6651a7 100644 --- a/server/lib/cimi/models/schema.rb +++ b/server/lib/cimi/models/schema.rb @@ -425,15 +425,6 @@ class CIMI::Model::Schema # +add_attributes!+ method module DSL - def resource_attr(name, opts={}) - CIMI::Model::ResourceMetadata.add_resource_attribute!(self, name, opts) - if opts[:type] - send(opts[:type], name) - else - text name - end - end - def href(*args) opts = args.extract_opts! args.each { |arg| struct(arg, opts) { scalar :href, :required => opts[:required] } } diff --git a/server/lib/cimi/service.rb b/server/lib/cimi/service.rb index b05efbf..8176532 100644 --- a/server/lib/cimi/service.rb +++ b/server/lib/cimi/service.rb @@ -14,7 +14,15 @@ # under the License. # -module CIMI::Service; end +module CIMI + module Service + def self.root_entities + CIMI::Model::root_entities.map do |m| + CIMI::Service.const_get(m.name.split('::').last) + end + end + end +end require_relative './models' require_relative './../db/provider' diff --git a/server/lib/cimi/service/base.rb b/server/lib/cimi/service/base.rb index fa845d0..b829e6a 100644 --- a/server/lib/cimi/service/base.rb +++ b/server/lib/cimi/service/base.rb @@ -136,6 +136,64 @@ module CIMI::Service end end + # + # Resource metadata + # + METADATA_TYPES = [ 'text', 'URI', 'string', 'boolean' ] + + # A hash of the attributes that need to be mentioned in the given + # context + def self.resource_attributes(context) + metadata.keys.map do |k| + a = model_class.schema.attributes.find { |a| a.name == k } + raise "No attribute named #{k} defined" unless a + constr = metadata[k][:constraints].call(context) + { + :name => a.name, + :namespace => "http://deltacloud.org/cimi/#{model_name}/#{a.name}", + :type => metadata[k][:type], + :required => a.required? ? 'true' : 'false', + :constraints => constr.map { |v| { :value => v } } + } + end + end + + def self.resource_capabilities(context) + cimi_object = model_name.to_s.pluralize.to_sym + driver_class = context.driver.class + (driver_class.features[cimi_object] || []).map do |cur| + feat = CIMI::FakeCollection.feature(cur) + values = driver_class.constraints[cimi_object][feat.name][:values] || [] + { :name => feat.name.to_s.camelize, + :uri => CMWG_NAMESPACE+"/capability/#{cimi_object.to_s.camelize.singularize}/#{feat.name.to_s.camelize}", + :description => feat.description, + :value => values.join(",") + } + end + end + + # Define the metadata for an attribute; +opts+ must be a Hash that can + # contain the following entries: + # :type : one of METADATA_TYPES + # :constraints : a proc that is passed the current context and + # must return a list of values + def self.metadata(attr_name = nil, opts = nil) + @metadata ||= {} + return @metadata if attr_name.nil? && opts.nil? + + opts[:type] ||= 'text' + opts[:type] = opts[:type].to_s + opts[:constraints] ||= lambda { |_| [] } + unless METADATA_TYPES.include?(opts[:type]) + raise "Metadata type must be one of #{METADATA_TYPES.join(",")}" + end + metadata[attr_name] = opts + end + + # + # Database interactions + # + # Save the common attributes name, description, and properties to the # database def save diff --git a/server/lib/cimi/service/cloud_entry_point.rb b/server/lib/cimi/service/cloud_entry_point.rb index 5029e12..9491e3d 100644 --- a/server/lib/cimi/service/cloud_entry_point.rb +++ b/server/lib/cimi/service/cloud_entry_point.rb @@ -15,6 +15,9 @@ class CIMI::Service::CloudEntryPoint < CIMI::Service::Base + metadata :driver, :type => 'text' + metadata :provider, :type => 'text' + def self.create(context) self.new(context, :values => entities(context).merge({ :name => context.driver.name, diff --git a/server/lib/cimi/service/machine.rb b/server/lib/cimi/service/machine.rb index 7112486..f347cda 100644 --- a/server/lib/cimi/service/machine.rb +++ b/server/lib/cimi/service/machine.rb @@ -15,6 +15,13 @@ class CIMI::Service::Machine < CIMI::Service::Base + metadata :realm, + :constraints => lambda { |c| + c.driver.realms(c.credentials).map { |r| r.id } + } + + metadata :machine_image, :type => 'URI' + def self.find(id, context) instances = [] if id == :all diff --git a/server/lib/cimi/service/machine_template.rb b/server/lib/cimi/service/machine_template.rb index e790e89..4a3cd4e 100644 --- a/server/lib/cimi/service/machine_template.rb +++ b/server/lib/cimi/service/machine_template.rb @@ -15,9 +15,7 @@ class CIMI::Service::MachineTemplate < CIMI::Service::Base - def initialize(ctx, opts) - super - end + metadata :realm, :constraints => lambda { |c| c.driver.realms(c.credentials).map { |r| r.id }} class << self def find(id, context) diff --git a/server/lib/cimi/service/resource_metadata.rb b/server/lib/cimi/service/resource_metadata.rb index 23924fb..3a8f09f 100644 --- a/server/lib/cimi/service/resource_metadata.rb +++ b/server/lib/cimi/service/resource_metadata.rb @@ -15,96 +15,30 @@ class CIMI::Service::ResourceMetadata < CIMI::Service::Base - def initialize(ctx, opts) - super - end - def self.find(id, context) if id == :all - resource_metadata = [] - CIMI::Model.root_entities.each do |resource_class| - meta = resource_metadata_for(resource_class, context) - resource_metadata << meta unless none_defined(meta) - end - return resource_metadata + CIMI::Service.root_entities.map do |svc_class| + resource_metadata_for(svc_class, context) + end.reject { |metadata| metadata.none_defined? } else - resource_class = CIMI::Model.const_get("#{id.camelize}") - resource_metadata_for(resource_class, context) + svc_class = CIMI::Service.const_get("#{id.camelize}") + resource_metadata_for(svc_class, context) end end - def self.resource_metadata_for(resource_class, context) - attributes = rm_attributes_for(resource_class, context) - capabilities = rm_capabilities_for(resource_class, context) - actions = rm_actions_for(resource_class, context) - cimi_resource = resource_class.name.split("::").last + def self.resource_metadata_for(svc_class, context) + cimi_resource = svc_class.name.split("::").last self.new(context, :values => { :id => context.resource_metadata_url(cimi_resource.underscore), :name => cimi_resource, - :type_uri => resource_class.resource_uri, - :attributes => attributes, - :capabilities => capabilities, - :actions => actions + :type_uri => svc_class.model_class.resource_uri, + :attributes => svc_class.resource_attributes(context), + :capabilities => svc_class.resource_capabilities(context), + :actions => [] }) end - private - - def self.rm_attributes_for(resource_class, context) - return [] if resource_attributes[resource_class.name].nil? - resource_attributes[resource_class.name].map do |attr_name, attr_def| - if attr_def.has_key? :constraints - constraints = attr_def[:constraints].call(context) - else - constraints = [] - end - { - :name => attr_name.to_s, - # TODO: We need to make this URI return description of this 'non-CIMI' - # attribute - :namespace => "http://deltacloud.org/cimi/#{resource_class.name.split('::').last}/#{attr_name}", - :type => translate_attr_type(attr_def[:type]), - :required => attr_def[:required] ? 'true' : 'false', - :constraints => constraints.map { |v| { :value => v }} - } - end - end - - # FIXME: This method is srsly a nightmare ;-) - # - def self.rm_capabilities_for(resource_class,context) - cimi_object = resource_class.name.split("::").last.underscore.pluralize.to_sym - (context.driver.class.features[cimi_object] || []).inject([]) do |res, cur| - feat = CIMI::FakeCollection.feature(cur) - values = (context.driver.class.constraints[cimi_object][feat.name][:values] || []).inject([]) do |vals, val| - vals << val - vals - end - res << {:name => feat.name.to_s.camelize, - :uri => CMWG_NAMESPACE+"/capability/#{cimi_object.to_s.camelize.singularize}/#{feat.name.to_s.camelize}", - :description => feat.description, - :value => values.join(",") } - res - end - end - - def self.rm_actions_for(resource_class, context) - [] - end - - def self.translate_attr_type(type) - case type - when :href then 'URI' - when :text then 'string' - when :boolean then 'boolean' - else 'text' - end - end - - def self.none_defined(metadata) - return true if metadata.capabilities.empty? && metadata.capabilities.empty? && metadata.attributes.empty? - return false + def none_defined? + capabilities.empty? && attributes.empty? end - - end -- 1.8.1.4