You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@deltacloud.apache.org by mf...@redhat.com on 2013/01/16 12:58:25 UTC

Replace datamapper with sequel (revision 2)

Hi,

This is a bit enhanced version of my previous patch set.
Additions/fixes:

- Added unit tests for database helper/schema (using in-memory sqlite)
- Added validation for entities (MachineTemplate, etc)
- Fixed false sqlite errors in console when launching with -V (verbose)
- Fixed wrong serialization for XML/JSON properties
- Fixed bug when creating new entity

Tracker: http://tracker.deltacloud.org/set/252

Cheers,

  -- Michal


[PATCH core 7/8] Added validation to database models

Posted by mf...@redhat.com.
From: Michal Fojtik <mf...@redhat.com>


Signed-off-by: Michal fojtik <mf...@redhat.com>
---
 server/lib/db.rb                      | 7 +++++--
 server/lib/db/address_template.rb     | 7 +++++++
 server/lib/db/machine_template.rb     | 2 ++
 server/lib/db/volume_configuration.rb | 2 ++
 server/lib/db/volume_template.rb      | 2 ++
 5 files changed, 18 insertions(+), 2 deletions(-)

diff --git a/server/lib/db.rb b/server/lib/db.rb
index c441021..6dc32c3 100644
--- a/server/lib/db.rb
+++ b/server/lib/db.rb
@@ -4,8 +4,11 @@ module Deltacloud
     ENV['RACK_ENV'] == 'test'
   end
 
-  require 'sequel' unless test_environment?
-  require 'logger'
+  unless test_environment?
+    require 'sequel'
+    require 'logger'
+    Sequel::Model.plugin :validation_class_methods
+  end
 
   DATABASE_LOCATION = ENV['DATABASE_LOCATION'] ||
     'sqlite://'+File.join('/', 'var', 'tmp', "deltacloud-mock-#{ENV['USER']}", 'db.sqlite')
diff --git a/server/lib/db/address_template.rb b/server/lib/db/address_template.rb
index 8586255..55771d1 100644
--- a/server/lib/db/address_template.rb
+++ b/server/lib/db/address_template.rb
@@ -2,6 +2,13 @@ module Deltacloud
   module Database
 
     class AddressTemplate < Entity
+      validates_presence_of :ip
+      validates_presence_of :hostname
+      validates_presence_of :allocation
+      validates_presence_of :default_gateway
+      validates_presence_of :dns
+      validates_presence_of :protocol
+      validates_presence_of :mask
     end
 
   end
diff --git a/server/lib/db/machine_template.rb b/server/lib/db/machine_template.rb
index 1b34161..61f57c1 100644
--- a/server/lib/db/machine_template.rb
+++ b/server/lib/db/machine_template.rb
@@ -2,6 +2,8 @@ module Deltacloud
   module Database
 
     class MachineTemplate < Entity
+      validates_presence_of :machine_config
+      validates_presence_of :machine_image
     end
 
   end
diff --git a/server/lib/db/volume_configuration.rb b/server/lib/db/volume_configuration.rb
index aa956ce..ebf59c2 100644
--- a/server/lib/db/volume_configuration.rb
+++ b/server/lib/db/volume_configuration.rb
@@ -2,6 +2,8 @@ module Deltacloud
   module Database
 
     class VolumeConfiguration < Entity
+      validates_presence_of :format
+      validates_presence_of :capacity
     end
 
   end
diff --git a/server/lib/db/volume_template.rb b/server/lib/db/volume_template.rb
index 0d876bf..8a4953a 100644
--- a/server/lib/db/volume_template.rb
+++ b/server/lib/db/volume_template.rb
@@ -2,6 +2,8 @@ module Deltacloud
   module Database
 
     class VolumeTemplate < Entity
+      validates_presence_of :volume_config
+      validates_presence_of :volume_Image
     end
 
   end
-- 
1.8.0.2


[PATCH core 5/8] CIMI: Moved database initialization to models.rb

Posted by mf...@redhat.com.
From: Michal Fojtik <mf...@redhat.com>

This will allow proper testing of database

Signed-off-by: Michal fojtik <mf...@redhat.com>
---
 server/lib/cimi/models.rb | 13 +++++++++++++
 server/lib/cimi/server.rb |  2 --
 server/lib/db.rb          | 12 +-----------
 3 files changed, 14 insertions(+), 13 deletions(-)

diff --git a/server/lib/cimi/models.rb b/server/lib/cimi/models.rb
index 09c9552..356f5a7 100644
--- a/server/lib/cimi/models.rb
+++ b/server/lib/cimi/models.rb
@@ -18,6 +18,17 @@ module CIMI
 end
 
 require 'require_relative' if RUBY_VERSION < '1.9'
+require_relative '../db'
+
+unless Deltacloud.test_environment?
+  Deltacloud::initialize_database
+  require_relative './../db/provider'
+  require_relative './../db/entity'
+  require_relative './../db/machine_template'
+  require_relative './../db/address_template'
+  require_relative './../db/volume_configuration'
+  require_relative './../db/volume_template'
+end
 
 require_relative './models/schema'
 require_relative './models/base'
@@ -29,7 +40,9 @@ require_relative './models/disk'
 
 require_relative './models/resource_metadata'
 require_relative './models/cloud_entry_point'
+
 CIMI::Model::ResourceMetadata.acts_as_root_entity
+
 require_relative './models/volume'
 require_relative './models/volume_template'
 require_relative './models/volume_configuration'
diff --git a/server/lib/cimi/server.rb b/server/lib/cimi/server.rb
index 41c8bd6..d23b949 100644
--- a/server/lib/cimi/server.rb
+++ b/server/lib/cimi/server.rb
@@ -20,8 +20,6 @@ require 'sinatra/base'
 require 'sinatra/rabbit'
 require_relative '../sinatra'
 
-require_relative '../db'
-
 require_relative './helpers'
 require_relative './collections'
 
diff --git a/server/lib/db.rb b/server/lib/db.rb
index 49e6f33..c441021 100644
--- a/server/lib/db.rb
+++ b/server/lib/db.rb
@@ -1,7 +1,7 @@
 module Deltacloud
 
   def self.test_environment?
-    ENV['RACK_ENV'] == 'test' || ENV['DELTACLOUD_NO_DATABASE']
+    ENV['RACK_ENV'] == 'test'
   end
 
   require 'sequel' unless test_environment?
@@ -72,13 +72,3 @@ module Deltacloud
   end
 
 end
-
-unless Deltacloud.test_environment?
-  Deltacloud::initialize_database
-  require_relative './db/provider'
-  require_relative './db/entity'
-  require_relative './db/machine_template'
-  require_relative './db/address_template'
-  require_relative './db/volume_configuration'
-  require_relative './db/volume_template'
-end
-- 
1.8.0.2


[PATCH core 1/8] CIMI: Replaced DataMapper with Sequel ORM

Posted by mf...@redhat.com.
From: Michal Fojtik <mf...@redhat.com>


Signed-off-by: Michal fojtik <mf...@redhat.com>
---
 server/deltacloud-core.gemspec             |  5 +-
 server/lib/cimi/helpers/database_helper.rb | 19 +++++--
 server/lib/db.rb                           | 81 +++++++++++++++++++++++-------
 3 files changed, 80 insertions(+), 25 deletions(-)

diff --git a/server/deltacloud-core.gemspec b/server/deltacloud-core.gemspec
index 7fad5be..977cc26 100644
--- a/server/deltacloud-core.gemspec
+++ b/server/deltacloud-core.gemspec
@@ -78,9 +78,8 @@ Gem::Specification.new do |s|
   s.add_dependency('nokogiri', '>= 1.4.3')
   s.add_dependency('require_relative') if RUBY_VERSION < '1.9'
 
-  s.add_dependency('data_mapper')
-  s.add_dependency('dm-sqlite-adapter')
-  s.add_dependency('dm-timestamps')
+  s.add_dependency('sequel', '<= 3.42.0')
+  s.add_dependency('sqlite3')
 
   # dependencies for various cloud providers:
 
diff --git a/server/lib/cimi/helpers/database_helper.rb b/server/lib/cimi/helpers/database_helper.rb
index ac6ae4f..d432f69 100644
--- a/server/lib/cimi/helpers/database_helper.rb
+++ b/server/lib/cimi/helpers/database_helper.rb
@@ -27,11 +27,14 @@ module Deltacloud
       def delete_attributes_for(model)
         return if test_environment?
         entity = get_entity(model)
-        !entity.nil? && entity.destroy!
+        !entity.nil? && entity.destroy
       end
 
       def get_entity(model)
-        Deltacloud::Database::Entity.first(:be_kind => model.to_entity, :be_id => model.id, 'provider.driver' => driver_symbol.to_s, 'provider.url' => current_provider)
+        current_db.entities_dataset.first(
+          :be_kind => model.to_entity,
+          :be_id => model.id,
+        )
       end
 
       def current_provider
@@ -43,23 +46,29 @@ module Deltacloud
       #
 
       def current_db
-        Deltacloud::Database::Provider.first_or_create(:driver => driver_symbol.to_s, :url => current_provider)
+        Deltacloud::Database::Provider.find_or_create(:driver => driver_symbol.to_s, :url => current_provider)
       end
 
       def store_attributes_for(model, attrs={})
         return if test_environment? or model.nil? or attrs.empty?
         return if model.id.nil?
-        entity = get_entity(model) || current_db.entities.new(:be_kind => model.to_entity, :be_id => model.id)
+
+        unless entity = get_entity(model)
+          entity = Deltacloud::Database::Entity.new(:provider_id => current_db.id)
+        end
 
         entity.description = extract_attribute_value('description', attrs) if attrs.has_key? 'description'
         entity.name = extract_attribute_value('name', attrs) if attrs.has_key? 'name'
+
         if attrs.has_key? 'properties'
           entity.ent_properties = extract_attribute_value('properties', attrs).to_json
         elsif attrs.has_key? 'property'
           entity.ent_properties = extract_attribute_value('property', attrs).to_json
         end
 
-        entity.save && entity
+        entity.exists? ? entity.save_changes : entity.save
+
+        entity
       end
 
       # In XML serialization the values stored in attrs are arrays, dues to
diff --git a/server/lib/db.rb b/server/lib/db.rb
index 567b356..64cc283 100644
--- a/server/lib/db.rb
+++ b/server/lib/db.rb
@@ -4,27 +4,74 @@ module Deltacloud
     ENV['RACK_ENV'] == 'test' || ENV['DELTACLOUD_NO_DATABASE']
   end
 
-  unless test_environment?
-    require 'data_mapper'
-    require_relative './db/provider'
-    require_relative './db/entity'
-    require_relative './db/machine_template'
-    require_relative './db/address_template'
-    require_relative './db/volume_configuration'
-    require_relative './db/volume_template'
-  end
+  require 'sequel' unless test_environment?
+  require 'logger'
+
+  DATABASE_LOCATION = ENV['DATABASE_LOCATION'] ||
+    'sqlite://'+File.join('/', 'var', 'tmp', "deltacloud-mock-#{ENV['USER']}", 'db.sqlite')
 
-  DATABASE_LOCATION = ENV['DATABASE_LOCATION'] || File.join('/', 'var', 'tmp', "deltacloud-mock-#{ENV['USER']}", 'db.sqlite')
+  def self.database(opts={})
+    opts[:logger] = ::Logger.new($stdout) if ENV['API_VERBOSE']
+    @db ||=  Sequel.connect(DATABASE_LOCATION, opts)
+  end
 
   def self.initialize_database
-    DataMapper::Logger.new($stdout, :debug) if ENV['API_VERBOSE']
-    dbdir = File::dirname(DATABASE_LOCATION)
-    FileUtils::mkdir(dbdir) unless File::directory?(dbdir)
-    DataMapper::setup(:default, "sqlite://#{DATABASE_LOCATION}")
-    DataMapper::finalize
-    DataMapper::auto_upgrade!
+
+    database.create_table?(:providers) {
+      primary_key :id
+
+      column :driver, :string, { :null => false }
+      column :url, :string
+      index [ :url, :driver ]
+    }
+
+    database.create_table?(:entities) {
+      primary_key :id
+      foreign_key :provider_id, :providers, { :index => true, :null => false }
+      column :created_at, :timestamp
+
+      # Base
+      column :model, :string, { :index => true, :null => false, :default => 'entity' }
+
+      # Map Entity to Deltacloud model
+      # (like: Machine => Instance)
+      column :be_kind, :string
+      column :be_id, :string
+
+      # Entity
+      column :name, :string
+      column :description, :string
+      column :ent_properties, :string, { :text => true }
+
+
+      column :machine_config, :string
+      column :machine_image, :string
+
+      column :network, :string
+      column :ip, :string
+      column :hostname, :string
+      column :allocation, :string
+      column :default_gateway, :string
+      column :dns, :string
+      column :protocol, :string
+      column :mask, :string
+
+      column :format, :string
+      column :capacity, :string
+
+      column :volume_config, :string
+      column :volume_image, :string
+    }
   end
 
 end
 
-Deltacloud::initialize_database unless Deltacloud.test_environment?
+unless Deltacloud.test_environment?
+  Deltacloud::initialize_database
+  require_relative './db/provider'
+  require_relative './db/entity'
+  require_relative './db/machine_template'
+  require_relative './db/address_template'
+  require_relative './db/volume_configuration'
+  require_relative './db/volume_template'
+end
-- 
1.8.0.2


[PATCH core 3/8] CIMI: Updated CIMI models to use Sequel methods and helpers

Posted by mf...@redhat.com.
From: Michal Fojtik <mf...@redhat.com>


Signed-off-by: Michal fojtik <mf...@redhat.com>
---
 server/lib/cimi/models/address_template.rb     | 25 ++++------------
 server/lib/cimi/models/machine.rb              |  2 +-
 server/lib/cimi/models/machine_template.rb     | 25 ++++------------
 server/lib/cimi/models/volume_configuration.rb | 25 ++++------------
 server/lib/cimi/models/volume_template.rb      | 40 ++++++++++----------------
 5 files changed, 34 insertions(+), 83 deletions(-)

diff --git a/server/lib/cimi/models/address_template.rb b/server/lib/cimi/models/address_template.rb
index 2d81f23..1e28602 100644
--- a/server/lib/cimi/models/address_template.rb
+++ b/server/lib/cimi/models/address_template.rb
@@ -42,20 +42,13 @@ class CIMI::Model::AddressTemplate < CIMI::Model::Base
       if context.driver.respond_to? :address_templates
         context.driver.address_templates(context.credentials, {:env=>context})
       else
-        Deltacloud::Database::AddressTemplate.all(
-          'provider.driver' => driver_symbol.to_s,
-          'provider.url' => current_provider
-        ).map { |t| from_db(t, context) }
+        current_db.address_teplates.map { |t| from_db(t, context) }
       end
     else
       if context.driver.respond_to? :address_template
         context.driver.address_template(context.credentials, id, :env=>context)
       else
-        template = Deltacloud::Database::AddressTemplate.first(
-          'provider.driver' => driver_symbol.to_s,
-          'provider.url' => current_provider,
-          :id => id
-        )
+        template = current_db.address_templates_dataset.first(:id => id)
         raise CIMI::Model::NotFound unless template
         from_db(template, context)
       end
@@ -64,7 +57,7 @@ class CIMI::Model::AddressTemplate < CIMI::Model::Base
 
   def self.create_from_json(body, context)
     json = JSON.parse(body)
-    new_template = current_db.address_templates.new(
+    new_template = current_db.add_address_template(
       :name => json['name'],
       :description => json['description'],
       :hostname => json['hostname'],
@@ -75,17 +68,14 @@ class CIMI::Model::AddressTemplate < CIMI::Model::Base
       :protocol => json['protocol'],
       :mask => json['mask'],
       :ent_properties => json['properties'].to_json,
-      :be_kind => 'address_template',
-      :be_id => ''
     )
-    new_template.save
     from_db(new_template, context)
   end
 
   def self.create_from_xml(body, context)
     xml = XmlSimple.xml_in(body)
     xml['property'] ||= []
-    new_template = current_db.address_templates.new(
+    new_template = current_db.add_address_template(
       :name => xml['name'].first,
       :description => xml['description'].first,
       :ip => xml['ip'].first,
@@ -95,11 +85,8 @@ class CIMI::Model::AddressTemplate < CIMI::Model::Base
       :dns => xml['dns'].first,
       :protocol => xml['protocol'].nil? ? nil : xml['protocol'].first,
       :mask => xml['mask'].first,
-      :ent_properties => xml['property'].inject({}) { |r, p| r[p['key']]=p['content']; r },
-      :be_kind => 'machine_template',
-      :be_id => ''
+      :ent_properties => JSON::dump(xml['property'].inject({}) { |r, p| r[p['key']]=p['content']; r }),
     )
-    new_template.save
     from_db(new_template, context)
   end
 
@@ -121,7 +108,7 @@ class CIMI::Model::AddressTemplate < CIMI::Model::Base
       :dns => model.dns,
       :protocol => model.protocol,
       :mask => model.mask,
-      :property => model.ent_properties,
+      :property => JSON::parse(model.ent_properties),
       :operations => [
         { :href => context.destroy_address_template_url(model.id), :rel => 'http://schemas.dmtf.org/cimi/1/action/delete' }
       ]
diff --git a/server/lib/cimi/models/machine.rb b/server/lib/cimi/models/machine.rb
index 7ac8f83..67e3eef 100644
--- a/server/lib/cimi/models/machine.rb
+++ b/server/lib/cimi/models/machine.rb
@@ -81,7 +81,7 @@ class CIMI::Model::Machine < CIMI::Model::Base
   def self.create_from_xml(body, context)
     xml = XmlSimple.xml_in(body)
     if xml['machineTemplate'][0]['href']
-      template = current_db.machine_templates.first(:id => xml['machineTemplate'][0]['href'].split('/').last)
+      template = current_db.machine_templates_dataset.first(:id => xml['machineTemplate'][0]['href'].split('/').last)
       hardware_profile_id = template.machine_config.split('/').last
       image_id = template.machine_image.split('/').last
     else
diff --git a/server/lib/cimi/models/machine_template.rb b/server/lib/cimi/models/machine_template.rb
index eb660d2..675f709 100644
--- a/server/lib/cimi/models/machine_template.rb
+++ b/server/lib/cimi/models/machine_template.rb
@@ -44,16 +44,9 @@ class CIMI::Model::MachineTemplate < CIMI::Model::Base
   class << self
     def find(id, context)
       if id == :all
-        Deltacloud::Database::MachineTemplate.all(
-          'provider.driver' => driver_symbol.to_s,
-          'provider.url' => current_provider
-        ).map { |t| from_db(t, context) }
+        current_db.machine_templates.map { |t| from_db(t, context) }
       else
-        template = Deltacloud::Database::MachineTemplate.first(
-          'provider.driver' => driver_symbol.to_s,
-          'provider.url' => current_provider,
-          :id => id
-        )
+        template = current_db.machine_templates_dataset.first(:id => id)
         raise CIMI::Model::NotFound unless template
         from_db(template, context)
       end
@@ -61,31 +54,25 @@ class CIMI::Model::MachineTemplate < CIMI::Model::Base
 
     def create_from_json(body, context)
       json = JSON.parse(body)
-      new_template = current_db.machine_templates.new(
+      new_template = current_db.add_machine_template(
         :name => json['name'],
         :description => json['description'],
         :machine_config => json['machineConfig']['href'],
         :machine_image => json['machineImage']['href'],
         :ent_properties => json['properties'].to_json,
-        :be_kind => 'machine_template',
-        :be_id => ''
       )
-      new_template.save
       from_db(new_template, context)
     end
 
     def create_from_xml(body, context)
       xml = XmlSimple.xml_in(body)
-      new_template = current_db.machine_templates.new(
+      new_template = current_db.add_machine_template(
         :name => xml['name'].first,
         :description => xml['description'].first,
         :machine_config => xml['machineConfig'].first['href'],
         :machine_image => xml['machineImage'].first['href'],
-        :ent_properties => xml['property'].inject({}) { |r, p| r[p['key']]=p['content']; r },
-        :be_kind => 'machine_template',
-        :be_id => ''
+        :ent_properties => JSON::dump(xml['property'].inject({}) { |r, p| r[p['key']]=p['content']; r }),
       )
-      new_template.save
       from_db(new_template, context)
     end
 
@@ -102,7 +89,7 @@ class CIMI::Model::MachineTemplate < CIMI::Model::Base
         :description => model.description,
         :machine_config => { :href => model.machine_config },
         :machine_image => { :href => model.machine_image },
-        :property => model.ent_properties,
+        :property => JSON::parse(model.ent_properties),
         :created => Time.parse(model.created_at.to_s).xmlschema,
         :operations => [
           { :href => context.destroy_machine_template_url(model.id), :rel => 'http://schemas.dmtf.org/cimi/1/action/delete' }
diff --git a/server/lib/cimi/models/volume_configuration.rb b/server/lib/cimi/models/volume_configuration.rb
index b0ba85b..12a3198 100644
--- a/server/lib/cimi/models/volume_configuration.rb
+++ b/server/lib/cimi/models/volume_configuration.rb
@@ -27,32 +27,26 @@ class CIMI::Model::VolumeConfiguration < CIMI::Model::Base
 
   def self.create_from_json(body, context)
     json = JSON.parse(body)
-    new_config = current_db.volume_configurations.new(
+    new_config = current_db.add_volume_configuration(
       :name => json['name'],
       :description => json['description'],
       :format => json['format'],
       :capacity => json['capacity'],
       :ent_properties => json['properties'].to_json,
-      :be_kind => 'volume_configuration',
-      :be_id => ''
     )
-    new_config.save
     from_db(new_config, context)
   end
 
   def self.create_from_xml(body, context)
     xml = XmlSimple.xml_in(body)
     xml['property'] ||= []
-    new_config = current_db.volume_configurations.new(
+    new_config = current_db.add_volume_configuration(
       :name => xml['name'].first,
       :description => xml['description'].first,
       :format => xml['format'].first,
       :capacity => xml['capacity'].first,
-      :ent_properties => xml['property'].inject({}) { |r, p| r[p['key']]=p['content']; r },
-      :be_kind => 'volume_configuration',
-      :be_id => ''
+      :ent_properties => JSON::dump(xml['property'].inject({}) { |r, p| r[p['key']]=p['content']; r }),
     )
-    new_config.save
     from_db(new_config, context)
   end
 
@@ -65,20 +59,13 @@ class CIMI::Model::VolumeConfiguration < CIMI::Model::Base
       if context.driver.respond_to? :volume_configurations
         context.driver.volume_configurations(context.credentials, {:env=>context})
       else
-        Deltacloud::Database::VolumeConfiguration.all(
-          'provider.driver' => driver_symbol.to_s,
-          'provider.url' => current_provider
-        ).map { |t| from_db(t, context) }
+        current_db.volume_configurations.map { |t| from_db(t, context) }
       end
     else
       if context.driver.respond_to? :volume_configuration
         context.driver.volume_configuration(context.credentials, id, :env=>context)
       else
-        config = Deltacloud::Database::VolumeConfiguration.first(
-          'provider.driver' => driver_symbol.to_s,
-          'provider.url' => current_provider,
-          :id => id
-        )
+        config = current_db.volume_configurations_dataset.first(:id => id)
         raise CIMI::Model::NotFound unless config
         from_db(config, context)
       end
@@ -94,7 +81,7 @@ class CIMI::Model::VolumeConfiguration < CIMI::Model::Base
       :description => model.description,
       :format => model.format,
       :capacity => context.to_kibibyte(model.capacity, "GB"),
-      :property => model.ent_properties,
+      :property => JSON::parse(model.ent_properties),
       :operations => [
         { :href => context.destroy_volume_configuration_url(model.id), :rel => 'http://schemas.dmtf.org/cimi/1/action/delete' }
       ]
diff --git a/server/lib/cimi/models/volume_template.rb b/server/lib/cimi/models/volume_template.rb
index a2b8eb7..47bbb3f 100644
--- a/server/lib/cimi/models/volume_template.rb
+++ b/server/lib/cimi/models/volume_template.rb
@@ -30,27 +30,20 @@ class CIMI::Model::VolumeTemplate < CIMI::Model::Base
   end
 
   def self.find(id, context)
-   if id==:all
-     if context.driver.respond_to? :volume_templates
-       context.driver.volume_templates(context.credentials, {:env=>context})
-     else
-       Deltacloud::Database::VolumeTemplate.all(
-         'provider.driver' => driver_symbol.to_s,
-         'provider.url' => current_provider
-       ).map { |t| from_db(t, context) }
+    if id==:all
+      if context.driver.respond_to? :volume_templates
+        context.driver.volume_templates(context.credentials, {:env=>context})
+      else
+        current_db.volume_templates.map { |t| from_db(t, context) }
       end
     else
-     if context.driver.respond_to? :volume_template
-       context.driver.volume_template(context.credentials, id, :env=>context)
-     else
-       template = Deltacloud::Database::VolumeTemplate.first(
-         'provider.driver' => driver_symbol.to_s,
-         'provider.url' => current_provider,
-         :id => id
-       )
-       raise CIMI::Model::NotFound unless template
-       from_db(template, context)
-     end
+      if context.driver.respond_to? :volume_template
+        context.driver.volume_template(context.credentials, id, :env=>context)
+      else
+        template = current_db.volume_templates_dataset.first(:id => id)
+        raise CIMI::Model::NotFound unless template
+        from_db(template, context)
+      end
     end
   end
 
@@ -58,16 +51,13 @@ class CIMI::Model::VolumeTemplate < CIMI::Model::Base
     input = (type == :xml)? XmlSimple.xml_in(body, {"ForceArray"=>false,"NormaliseSpace"=>2}) : JSON.parse(body)
     input['property'] ||= []
     vol_image = input['volumeImage']['href'] if input['volumeImage']
-    new_template = current_db.volume_templates.new(
+    new_template = current_db.add_volume_template(
       :name => input['name'],
       :description => input['description'],
       :volume_config => input['volumeConfig']['href'],
       :volume_image => vol_image,
-      :ent_properties => input['property'].inject({}) { |r, p| r[p['key']]=p['content']; r },
-      :be_kind => 'volume_template',
-      :be_id => ''
+      :ent_properties => JSON::dump(input['property'].inject({}) { |r, p| r[p['key']]=p['content']; r }),
     )
-    new_template.save
     from_db(new_template, context)
   end
 
@@ -84,7 +74,7 @@ private
       :description => model.description,
       :volume_config => {:href => model.volume_config},
       :volume_image => {:href => model.volume_image},
-      :property => model.ent_properties,
+      :property => JSON::parse(model.ent_properties),
       :operations => [
         { :href => context.destroy_volume_template_url(model.id), :rel => 'http://schemas.dmtf.org/cimi/1/action/delete' }
       ]
-- 
1.8.0.2


[PATCH core 2/8] CIMI: Migrated database models to use Sequel

Posted by mf...@redhat.com.
From: Michal Fojtik <mf...@redhat.com>


Signed-off-by: Michal fojtik <mf...@redhat.com>
---
 server/lib/db/address_template.rb     | 10 ---------
 server/lib/db/entity.rb               | 25 +++++----------------
 server/lib/db/machine_template.rb     |  5 -----
 server/lib/db/provider.rb             | 41 +++++------------------------------
 server/lib/db/volume_configuration.rb |  4 ----
 server/lib/db/volume_template.rb      |  4 ----
 6 files changed, 11 insertions(+), 78 deletions(-)

diff --git a/server/lib/db/address_template.rb b/server/lib/db/address_template.rb
index 5a08346..8586255 100644
--- a/server/lib/db/address_template.rb
+++ b/server/lib/db/address_template.rb
@@ -2,16 +2,6 @@ module Deltacloud
   module Database
 
     class AddressTemplate < Entity
-      belongs_to :provider
-
-      property :ip, String
-      property :hostname, String
-      property :allocation, String, :default => 'dynamic'
-      property :default_gateway, String, :default => 'unknown'
-      property :dns, String, :default => 'unknown'
-      property :protocol, String, :default => 'ipv4'
-      property :mask, String, :default => 'unknown'
-      property :network, String
     end
 
   end
diff --git a/server/lib/db/entity.rb b/server/lib/db/entity.rb
index f9b34ff..963a26b 100644
--- a/server/lib/db/entity.rb
+++ b/server/lib/db/entity.rb
@@ -1,33 +1,18 @@
 module Deltacloud
   module Database
 
-    class BaseEntity
-      include DataMapper::Resource
+    class Entity < Sequel::Model
 
-      belongs_to :provider
+      many_to_one :provider
 
-      property :id, Serial
-      property :type, Discriminator
-
-      property :be_kind, String, :required => true # => Machine, MachineImage, ...
-      property :be_id, String # => Original Machine 'id'
-
-      timestamps :created_at, :updated_on
-    end
-
-    class Entity < BaseEntity
-
-      belongs_to :provider
-
-      property :name, String
-      property :description, String
-      property :ent_properties, Json
+      plugin :single_table_inheritance, :model
+      plugin :timestamps, :create => :created_at
 
       def to_hash
         retval = {}
         retval.merge!(:name => self.name) if !self.name.nil?
         retval.merge!(:description => self.description) if !self.description.nil?
-        retval.merge!(:property => self.ent_properties) if !self.ent_properties.nil?
+        retval.merge!(:property => JSON::parse(self.ent_properties)) if !self.ent_properties.nil?
         retval
       end
 
diff --git a/server/lib/db/machine_template.rb b/server/lib/db/machine_template.rb
index 134eb23..1b34161 100644
--- a/server/lib/db/machine_template.rb
+++ b/server/lib/db/machine_template.rb
@@ -2,11 +2,6 @@ module Deltacloud
   module Database
 
     class MachineTemplate < Entity
-      belongs_to :provider
-
-      property :machine_config, String, :length => 255
-      property :machine_image, String, :length => 255
-
     end
 
   end
diff --git a/server/lib/db/provider.rb b/server/lib/db/provider.rb
index e8ca4f5..c0b8485 100644
--- a/server/lib/db/provider.rb
+++ b/server/lib/db/provider.rb
@@ -1,41 +1,12 @@
 module Deltacloud
   module Database
 
-    class Provider
-      include DataMapper::Resource
-
-      property :id, Serial
-      property :driver, String, :required => true
-      property :url, Text
-
-      has n, :entities
-      has n, :machine_templates
-      has n, :address_templates
-      has n, :volume_configurations
-      has n, :volume_templates
-
-      # This is a workaround for strange bug in Fedora MRI:
-      #
-      def machine_templates
-        MachineTemplate.all(:provider_id => self.id)
-      end
-
-      def address_templates
-        AddressTemplate.all(:provider_id => self.id)
-      end
-
-      def volume_configurations
-        VolumeConfiguration.all(:provider_id => self.id)
-      end
-
-      def volume_templates
-        VolumeTemplate.all(:provider_id => self.id)
-      end
-
-      def entities
-        Entity.all(:provider_id => self.id)
-      end
-
+    class Provider < Sequel::Model
+      one_to_many :entities
+      one_to_many :machine_templates
+      one_to_many :address_templates
+      one_to_many :volume_templates
+      one_to_many :volume_configurations
     end
 
   end
diff --git a/server/lib/db/volume_configuration.rb b/server/lib/db/volume_configuration.rb
index 58aa624..aa956ce 100644
--- a/server/lib/db/volume_configuration.rb
+++ b/server/lib/db/volume_configuration.rb
@@ -2,10 +2,6 @@ module Deltacloud
   module Database
 
     class VolumeConfiguration < Entity
-      belongs_to :provider
-
-      property :format, String
-      property :capacity, String
     end
 
   end
diff --git a/server/lib/db/volume_template.rb b/server/lib/db/volume_template.rb
index 8658b8b..0d876bf 100644
--- a/server/lib/db/volume_template.rb
+++ b/server/lib/db/volume_template.rb
@@ -2,10 +2,6 @@ module Deltacloud
   module Database
 
     class VolumeTemplate < Entity
-      belongs_to :provider
-
-      property :volume_config, String
-      property :volume_image, String
     end
 
   end
-- 
1.8.0.2


[PATCH core 4/8] Remove index creation errors when database is already created

Posted by mf...@redhat.com.
From: Michal Fojtik <mf...@redhat.com>


Signed-off-by: Michal fojtik <mf...@redhat.com>
---
 server/lib/db.rb | 17 ++++++++++++-----
 1 file changed, 12 insertions(+), 5 deletions(-)

diff --git a/server/lib/db.rb b/server/lib/db.rb
index 64cc283..49e6f33 100644
--- a/server/lib/db.rb
+++ b/server/lib/db.rb
@@ -16,22 +16,29 @@ module Deltacloud
   end
 
   def self.initialize_database
+    db = database
 
-    database.create_table?(:providers) {
+    db.create_table?(:providers) {
       primary_key :id
 
       column :driver, :string, { :null => false }
       column :url, :string
-      index [ :url, :driver ]
+      index [ :url, :driver ] if !db.table_exists?(:providers)
     }
 
-    database.create_table?(:entities) {
+    db.create_table?(:entities) {
       primary_key :id
-      foreign_key :provider_id, :providers, { :index => true, :null => false }
+
+      unless db.table_exists?(:entities)
+        foreign_key :provider_id, :providers, { :index => true, :null => false }
+      end
+
       column :created_at, :timestamp
 
       # Base
-      column :model, :string, { :index => true, :null => false, :default => 'entity' }
+      unless db.table_exists?(:entities)
+        column :model, :string, { :index => true, :null => false, :default => 'entity' }
+      end
 
       # Map Entity to Deltacloud model
       # (like: Machine => Instance)
-- 
1.8.0.2


[PATCH core 8/8] Initial database tests for CIMI frontend

Posted by mf...@redhat.com.
From: Michal Fojtik <mf...@redhat.com>


Signed-off-by: Michal fojtik <mf...@redhat.com>
---
 server/Rakefile                              |   1 +
 server/tests/cimi/db/database_helper_test.rb | 190 +++++++++++++++++++++++++++
 server/tests/cimi/db/db_helper.rb            |  22 ++++
 server/tests/cimi/db/schema_test.rb          |  94 +++++++++++++
 4 files changed, 307 insertions(+)
 create mode 100644 server/tests/cimi/db/database_helper_test.rb
 create mode 100644 server/tests/cimi/db/db_helper.rb
 create mode 100644 server/tests/cimi/db/schema_test.rb

diff --git a/server/Rakefile b/server/Rakefile
index cc17034..b8b3ea1 100644
--- a/server/Rakefile
+++ b/server/Rakefile
@@ -206,6 +206,7 @@ namespace :test do
         t.loader = :testrb
       end
       t.test_files = FileList[
+        'tests/cimi/db/*test.rb',            # CIMI frontend database tests
         'tests/cimi/model/*spec.rb',            # CIMI frontend serialization API tests
         'tests/cimi/collections/*test.rb',      # CIMI frontend API tests
       ]
diff --git a/server/tests/cimi/db/database_helper_test.rb b/server/tests/cimi/db/database_helper_test.rb
new file mode 100644
index 0000000..7bd3e23
--- /dev/null
+++ b/server/tests/cimi/db/database_helper_test.rb
@@ -0,0 +1,190 @@
+require 'rubygems'
+require 'require_relative' if RUBY_VERSION < '1.9'
+require 'minitest/autorun'
+
+require_relative 'db_helper.rb'
+require_relative '../spec_helper.rb'
+require_relative './../collections/common.rb'
+
+class DatabaseHelper
+  include Deltacloud::Helpers::Database
+end
+
+describe Deltacloud::Helpers::Database do
+  include Deltacloud::DatabaseTestHelper
+
+  before do
+    ENV['RACK_ENV'] = 'development'
+    @db = DatabaseHelper.new
+  end
+
+  it 'report if application is running under test environment' do
+    ENV['RACK_ENV'] = 'test'
+    @db.test_environment?.must_equal true
+    ENV['RACK_ENV'] = 'development'
+    @db.test_environment?.must_equal false
+  end
+
+  it 'report if given entity is provided by database' do
+    @db.provides?('machine_template').must_equal true
+    @db.provides?('machine').must_equal false
+  end
+
+  it 'reports the current provider' do
+    @db.current_provider.must_equal 'default'
+  end
+
+  it 'create provider when it does not exists' do
+    @db.current_db.must_be_kind_of Deltacloud::Database::Provider
+    @db.current_db.driver.must_equal 'mock'
+    @db.current_db.url.must_equal @db.current_provider
+    @db.current_db.must_respond_to :entities
+    @db.current_db.must_respond_to :machine_templates
+    @db.current_db.must_respond_to :address_templates
+    @db.current_db.must_respond_to :volume_configurations
+    @db.current_db.must_respond_to :volume_templates
+  end
+
+  it 'extract attributes both from JSON and XMLSimple' do
+    xml_simple_test = { 'property' => [ { 'key' => 'template', 'content' => "value"} ] }
+    json_test = { 'properties' => { 'template' => 'value' } }
+
+    @db.extract_attribute_value('property', xml_simple_test).must_equal('template' => 'value')
+    @db.extract_attribute_value('properties', json_test).must_equal('template' => 'value')
+  end
+
+  it 'must return entity for given model' do
+    provider = Deltacloud::Database::Provider
+    entity = Deltacloud::Database::Entity
+    @db.current_db.wont_be_nil
+
+    new_entity = @db.current_db.add_entity(
+      :name => 'testMachine1',
+      :description => 'testMachine1 description',
+      :ent_properties => JSON::dump(:key => 'value'),
+      :be_kind => 'instance',
+      :be_id => 'inst1'
+    )
+
+    check_entity_base_attrs new_entity, entity, @db.current_db
+
+    result = @db.get_entity(Instance.new(:id => 'inst1'))
+    result.must_equal new_entity
+
+    new_entity.destroy.wont_equal false
+  end
+
+  it 'must load attributes for entity for given model' do
+    provider = Deltacloud::Database::Provider
+    entity = Deltacloud::Database::Entity
+    @db.current_db.wont_be_nil
+
+    new_entity = @db.current_db.add_entity(
+      :name => 'testMachine1',
+      :description => 'testMachine1 description',
+      :ent_properties => JSON::dump(:key => 'value'),
+      :be_kind => 'instance',
+      :be_id => 'inst1'
+    )
+
+    check_entity_base_attrs new_entity, entity, @db.current_db
+
+    result = @db.load_attributes_for(Instance.new(:id => 'inst1'))
+    result.must_be_kind_of Hash
+    result[:name].must_equal new_entity.name
+    result[:description].must_equal new_entity.description
+    result[:property].must_equal JSON::parse(new_entity.ent_properties)
+
+    new_entity.destroy.wont_equal false
+  end
+
+  it 'must delete attributes for entity for given model' do
+    provider = Deltacloud::Database::Provider
+    entity = Deltacloud::Database::Entity
+    @db.current_db.wont_be_nil
+
+    new_entity = @db.current_db.add_entity(
+      :name => 'testMachine1',
+      :description => 'testMachine1 description',
+      :ent_properties => JSON::dump(:key => 'value'),
+      :be_kind => 'instance',
+      :be_id => 'inst1'
+    )
+
+    check_entity_base_attrs new_entity, entity, @db.current_db
+
+    result = @db.delete_attributes_for(Instance.new(:id => 'inst1'))
+    result.wont_equal false
+    result.exists?.must_equal false
+  end
+
+  it 'must store JSON attributes for entity for given model' do
+    provider = Deltacloud::Database::Provider
+    entity = Deltacloud::Database::Entity
+    @db.current_db.wont_be_nil
+
+    mock_instance = Instance.new(:id => 'inst1')
+    mock_json = '
+{
+  "resourceURI": "http://schemas.dmtf.org/cimi/1/MachineCreate",
+  "name": "myDatabaseMachine",
+  "description": "This is a demo machine",
+  "properties": {
+    "foo": "bar",
+    "life": "is life"
+  },
+  "machineTemplate": {
+    "machineConfig": { "href": "http://localhost:3001/cimi/machine_configurations/m1-small" },
+    "machineImage": { "href": "http://localhost:3001/cimi/machine_images/img1" }
+  }
+}
+    '
+    result = @db.store_attributes_for(mock_instance, JSON::parse(mock_json))
+    result.must_be_kind_of entity
+    check_entity_base_attrs result, entity, @db.current_db
+    load_result = @db.load_attributes_for(mock_instance)
+    load_result.must_be_kind_of Hash
+    load_result.wont_be_empty
+    load_result[:name].must_equal 'myDatabaseMachine'
+    load_result[:description].must_equal 'This is a demo machine'
+    load_result[:property].must_be_kind_of Hash
+    load_result[:property].wont_be_empty
+    load_result[:property]['foo'].must_equal 'bar'
+    load_result[:property]['life'].must_equal 'is life'
+    result.destroy.wont_equal false
+  end
+
+  it 'must store XML attributes for entity for given model' do
+    provider = Deltacloud::Database::Provider
+    entity = Deltacloud::Database::Entity
+    @db.current_db.wont_be_nil
+
+    mock_instance = Instance.new(:id => 'inst1')
+    mock_xml = '
+<MachineCreate>
+  <name>myMachineXML123</name>
+  <description>Description of my new Machine</description>
+  <machineTemplate>
+    <machineConfig href="http://localhost:3001/cimi/machine_configurations/m1-small"/>
+    <machineImage href="http://localhost:3001/cimi/machine_images/img1"/>
+  </machineTemplate>
+  <property key="test">value</property>
+  <property key="foo">bar</property>
+</MachineCreate>
+    '
+    result = @db.store_attributes_for(mock_instance, XmlSimple.xml_in(mock_xml))
+    result.must_be_kind_of entity
+    check_entity_base_attrs result, entity, @db.current_db
+    load_result = @db.load_attributes_for(mock_instance)
+    load_result.must_be_kind_of Hash
+    load_result.wont_be_empty
+    load_result[:name].must_equal 'myMachineXML123'
+    load_result[:description].must_equal 'Description of my new Machine'
+    load_result[:property].must_be_kind_of Hash
+    load_result[:property].wont_be_empty
+    load_result[:property]['test'].must_equal 'value'
+    result.destroy.wont_equal false
+  end
+
+
+end
diff --git a/server/tests/cimi/db/db_helper.rb b/server/tests/cimi/db/db_helper.rb
new file mode 100644
index 0000000..9bbdf30
--- /dev/null
+++ b/server/tests/cimi/db/db_helper.rb
@@ -0,0 +1,22 @@
+# Memory database
+ENV['DATABASE_LOCATION'] = 'sqlite:/'
+
+module Deltacloud
+  module DatabaseTestHelper
+
+    def check_entity_base_attrs(entity, entity_klass, provider)
+      entity.must_be_kind_of entity_klass
+      entity.id.wont_be_nil
+      entity.created_at.wont_be_nil
+      entity.name.wont_be_empty
+      entity.description.wont_be_empty
+      entity.provider.must_equal provider
+      entity.model.must_equal entity_klass
+      entity.to_hash[:name].must_equal entity.name
+      entity.to_hash[:description].must_equal entity.description
+      entity.to_hash[:property].must_be_kind_of Hash
+      entity.to_hash[:property].wont_be_empty
+    end
+
+  end
+end
diff --git a/server/tests/cimi/db/schema_test.rb b/server/tests/cimi/db/schema_test.rb
new file mode 100644
index 0000000..db5e71c
--- /dev/null
+++ b/server/tests/cimi/db/schema_test.rb
@@ -0,0 +1,94 @@
+require 'rubygems'
+require 'require_relative' if RUBY_VERSION < '1.9'
+
+require_relative 'db_helper.rb'
+require_relative '../spec_helper.rb'
+
+describe Deltacloud::Database do
+
+  include Deltacloud::DatabaseTestHelper
+
+  before do
+    @db = Deltacloud.database
+  end
+
+  it 'has valid database connection' do
+    @db.test_connection.must_equal true
+  end
+
+  it 'creates the database schema' do
+    @db.tables.wont_be_empty
+    @db.tables.must_include :providers
+    @db.tables.must_include :entities
+  end
+
+  it 'should allow creation of providers' do
+    provider = Deltacloud::Database::Provider
+    provider.table_name.must_equal :providers
+    new_provider = provider.create(:driver => 'mock', :url => 'test1')
+    new_provider.must_be_kind_of provider
+    new_provider.destroy.wont_equal false
+  end
+
+  it 'should not allow creation of provider with nil driver' do
+    provider = Deltacloud::Database::Provider
+    lambda {
+      new_provider = provider.create(:driver => nil, :url => 'test1')
+    }.must_raise Sequel::InvalidValue
+  end
+
+  it 'allow creation of simple entity' do
+    provider = Deltacloud::Database::Provider
+    entity = Deltacloud::Database::Entity
+    entity.table_name.must_equal :entities
+
+    entity_provider = provider.create(:driver => :mock)
+
+    new_entity = entity_provider.add_entity(
+      :name => 'testEntity1',
+      :description => 'testEntity1 description',
+      :ent_properties => JSON::dump(:key => 'value')
+    )
+
+    check_entity_base_attrs new_entity, entity, entity_provider
+
+    new_entity.destroy.wont_equal false
+    entity_provider.destroy.wont_equal false
+  end
+
+  it 'allow creation of extended entities' do
+    provider = Deltacloud::Database::Provider
+    entity = Deltacloud::Database::MachineTemplate
+    entity.table_name.must_equal :entities
+    entity_provider = provider.create(:driver => :mock)
+    new_entity = entity_provider.add_machine_template(
+      :name => 'testMachineTemplate1',
+      :description => 'testMachineTemplate1 description',
+      :ent_properties => JSON::dump(:key => 'value'),
+      :machine_config => 'http://example.com/cimi/machine_configurations/m1-small',
+      :machine_image => 'http://example.com/cimi/machine_image/img1'
+    )
+    check_entity_base_attrs new_entity, entity, entity_provider
+
+    new_entity.machine_config.wont_be_empty
+    new_entity.machine_image.wont_be_empty
+
+    new_entity.destroy.wont_equal false
+    entity_provider.destroy.wont_equal false
+  end
+
+  it 'validate presence of required attributes for extended entities' do
+    provider = Deltacloud::Database::Provider
+    entity = Deltacloud::Database::MachineTemplate
+    entity.table_name.must_equal :entities
+    entity_provider = provider.create(:driver => :mock)
+    lambda {
+      new_entity = entity_provider.add_machine_template(
+        :name => 'testMachineTemplate1',
+        :description => 'testMachineTemplate1 description',
+        :ent_properties => JSON::dump(:key => 'value'),
+      )
+    }.must_raise Sequel::ValidationFailed
+  end
+
+end
-- 
1.8.0.2


[PATCH core 6/8] Fixed bugs in storing entity data to database

Posted by mf...@redhat.com.
From: Michal Fojtik <mf...@redhat.com>


Signed-off-by: Michal fojtik <mf...@redhat.com>
---
 server/lib/cimi/helpers/database_helper.rb | 14 ++++++++++++--
 1 file changed, 12 insertions(+), 2 deletions(-)

diff --git a/server/lib/cimi/helpers/database_helper.rb b/server/lib/cimi/helpers/database_helper.rb
index d432f69..e6f73fe 100644
--- a/server/lib/cimi/helpers/database_helper.rb
+++ b/server/lib/cimi/helpers/database_helper.rb
@@ -54,7 +54,11 @@ module Deltacloud
         return if model.id.nil?
 
         unless entity = get_entity(model)
-          entity = Deltacloud::Database::Entity.new(:provider_id => current_db.id)
+          entity = Deltacloud::Database::Entity.new(
+            :provider_id => current_db.id,
+            :be_id => model.id,
+            :be_kind => model.to_entity
+          )
         end
 
         entity.description = extract_attribute_value('description', attrs) if attrs.has_key? 'description'
@@ -76,7 +80,13 @@ module Deltacloud
       #
       def extract_attribute_value(name, attrs={})
         return unless attrs[name]
-        attrs[name].is_a?(Array) ? attrs[name].first : attrs[name]
+        if name == 'property'
+          attrs[name].is_a?(Array) ?
+            attrs[name].inject({}) { |r, v| r[v['key']] = v['content']; r} :
+            attrs[name]
+        else
+          attrs[name].is_a?(Array) ? attrs[name].first : attrs[name]
+        end
       end
 
     end
-- 
1.8.0.2