You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@deltacloud.apache.org by ma...@redhat.com on 2011/12/08 15:24:48 UTC

CIMI::EntityMetadata

EntityMetadata allows for:

 "Consumers to discover the metadata associated with each supported entity.
  Doing so allows for the discovery of Provider defined constraints on the 
  CIMI defined attributes as well as discovery of any new extension attributes 
  that the Provider may have defined."

right now I'm just mapping deltacloud features to CIMI EntityMetadata - for example
to signal that a Machine will not accept a consumer defined name as this is set
by the provider (EC2 is one case). I think this mechanism can be useful for getting
around the particularities of individual providers - we can add to it as issues
arise,

marios

[PATCH 2/4] Adds create_entity_metadata to CIMI::Machine model (+typos in xml parsing)

Posted by ma...@redhat.com.
From: marios <ma...@redhat.com>


Signed-off-by: marios <ma...@redhat.com>
---
 server/lib/cimi/model/machine.rb |   28 +++++++++++++++++++---------
 1 files changed, 19 insertions(+), 9 deletions(-)

diff --git a/server/lib/cimi/model/machine.rb b/server/lib/cimi/model/machine.rb
index 4f28ea8..8f31bc6 100644
--- a/server/lib/cimi/model/machine.rb
+++ b/server/lib/cimi/model/machine.rb
@@ -70,20 +70,20 @@ class CIMI::Model::Machine < CIMI::Model::Base
 
   def self.create_from_json(body, context)
     json = JSON.parse(body)
-    hardware_profile_id = xml['MachineTemplate']['MachineConfig']["href"].split('/').last
-    image_id = xml['MachineTemplate']['MachineImage']["href"].split('/').last
+    hardware_profile_id = xml['machineTemplate']['machineConfig']["href"].split('/').last
+    image_id = xml['machineTemplate']['machineImage']["href"].split('/').last
     instance = context.create_instance(context.credentials, image_id, { :hwp_id => hardware_profile_id })
     from_instance(instance, context)
   end
 
   def self.create_from_xml(body, context)
     xml = XmlSimple.xml_in(body)
-    machine_template = xml['MachineTemplate'][0]
-    hardware_profile_id = machine_template['MachineConfig'][0]["href"].split('/').last
-    image_id = machine_template['MachineImage'][0]["href"].split('/').last
+    machine_template = xml['machineTemplate'][0]
+    hardware_profile_id = machine_template['machineConfig'][0]["href"].split('/').last
+    image_id = machine_template['machineImage'][0]["href"].split('/').last
     additional_params = {}
     if machine_template.has_key? 'MachineAdmin'
-      additional_params[:keyname] = machine_template['MachineAdmin'][0]["href"].split('/').last
+      additional_params[:keyname] = machine_template['machineAdmin'][0]["href"].split('/').last
     end
     instance = context.driver.create_instance(context.credentials, image_id, { 
       :hwp_id => hardware_profile_id
@@ -107,6 +107,16 @@ class CIMI::Model::Machine < CIMI::Model::Base
     context.driver.destroy_instance(context.credentials, id)
   end
 
+  def self.create_entity_metadata(context)
+    cimi_entity = self.name.split("::").last
+    metadata = EntityMetadata.metadata_from_deltacloud_features(cimi_entity, :instances, context)
+    unless metadata.includes_attribute?(:name)
+      metadata.attributes << {:name=>"name", :required=>"false",
+                   :constraints=>"Determined by the cloud provider", :type=>"xs:string"}
+    end
+    metadata
+  end
+
   private
 
   def self.from_instance(instance, context)
@@ -163,11 +173,11 @@ class CIMI::Model::Machine < CIMI::Model::Base
     machine_conf = MachineConfiguration.find(profile.name, context)
     storage_override = profile.overrides.find { |p, v| p == :storage }
     [
-      { :capacity => { 
+      { :capacity => {
           :quantity => storage_override.nil? ? machine_conf.disks.first[:capacity][:quantity] : storage_override[1],
           :units => machine_conf.disks.first[:capacity][:units]
-        } 
-      } 
+        }
+      }
     ]
   end
 
-- 
1.7.6.4


Re: [PATCH 1/4] Adds CIMI::EntityMetadata model

Posted by Michal Fojtik <mi...@mifo.sk>.
On Dec 8, 2011, at 3:24 PM, marios@redhat.com wrote:

ACK. Very minor styling bugs/suggestions inline.
Also pls consider the Collection entity for EntityMetadata before push.

 -- Michal


> From: marios <ma...@redhat.com>
> 
> 
> Signed-off-by: marios <ma...@redhat.com>
> ---
> server/lib/cimi/model.rb                 |    1 +
> server/lib/cimi/model/entity_metadata.rb |   85 ++++++++++++++++++++++++++++++
> server/lib/cimi/server.rb                |   30 ++++++++++-
> 3 files changed, 115 insertions(+), 1 deletions(-)
> create mode 100644 server/lib/cimi/model/entity_metadata.rb
> 
> diff --git a/server/lib/cimi/model.rb b/server/lib/cimi/model.rb
> index 79645b2..76c0b15 100644
> --- a/server/lib/cimi/model.rb
> +++ b/server/lib/cimi/model.rb
> @@ -43,3 +43,4 @@ require 'cimi/model/machine_admin_collection'
> require 'cimi/model/volume_configuration_collection'
> require 'cimi/model/volume_image_collection'
> require 'cimi/model/volume_template_collection'
> +require 'cimi/model/entity_metadata'
> diff --git a/server/lib/cimi/model/entity_metadata.rb b/server/lib/cimi/model/entity_metadata.rb
> new file mode 100644
> index 0000000..eca2443
> --- /dev/null
> +++ b/server/lib/cimi/model/entity_metadata.rb
> @@ -0,0 +1,85 @@
> +# 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::EntityMetadata < CIMI::Model::Base
> +
> +text :type_uri
> +
> +  array :attributes do
> +    scalar :name
> +    scalar :namespace
> +    scalar :type
> +    scalar :required
> +    scalar :constraints
> +  end
> +
> +  array :operations do
> +    scalar :name
> +    scalar :uri
> +    scalar :description
> +    scalar :method
> +    scalar :input_message
> +    scalar :output_message
> +  end
> +
> +  def self.find(id, context)
> +    entity_metadata = []
> +    if id == :all
> +      CIMI::Model.root_entities.each do |entity|
> +        entity_class = Object::const_get("CIMI").const_get("Model").const_get("#{entity.singularize}")

You can also do "CIMI::Model.const_get(entity.singularize)" here.

> +        entity_metadata << entity_class.create_entity_metadata(context) if entity_class.respond_to?("create_entity_metadata")
> +      end
> +      return entity_metadata
> +    else
> +      entity_class = Object::const_get("CIMI").const_get("Model").const_get("#{id.camelize}")
> +      entity_metadata << entity_class.create_entity_metadata(context) if entity_class.respond_to?("create_entity_metadata")
> +      return entity_metadata.first
> +    end
> +  end
> +
> +  def self.metadata_from_deltacloud_features(cimi_entity, dcloud_entity, context)
> +      metadata_attributes = []
> +      deltacloud_features = context.driver.features(dcloud_entity)
> +      deltacloud_features.each do |feature|
> +        metadata_attributes << attributes_from_feature(feature)
> +      end

You can avoid initializing empty Array by:

metadata_attributes = deltacloud_features.map { |f| attributes_from_feature(f) }

> +      from_feature(cimi_entity, context, metadata_attributes)
> +  end
> +
> +  def includes_attribute?(attribute)
> +    self.attributes.each do |attr|
> +      return true if attr[:name] == attribute
> +    end
> +    return false
> +  end

This method can be replaced by:

attributes.any? { |a| a[:name] == attribute }

> +  private
> +
> +  def self.attributes_from_feature(feature)
> +    { :name=>(feature.name == :user_name ? :name : feature.name),
> +      :type=> "xs:string",
> +      :required=>(feature.operations.first.params[feature.name].type == :optional ? "false" : "true"),
> +      :constraints=> (feature.constraints.empty? ? (feature.description.nil? ? "" : feature.description): feature.constraints)
> +    }
> +  end
> +
> +  def self.from_feature(cimi_entity, context, metadata_attributes)
> +    self.new(:name => cimi_entity, :uri=>"#{context.entity_metadata_url}/#{cimi_entity.underscore}",
> +            :type_uri=> context.send("#{cimi_entity.pluralize.underscore}_url"),
> +            :attributes => metadata_attributes   )
> +  end
> +
> +end
> diff --git a/server/lib/cimi/server.rb b/server/lib/cimi/server.rb
> index 746587c..305d95f 100644
> --- a/server/lib/cimi/server.rb
> +++ b/server/lib/cimi/server.rb
> @@ -75,7 +75,6 @@ end
> 
> global_collection  :cloudEntryPoint do
>   description 'Cloud entry point'
> -
>   operation :index do
>     description "list all resources of the cloud"
>     control do
> @@ -420,4 +419,33 @@ global_collection :volume_images do
> 
> end
> 
> +
> +global_collection :entity_metadata do
> +  description 'This allows for the discovery of Provider defined constraints on the CIMI defined attributes as well as discovery of any new extension attributes that the Provider may have defined.'
> +
> +  operation :index do
> +    description "List all entity metadata defined for this provider"
> +    control do
> +      entity_metadata = EntityMetadata.all(self)
> +      respond_to do |format|
> +        format.xml{entity_metadata.to_xml_cimi_collection(self)}
> +        format.json{entity_metadata.to_json_cimi_collection(self)}

Could you please create EntityMetadataCollection entity and then use:

EntityMetadataCollection.default(self) ?

 

> +      end
> +    end
> +  end
> +
> +  operation :show do
> +    description "Get the entity metadata for a specific collection"
> +    param :id, :required, :string
> +    control do
> +      entity_metadata = EntityMetadata.find(params[:id], self)
> +      respond_to do |format|
> +        format.xml{entity_metadata.to_xml}
> +        format.json{entity_metadata.to_json}
> +      end
> +    end
> +  end
> +
> +end
> +
> end
> -- 
> 1.7.6.4
> 


[PATCH 1/4] Adds CIMI::EntityMetadata model

Posted by ma...@redhat.com.
From: marios <ma...@redhat.com>


Signed-off-by: marios <ma...@redhat.com>
---
 server/lib/cimi/model.rb                 |    1 +
 server/lib/cimi/model/entity_metadata.rb |   85 ++++++++++++++++++++++++++++++
 server/lib/cimi/server.rb                |   30 ++++++++++-
 3 files changed, 115 insertions(+), 1 deletions(-)
 create mode 100644 server/lib/cimi/model/entity_metadata.rb

diff --git a/server/lib/cimi/model.rb b/server/lib/cimi/model.rb
index 79645b2..76c0b15 100644
--- a/server/lib/cimi/model.rb
+++ b/server/lib/cimi/model.rb
@@ -43,3 +43,4 @@ require 'cimi/model/machine_admin_collection'
 require 'cimi/model/volume_configuration_collection'
 require 'cimi/model/volume_image_collection'
 require 'cimi/model/volume_template_collection'
+require 'cimi/model/entity_metadata'
diff --git a/server/lib/cimi/model/entity_metadata.rb b/server/lib/cimi/model/entity_metadata.rb
new file mode 100644
index 0000000..eca2443
--- /dev/null
+++ b/server/lib/cimi/model/entity_metadata.rb
@@ -0,0 +1,85 @@
+# 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::EntityMetadata < CIMI::Model::Base
+
+text :type_uri
+
+  array :attributes do
+    scalar :name
+    scalar :namespace
+    scalar :type
+    scalar :required
+    scalar :constraints
+  end
+
+  array :operations do
+    scalar :name
+    scalar :uri
+    scalar :description
+    scalar :method
+    scalar :input_message
+    scalar :output_message
+  end
+
+  def self.find(id, context)
+    entity_metadata = []
+    if id == :all
+      CIMI::Model.root_entities.each do |entity|
+        entity_class = Object::const_get("CIMI").const_get("Model").const_get("#{entity.singularize}")
+        entity_metadata << entity_class.create_entity_metadata(context) if entity_class.respond_to?("create_entity_metadata")
+      end
+      return entity_metadata
+    else
+      entity_class = Object::const_get("CIMI").const_get("Model").const_get("#{id.camelize}")
+      entity_metadata << entity_class.create_entity_metadata(context) if entity_class.respond_to?("create_entity_metadata")
+      return entity_metadata.first
+    end
+  end
+
+  def self.metadata_from_deltacloud_features(cimi_entity, dcloud_entity, context)
+      metadata_attributes = []
+      deltacloud_features = context.driver.features(dcloud_entity)
+      deltacloud_features.each do |feature|
+        metadata_attributes << attributes_from_feature(feature)
+      end
+      from_feature(cimi_entity, context, metadata_attributes)
+  end
+
+  def includes_attribute?(attribute)
+    self.attributes.each do |attr|
+      return true if attr[:name] == attribute
+    end
+    return false
+  end
+
+  private
+
+  def self.attributes_from_feature(feature)
+    { :name=>(feature.name == :user_name ? :name : feature.name),
+      :type=> "xs:string",
+      :required=>(feature.operations.first.params[feature.name].type == :optional ? "false" : "true"),
+      :constraints=> (feature.constraints.empty? ? (feature.description.nil? ? "" : feature.description): feature.constraints)
+    }
+  end
+
+  def self.from_feature(cimi_entity, context, metadata_attributes)
+    self.new(:name => cimi_entity, :uri=>"#{context.entity_metadata_url}/#{cimi_entity.underscore}",
+            :type_uri=> context.send("#{cimi_entity.pluralize.underscore}_url"),
+            :attributes => metadata_attributes   )
+  end
+
+end
diff --git a/server/lib/cimi/server.rb b/server/lib/cimi/server.rb
index 746587c..305d95f 100644
--- a/server/lib/cimi/server.rb
+++ b/server/lib/cimi/server.rb
@@ -75,7 +75,6 @@ end
 
 global_collection  :cloudEntryPoint do
   description 'Cloud entry point'
-
   operation :index do
     description "list all resources of the cloud"
     control do
@@ -420,4 +419,33 @@ global_collection :volume_images do
 
 end
 
+
+global_collection :entity_metadata do
+  description 'This allows for the discovery of Provider defined constraints on the CIMI defined attributes as well as discovery of any new extension attributes that the Provider may have defined.'
+
+  operation :index do
+    description "List all entity metadata defined for this provider"
+    control do
+      entity_metadata = EntityMetadata.all(self)
+      respond_to do |format|
+        format.xml{entity_metadata.to_xml_cimi_collection(self)}
+        format.json{entity_metadata.to_json_cimi_collection(self)}
+      end
+    end
+  end
+
+  operation :show do
+    description "Get the entity metadata for a specific collection"
+    param :id, :required, :string
+    control do
+      entity_metadata = EntityMetadata.find(params[:id], self)
+      respond_to do |format|
+        format.xml{entity_metadata.to_xml}
+        format.json{entity_metadata.to_json}
+      end
+    end
+  end
+
+end
+
 end
-- 
1.7.6.4


[PATCH 4/4] Adds exception to String::pluralize for 'data' ("metadata".pluralize != "metadatas")

Posted by ma...@redhat.com.
From: marios <ma...@redhat.com>


Signed-off-by: marios <ma...@redhat.com>
---
 server/lib/deltacloud/core_ext/string.rb |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)

diff --git a/server/lib/deltacloud/core_ext/string.rb b/server/lib/deltacloud/core_ext/string.rb
index de56c99..b3e2dbe 100644
--- a/server/lib/deltacloud/core_ext/string.rb
+++ b/server/lib/deltacloud/core_ext/string.rb
@@ -35,6 +35,7 @@ class String
   def pluralize
     return self + 'es' if self =~ /ess$/
     return self[0, self.length-1] + "ies" if self =~ /ty$/
+    return self if self =~ /data$/
     self + "s"
   end
 
-- 
1.7.6.4


[PATCH 3/4] Adds CIMI::EntityMetadata to the CIMI::CloudEntryPoint

Posted by ma...@redhat.com.
From: marios <ma...@redhat.com>


Signed-off-by: marios <ma...@redhat.com>
---
 server/lib/cimi/model/cloud_entry_point.rb |   11 ++++++++++-
 1 files changed, 10 insertions(+), 1 deletions(-)

diff --git a/server/lib/cimi/model/cloud_entry_point.rb b/server/lib/cimi/model/cloud_entry_point.rb
index 62a91b6..e7464f0 100644
--- a/server/lib/cimi/model/cloud_entry_point.rb
+++ b/server/lib/cimi/model/cloud_entry_point.rb
@@ -15,6 +15,10 @@
 
 class CIMI::Model::CloudEntryPoint < CIMI::Model::Base
 
+array :entity_metadata do
+  scalar :href
+end
+
   def self.create(context)
     root_entities = CIMI::Model.root_entities.inject({}) do |result, entity|
       if context.respond_to? :"#{entity.underscore}_url"
@@ -22,11 +26,16 @@ class CIMI::Model::CloudEntryPoint < CIMI::Model::Base
       end
       result
     end
+    entity_metadata = EntityMetadata.all(context)
+    root_entity_meta = [] ; entity_metadata.each do |m|
+      root_entity_meta << {:href=>m.uri}
+    end
     root_entities.merge!({
       :name => context.driver.name,
       :description => "Cloud Entry Point for the Deltacloud #{context.driver.name} driver",
       :uri => context.cloudEntryPoint_url,
-      :created => Time.now
+      :created => Time.now,
+      :entity_metadata => root_entity_meta
     })
     self.new(root_entities)
   end
-- 
1.7.6.4