You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@deltacloud.apache.org by lu...@redhat.com on 2012/10/06 02:52:04 UTC

RFC: embedded CIMI collections

These series of patches adds support for embedded collections for CIMI
models. It's not quite perfect yet, since it doesn't produce the exactly
right XML yet, nor is it possible to parse objects with embedded
collections.

The main reason I like this better than the way Michal did it is because it
makes it unnecessary to have XXXCollection classes for
collections. Instead, you can just write

  collection :things, :class => CIMI::Model::Thing

For example, for the disks collection in machine, we simply have

  class CIMI::Model::Machine < CIMI::Model::Base
    ...
    collection :disks, :class => CIMI::Model::Disk
    ...
  end

The interesting stuff are the last three patches in the series. The other
ones can probably be acked and committed as they are.

David

[PATCH 3/7] CIMI models: let the schema convert raw values for model objects

Posted by lu...@redhat.com.
From: David Lutterkort <lu...@redhat.com>

This is a noop for now
---
 server/lib/cimi/models/base.rb   |    9 +++++++--
 server/lib/cimi/models/schema.rb |   10 ++++++++++
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/server/lib/cimi/models/base.rb b/server/lib/cimi/models/base.rb
index 4c9b2dc..eefa868 100644
--- a/server/lib/cimi/models/base.rb
+++ b/server/lib/cimi/models/base.rb
@@ -161,14 +161,19 @@ class CIMI::Model::Base
   end
 
   def []=(a, v)
-    @attribute_values[a] = v
+    @attribute_values[a] = self.class.schema.convert(a, v)
+  end
   end
 
   #
   # Factory methods
   #
   def initialize(values = {})
-    @attribute_values = values
+    names = self.class.schema.attribute_names
+    @attribute_values = names.inject({}) do |hash, name|
+      hash[name] = self.class.schema.convert(name, values[name])
+      hash
+    end
   end
 
   # Construct a new object from the XML representation +xml+
diff --git a/server/lib/cimi/models/schema.rb b/server/lib/cimi/models/schema.rb
index ed3541a..e679b2e 100644
--- a/server/lib/cimi/models/schema.rb
+++ b/server/lib/cimi/models/schema.rb
@@ -46,6 +46,10 @@ class CIMI::Model::Schema
     def to_json(model, json)
       json[@json_name] = model[@name] if model and model[@name]
     end
+
+    def convert(value)
+      value
+    end
   end
 
   class Scalar < Attribute
@@ -222,6 +226,12 @@ class CIMI::Model::Schema
     @attributes = []
   end
 
+  def convert(name, value)
+    attr = @attributes.find { |a| a.name == name }
+    raise "Unknown attribute #{name}" unless attr
+    attr.convert(value)
+  end
+
   def from_xml(xml, model = {})
     @attributes.freeze
     @attributes.each { |attr| attr.from_xml(xml, model) }
-- 
1.7.7.6


[PATCH 5/7] CIMI: add collection support to model DSL

Posted by lu...@redhat.com.
From: David Lutterkort <lu...@redhat.com>

We reuse the CIMI::Model::Collection class that is also used for toplevel
collections. With that, we won't need special purpose XXXCollection
classes.
---
 server/lib/cimi/models/base.rb   |    3 ++
 server/lib/cimi/models/schema.rb |   45 +++++++++++++++++++++++++++++++++----
 2 files changed, 43 insertions(+), 5 deletions(-)

diff --git a/server/lib/cimi/models/base.rb b/server/lib/cimi/models/base.rb
index 2a27a8f..2e66694 100644
--- a/server/lib/cimi/models/base.rb
+++ b/server/lib/cimi/models/base.rb
@@ -66,6 +66,9 @@ require 'json'
 #   [array(name, opts, &block)]
 #     An array of structured subobjects; the block defines the schema of
 #     the subobjects.
+#   [collection(name, opts)]
+#     A collection of associated objects; use the +:class+ option to
+#     specify the type of the collection entries
 
 module CIMI::Model
 
diff --git a/server/lib/cimi/models/schema.rb b/server/lib/cimi/models/schema.rb
index e679b2e..d8ba13b 100644
--- a/server/lib/cimi/models/schema.rb
+++ b/server/lib/cimi/models/schema.rb
@@ -216,6 +216,41 @@ class CIMI::Model::Schema
     end
   end
 
+  class Collection < Attribute
+    def initialize(name, opts = {})
+      super(name, opts)
+      unless opts[:class]
+        raise "Specify the class of collection entries using :class"
+      end
+      @collection_class = CIMI::Model::Collection.generate(opts[:class])
+    end
+
+    def from_xml(xml, model)
+      raise "Parsing collections (#{name}) not supported"
+    end
+
+    def from_json(json, model)
+      raise "Parsing collections (#{name}) not supported"
+    end
+
+    def to_xml(model, xml)
+      xml[xml_name] = @collection_class.schema.to_xml(model[name])
+    end
+
+    def to_json(model, json)
+      json[json_name] = @collection_class.schema.to_json(model[name])
+    end
+
+    # Convert a Hash or Array to an instance of the collection class
+    def convert(value)
+      if value.is_a?(::Array)
+        @collection_class.new(:entries => value)
+      else
+        @collection_class.new(value || {})
+      end
+    end
+  end
+
   #
   # The actual Schema class
   #
@@ -226,6 +261,10 @@ class CIMI::Model::Schema
     @attributes = []
   end
 
+  def collections
+    @attributes.select { |a| a.is_a?(Collection) }
+  end
+
   def convert(name, value)
     attr = @attributes.find { |a| a.name == name }
     raise "Unknown attribute #{name}" unless attr
@@ -303,11 +342,7 @@ class CIMI::Model::Schema
     end
 
     def collection(name, opts={})
-      text :count
-
-      array :operations do
-        scalar :rel, :href
-      end
+      add_attributes!([name, opts], Collection)
     end
   end
 
-- 
1.7.7.6


[PATCH 2/7] CIMI (Model::Base): make generated attr methods go through the [] methods

Posted by lu...@redhat.com.
From: David Lutterkort <lu...@redhat.com>

---
 server/lib/cimi/models/base.rb |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/server/lib/cimi/models/base.rb b/server/lib/cimi/models/base.rb
index bb4a055..4c9b2dc 100644
--- a/server/lib/cimi/models/base.rb
+++ b/server/lib/cimi/models/base.rb
@@ -143,8 +143,8 @@ class CIMI::Model::Base
         base_schema.add_attributes!(names, attr_klass, &block)
       end
       names.each do |name|
-        define_method(name) { @attribute_values[name] }
-        define_method(:"#{name}=") { |newval| @attribute_values[name] = newval }
+        define_method(name) { self[name] }
+        define_method(:"#{name}=") { |newval| self[name] = newval }
       end
     end
 
-- 
1.7.7.6


Re: RFC: embedded CIMI collections

Posted by Michal Fojtik <mi...@mifo.sk>.
On Oct 6, 2012, at 2:52 AM, lutter@redhat.com wrote:

ACK. I rebased the $expand patches and make them work with this
collections. 

  -- Michal

> 
> These series of patches adds support for embedded collections for CIMI
> models. It's not quite perfect yet, since it doesn't produce the exactly
> right XML yet, nor is it possible to parse objects with embedded
> collections.
> 
> The main reason I like this better than the way Michal did it is because it
> makes it unnecessary to have XXXCollection classes for
> collections. Instead, you can just write
> 
>  collection :things, :class => CIMI::Model::Thing
> 
> For example, for the disks collection in machine, we simply have
> 
>  class CIMI::Model::Machine < CIMI::Model::Base
>    ...
>    collection :disks, :class => CIMI::Model::Disk
>    ...
>  end
> 
> The interesting stuff are the last three patches in the series. The other
> ones can probably be acked and committed as they are.
> 
> David


[PATCH 4/7] CIMI::Model::Base: remove unused methods acts_as_root_entity and all

Posted by lu...@redhat.com.
From: David Lutterkort <lu...@redhat.com>

---
 server/lib/cimi/models/base.rb |   11 -----------
 1 files changed, 0 insertions(+), 11 deletions(-)

diff --git a/server/lib/cimi/models/base.rb b/server/lib/cimi/models/base.rb
index eefa868..2a27a8f 100644
--- a/server/lib/cimi/models/base.rb
+++ b/server/lib/cimi/models/base.rb
@@ -235,17 +235,6 @@ class CIMI::Model::Base
 
   hash :property
 
-  def self.acts_as_root_entity(name=nil)
-    if name
-      name = name.to_s.camelize.pluralize
-    else
-      name = xml_tag_name.pluralize.uncapitalize
-    end
-    CIMI::Model.register_as_root_entity! name
-  end
-
-  def self.all(_self); find(:all, _self); end
-
   def filter_by(filter_opts)
     return self if filter_opts.nil?
     return filter_attributes(filter_opts.split(',').map{ |a| a.intern }) if filter_opts.include? ','
-- 
1.7.7.6


[PATCH 1/7] CIMI::Model::Collection: fix typo in entries method

Posted by lu...@redhat.com.
From: David Lutterkort <lu...@redhat.com>

---
 server/lib/cimi/models/collection.rb |    3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/server/lib/cimi/models/collection.rb b/server/lib/cimi/models/collection.rb
index 47c92f2..cae5e69 100644
--- a/server/lib/cimi/models/collection.rb
+++ b/server/lib/cimi/models/collection.rb
@@ -31,7 +31,8 @@ module CIMI::Model
     end
 
     def entries
-      self[entry_name]
+      self[self.class.entry_name]
+    end
     end
 
     def [](a)
-- 
1.7.7.6


[PATCH 6/7] CIMI: call a 'prepare' method on models before serializing

Posted by lu...@redhat.com.
From: David Lutterkort <lu...@redhat.com>

This gives us an opportunity to
  * set the count of collections to the number of entries
  * generate id's for collections embedded in other objects
---
 server/lib/cimi/models/base.rb       |    6 ++++++
 server/lib/cimi/models/collection.rb |    6 ++++++
 server/lib/cimi/models/schema.rb     |    4 ++++
 3 files changed, 16 insertions(+), 0 deletions(-)

diff --git a/server/lib/cimi/models/base.rb b/server/lib/cimi/models/base.rb
index 2e66694..d238135 100644
--- a/server/lib/cimi/models/base.rb
+++ b/server/lib/cimi/models/base.rb
@@ -166,6 +166,12 @@ class CIMI::Model::Base
   def []=(a, v)
     @attribute_values[a] = self.class.schema.convert(a, v)
   end
+
+  # Prepare to serialize
+  def prepare
+    self.class.schema.collections.map { |coll| coll.name }.each do |n|
+      self[n].id = "#{self.id}/#{n}"
+    end
   end
 
   #
diff --git a/server/lib/cimi/models/collection.rb b/server/lib/cimi/models/collection.rb
index cae5e69..f56efc5 100644
--- a/server/lib/cimi/models/collection.rb
+++ b/server/lib/cimi/models/collection.rb
@@ -27,12 +27,18 @@ module CIMI::Model
       if values[:entries]
         values[self.class.entry_name] = values.delete(:entries)
       end
+      values[self.class.entry_name] ||= []
       super(values)
     end
 
     def entries
       self[self.class.entry_name]
     end
+
+    # Prepare to serialize
+    def prepare
+      self.count = self.entries.size
+      self.count = nil if self.count == 0
     end
 
     def [](a)
diff --git a/server/lib/cimi/models/schema.rb b/server/lib/cimi/models/schema.rb
index d8ba13b..a8f76f9 100644
--- a/server/lib/cimi/models/schema.rb
+++ b/server/lib/cimi/models/schema.rb
@@ -234,10 +234,12 @@ class CIMI::Model::Schema
     end
 
     def to_xml(model, xml)
+      model[name].prepare
       xml[xml_name] = @collection_class.schema.to_xml(model[name])
     end
 
     def to_json(model, json)
+      model[name].prepare
       json[json_name] = @collection_class.schema.to_json(model[name])
     end
 
@@ -286,6 +288,7 @@ class CIMI::Model::Schema
   def to_xml(model, xml = nil)
     xml ||= OrderedHash.new
     @attributes.freeze
+    model.prepare if model.respond_to?(:prepare)
     @attributes.each { |attr| attr.to_xml(model, xml) }
     xml
   end
@@ -301,6 +304,7 @@ class CIMI::Model::Schema
 
   def to_json(model, json = {})
     @attributes.freeze
+    model.prepare if model.respond_to?(:prepare)
     @attributes.each { |attr| attr.to_json(model, json) }
     json
   end
-- 
1.7.7.6


[PATCH 7/7] CIMI: use embedded collection for Machine.disks and Machine.volumes

Posted by lu...@redhat.com.
From: David Lutterkort <lu...@redhat.com>

---
 server/lib/cimi/models.rb                          |    2 -
 server/lib/cimi/models/disk_collection.rb          |   37 --------------------
 server/lib/cimi/models/machine.rb                  |   13 +++----
 .../lib/cimi/models/machine_volume_collection.rb   |   34 ------------------
 4 files changed, 5 insertions(+), 81 deletions(-)
 delete mode 100644 server/lib/cimi/models/disk_collection.rb
 delete mode 100644 server/lib/cimi/models/machine_volume_collection.rb

diff --git a/server/lib/cimi/models.rb b/server/lib/cimi/models.rb
index df328f5..1eae2c9 100644
--- a/server/lib/cimi/models.rb
+++ b/server/lib/cimi/models.rb
@@ -25,9 +25,7 @@ require_relative './models/collection'
 require_relative './models/errors'
 require_relative './models/action'
 require_relative './models/disk'
-require_relative './models/disk_collection'
 require_relative './models/machine_volume'
-require_relative './models/machine_volume_collection'
 
 # Toplevel entities; order matters as it determines the order
 # in which the entities appear in the CEP
diff --git a/server/lib/cimi/models/disk_collection.rb b/server/lib/cimi/models/disk_collection.rb
deleted file mode 100644
index 7dbff39..0000000
--- a/server/lib/cimi/models/disk_collection.rb
+++ /dev/null
@@ -1,37 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-class CIMI::Model::DiskCollection < CIMI::Model::Base
-  text :count
-
-  #add disks array:
-  self << CIMI::Model::Disk
-
-  array :operations do
-    scalar :rel, :href
-  end
-
-  def self.default(instance_id, context)
-    instance = context.driver.instance(context.credentials, :id=>instance_id)
-    machine_conf = CIMI::Model::MachineConfiguration.find(instance.instance_profile.name, context)
-    disks = CIMI::Model::Disk.find(instance, machine_conf, context, :all)
-    self.new(
-      :id => context.machine_url(instance_id)+"/disks",
-      :description => "DiskCollection for Machine #{instance_id}",
-      :created => instance.launch_time,
-      :count => disks.size,
-      :disks => disks
-    )
-  end
-end
diff --git a/server/lib/cimi/models/machine.rb b/server/lib/cimi/models/machine.rb
index c605d2a..a15fa81 100644
--- a/server/lib/cimi/models/machine.rb
+++ b/server/lib/cimi/models/machine.rb
@@ -24,11 +24,8 @@ class CIMI::Model::Machine < CIMI::Model::Base
 
   href :event_log
 
-  href :disks
-
-  href :volumes
-
-  href :network_interfaces
+  collection :disks, :class => CIMI::Model::Disk
+  collection :volumes, :class => CIMI::Model::MachineVolume
 
   array :meters do
     scalar :href
@@ -118,6 +115,7 @@ class CIMI::Model::Machine < CIMI::Model::Base
   private
   def self.from_instance(instance, context)
     cpu =  memory = (instance.instance_profile.id == "opaque")? "n/a" : nil
+    machine_conf = CIMI::Model::MachineConfiguration.find(instance.instance_profile.name, context)
     self.new(
       :name => instance.id,
       :description => instance.name,
@@ -126,10 +124,9 @@ class CIMI::Model::Machine < CIMI::Model::Base
       :state => convert_instance_state(instance.state),
       :cpu => cpu || convert_instance_cpu(instance.instance_profile, context),
       :memory => memory || convert_instance_memory(instance.instance_profile, context),
-      :disks => {:href => context.machine_url(instance.id)+"/disks"},
-      :network_interfaces => {:href => context.machine_url(instance.id+"/network_interfaces")},
+      :disks => CIMI::Model::Disk.find(instance, machine_conf, context, :all),
       :operations => convert_instance_actions(instance, context),
-      :volumes=>{:href=>context.machine_url(instance.id)+"/volumes"},
+      :volumes => CIMI::Model::MachineVolume.find(instance.id, context, :all),
       :property => convert_instance_properties(instance, context)
     )
   end
diff --git a/server/lib/cimi/models/machine_volume_collection.rb b/server/lib/cimi/models/machine_volume_collection.rb
deleted file mode 100644
index b9dfcad..0000000
--- a/server/lib/cimi/models/machine_volume_collection.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-class CIMI::Model::MachineVolumeCollection < CIMI::Model::Base
-
-  text :count
-
-  self << CIMI::Model::MachineVolume
-
-  array :operations do
-    scalar :rel, :href
-  end
-
-  def self.default(instance_id, context)
-    volumes = CIMI::Model::MachineVolume.find(instance_id, context)
-    self.new(
-      :id => context.machine_url(instance_id)+"/volumes",
-      :description => "MachineVolumeCollection for Machine #{instance_id}",
-      :count => volumes.size,
-      :machine_volumes => volumes
-    )
-  end
-end
-- 
1.7.7.6