diff --git a/include/Image.h b/include/Image.h
index 0cc7bf1c8e..4206f48b93 100644
--- a/include/Image.h
+++ b/include/Image.h
@@ -292,14 +292,24 @@ public:
return cloning_ops;
}
- int dec_cloning()
+ int dec_cloning(int img_id)
{
- return --cloning_ops;
+ if ( img_clone_collection.del_collection_id(img_id) == 0 )
+ {
+ cloning_ops--;
+ }
+
+ return cloning_ops;
}
- int inc_cloning()
+ int inc_cloning(int img_id)
{
- return ++cloning_ops;
+ if ( img_clone_collection.add_collection_id(img_id) == 0 )
+ {
+ cloning_ops++;
+ }
+
+ return cloning_ops;
}
/**
@@ -553,6 +563,11 @@ private:
*/
ObjectCollection vm_collection;
+ /**
+ * Stores a collection with the Images cloning this image
+ */
+ ObjectCollection img_clone_collection;
+
// *************************************************************************
// DataBase implementation (Private)
// *************************************************************************
diff --git a/include/ImageManager.h b/include/ImageManager.h
index 48fa547c6c..91e02129e8 100644
--- a/include/ImageManager.h
+++ b/include/ImageManager.h
@@ -107,8 +107,9 @@ public:
/**
* Closes any cloning operation on the image, updating the state if needed
* @param iid image id of the image to be released
+ * @param clone_img_id image id of the image that was being cloned
*/
- void release_cloning_image(int iid);
+ void release_cloning_image(int iid, int clone_img_id);
/**
* Enables the image
diff --git a/install.sh b/install.sh
index 116dd0ebf3..b8f8aad8c3 100755
--- a/install.sh
+++ b/install.sh
@@ -1001,6 +1001,7 @@ ONEDB_MIGRATOR_FILES="src/onedb/2.0_to_2.9.80.rb \
src/onedb/3.6.0_to_3.7.80.rb \
src/onedb/3.7.80_to_3.8.0.rb \
src/onedb/3.8.0_to_3.8.1.rb \
+ src/onedb/3.8.1_to_3.9.80.rb \
src/onedb/fsck.rb \
src/onedb/onedb.rb \
src/onedb/onedb_backend.rb"
diff --git a/share/doc/xsd/image.xsd b/share/doc/xsd/image.xsd
index e5dc49fe12..72a5eb7bf2 100644
--- a/share/doc/xsd/image.xsd
+++ b/share/doc/xsd/image.xsd
@@ -57,6 +57,13 @@
+
+
+
+
+
+
+
diff --git a/src/image/Image.cc b/src/image/Image.cc
index 3c45772b2b..0d4fb7baa1 100644
--- a/src/image/Image.cc
+++ b/src/image/Image.cc
@@ -53,7 +53,8 @@ Image::Image(int _uid,
cloning_id(-1),
ds_id(-1),
ds_name(""),
- vm_collection("VMS")
+ vm_collection("VMS"),
+ img_clone_collection("CLONES")
{
if (_image_template != 0)
{
@@ -318,6 +319,7 @@ string& Image::to_xml(string& xml) const
string perms_xml;
ostringstream oss;
string vm_collection_xml;
+ string clone_collection_xml;
oss <<
"" <<
@@ -343,6 +345,7 @@ string& Image::to_xml(string& xml) const
"" << ds_id << ""<<
"" << ds_name << "" <<
vm_collection.to_xml(vm_collection_xml) <<
+ img_clone_collection.to_xml(clone_collection_xml) <<
obj_template->to_xml(template_xml) <<
"";
@@ -427,6 +430,21 @@ int Image::from_xml(const string& xml)
ObjectXML::free_nodes(content);
+
+ content.clear();
+
+ ObjectXML::get_nodes("/IMAGE/CLONES", content);
+
+ if (content.empty())
+ {
+ return -1;
+ }
+
+ rc += img_clone_collection.from_xml_node(content[0]);
+
+ ObjectXML::free_nodes(content);
+
+
if (rc != 0)
{
return -1;
diff --git a/src/image/ImageManagerActions.cc b/src/image/ImageManagerActions.cc
index 2ec9a56781..a6dba546a5 100644
--- a/src/image/ImageManagerActions.cc
+++ b/src/image/ImageManagerActions.cc
@@ -225,7 +225,7 @@ void ImageManager::release_image(int vm_id, int iid, bool failed)
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
-void ImageManager::release_cloning_image(int iid)
+void ImageManager::release_cloning_image(int iid, int clone_img_id)
{
Image * img;
@@ -238,24 +238,18 @@ void ImageManager::release_cloning_image(int iid)
return;
}
+ int cloning = img->dec_cloning(clone_img_id);
+
switch (img->get_state())
{
- case Image::CLONE:
- img->dec_cloning();
- img->set_state(Image::READY);
-
- ipool->update(img);
- img->unlock();
- break;
-
case Image::USED:
- if ( img->dec_cloning() == 0 && img->get_running() == 0 )
+ case Image::CLONE:
+
+ if ( cloning == 0 && img->get_running() == 0 )
{
img->set_state(Image::READY);
}
- ipool->update(img);
- img->unlock();
break;
case Image::DELETE:
@@ -275,6 +269,9 @@ void ImageManager::release_cloning_image(int iid)
img->unlock();
break;
}
+
+ ipool->update(img);
+ img->unlock();
}
/* -------------------------------------------------------------------------- */
@@ -439,7 +436,7 @@ int ImageManager::delete_image(int iid, const string& ds_data)
if ( cloning_id != -1 )
{
- release_cloning_image(cloning_id);
+ release_cloning_image(cloning_id, iid);
}
return 0;
@@ -524,7 +521,7 @@ int ImageManager::clone_image(int new_id,
switch(img->get_state())
{
case Image::READY:
- img->inc_cloning();
+ img->inc_cloning(new_id);
if (img->isPersistent())
{
@@ -541,7 +538,7 @@ int ImageManager::clone_image(int new_id,
break;
case Image::USED:
- img->inc_cloning();
+ img->inc_cloning(new_id);
ipool->update(img);
diff --git a/src/image/ImageManagerDriver.cc b/src/image/ImageManagerDriver.cc
index f0c07900cb..da7a6bb1e3 100644
--- a/src/image/ImageManagerDriver.cc
+++ b/src/image/ImageManagerDriver.cc
@@ -279,7 +279,7 @@ static void clone_action(istringstream& is,
NebulaLog::log("ImM", Log::INFO, "Image cloned and ready to use.");
- im ->release_cloning_image(cloning_id);
+ im->release_cloning_image(cloning_id, id);
return;
@@ -304,7 +304,7 @@ error:
image->unlock();
- im ->release_cloning_image(cloning_id);
+ im->release_cloning_image(cloning_id, id);
return;
}
diff --git a/src/onedb/3.8.1_to_3.9.80.rb b/src/onedb/3.8.1_to_3.9.80.rb
new file mode 100644
index 0000000000..2ccf5e7a5d
--- /dev/null
+++ b/src/onedb/3.8.1_to_3.9.80.rb
@@ -0,0 +1,105 @@
+# -------------------------------------------------------------------------- #
+# Copyright 2002-2012, OpenNebula Project Leads (OpenNebula.org) #
+# #
+# Licensed 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. #
+#--------------------------------------------------------------------------- #
+
+require 'set'
+require "rexml/document"
+include REXML
+
+module Migrator
+ def db_version
+ "3.9.80"
+ end
+
+ def one_version
+ "OpenNebula 3.9.80"
+ end
+
+ def up
+
+ ########################################################################
+ # Add Cloning Image ID collection to Images
+ ########################################################################
+
+ counters = {}
+ counters[:image] = {}
+
+ # Init image counters
+ @db.fetch("SELECT oid,body FROM image_pool") do |row|
+ if counters[:image][row[:oid]].nil?
+ counters[:image][row[:oid]] = {
+ :clones => Set.new
+ }
+ end
+
+ doc = Document.new(row[:body])
+
+ doc.root.each_element("CLONING_ID") do |e|
+ img_id = e.text.to_i
+
+ if counters[:image][img_id].nil?
+ counters[:image][img_id] = {
+ :clones => Set.new
+ }
+ end
+
+ counters[:image][img_id][:clones].add(row[:oid])
+ end
+ end
+
+ ########################################################################
+ # Image
+ #
+ # IMAGE/CLONING_OPS
+ # IMAGE/CLONES/ID
+ ########################################################################
+
+ @db.run "CREATE TABLE image_pool_new (oid INTEGER PRIMARY KEY, name VARCHAR(128), body TEXT, uid INTEGER, gid INTEGER, owner_u INTEGER, group_u INTEGER, other_u INTEGER, UNIQUE(name,uid) );"
+
+ @db[:image_pool].each do |row|
+ doc = Document.new(row[:body])
+
+ oid = row[:oid]
+
+ n_cloning_ops = counters[:image][oid][:clones].size
+
+ # Rewrite number of clones
+ doc.root.each_element("CLONING_OPS") { |e|
+ if e.text != n_cloning_ops.to_s
+ warn("Image #{oid} CLONING_OPS has #{e.text} \tis\t#{n_cloning_ops}")
+ e.text = n_cloning_ops
+ end
+ }
+
+ # re-do list of Images cloning this one
+ clones_new_elem = doc.root.add_element("CLONES")
+
+ counters[:image][oid][:clones].each do |id|
+ clones_new_elem.add_element("ID").text = id.to_s
+ end
+
+ row[:body] = doc.to_s
+
+ # commit
+ @db[:image_pool_new].insert(row)
+ end
+
+ # Rename table
+ @db.run("DROP TABLE image_pool")
+ @db.run("ALTER TABLE image_pool_new RENAME TO image_pool")
+
+ return true
+ end
+end
diff --git a/src/onedb/fsck.rb b/src/onedb/fsck.rb
index 35960a0596..7c9b222b7b 100644
--- a/src/onedb/fsck.rb
+++ b/src/onedb/fsck.rb
@@ -21,11 +21,11 @@ require 'set'
module OneDBFsck
def db_version
- "3.8.1"
+ "4.0.0"
end
def one_version
- "OpenNebula 3.8.1"
+ "OpenNebula 4.0.0"
end
IMAGE_STATES=%w{INIT READY USED DISABLED LOCKED ERROR CLONE DELETE USED_PERS}
@@ -530,8 +530,6 @@ module OneDBFsck
counters[:image] = {}
counters[:vnet] = {}
- cloning_ops = {}
-
# Initialize all the host counters to 0
@db.fetch("SELECT oid FROM host_pool") do |row|
counters[:host][row[:oid]] = {
@@ -543,18 +541,26 @@ module OneDBFsck
# Init image counters
@db.fetch("SELECT oid,body FROM image_pool") do |row|
- counters[:image][row[:oid]] = Set.new
+ if counters[:image][row[:oid]].nil?
+ counters[:image][row[:oid]] = {
+ :vms => Set.new,
+ :clones => Set.new
+ }
+ end
doc = Document.new(row[:body])
- cloning_ops[row[:oid]] = [] if cloning_ops[row[:oid]].nil?
-
doc.root.each_element("CLONING_ID") do |e|
img_id = e.text.to_i
-
- cloning_ops[img_id] = [] if cloning_ops[img_id].nil?
- cloning_ops[img_id] << row[:oid]
+ if counters[:image][img_id].nil?
+ counters[:image][img_id] = {
+ :vms => Set.new,
+ :clones => Set.new
+ }
+ end
+
+ counters[:image][img_id][:clones].add(row[:oid])
end
end
@@ -584,7 +590,7 @@ module OneDBFsck
if counters[:image][img_id].nil?
log_error("VM #{row[:oid]} is using Image #{img_id}, but it does not exist")
else
- counters[:image][img_id].add(row[:oid])
+ counters[:image][img_id][:vms].add(row[:oid])
end
end
@@ -733,6 +739,8 @@ module OneDBFsck
# IMAGE/VMS/ID
#
# IMAGE/CLONING_OPS
+ # IMAGE/CLONES/ID
+ #
# IMAGE/CLONING_ID
#
# IMAGE/STATE
@@ -750,8 +758,8 @@ module OneDBFsck
persistent = ( doc.root.get_text('PERSISTENT').to_s == "1" )
current_state = doc.root.get_text('STATE').to_s.to_i
- rvms = counters[:image][oid].size
- n_cloning_ops = cloning_ops[row[:oid]].size
+ rvms = counters[:image][oid][:vms].size
+ n_cloning_ops = counters[:image][oid][:clones].size
# rewrite running_vms
doc.root.each_element("RUNNING_VMS") {|e|
@@ -766,7 +774,7 @@ module OneDBFsck
vms_new_elem = doc.root.add_element("VMS")
- counters[:image][oid].each do |id|
+ counters[:image][oid][:vms].each do |id|
id_elem = vms_elem.elements.delete("ID[.=#{id}]")
if id_elem.nil?
@@ -783,6 +791,7 @@ module OneDBFsck
if ( persistent && rvms > 0 )
n_cloning_ops = 0
+ counters[:image][oid][:clones] = Set.new
end
# Check number of clones
@@ -793,6 +802,26 @@ module OneDBFsck
end
}
+ # re-do list of Images cloning this one
+ clones_elem = doc.root.elements.delete("CLONES")
+
+ clones_new_elem = doc.root.add_element("CLONES")
+
+ counters[:image][oid][:clones].each do |id|
+ id_elem = clones_elem.elements.delete("ID[.=#{id}]")
+
+ if id_elem.nil?
+ log_error("Image #{id} is missing fom Image #{oid} CLONES id list")
+ end
+
+ clones_new_elem.add_element("ID").text = id.to_s
+ end
+
+ clones_elem.each_element("ID") do |id_elem|
+ log_error("Image #{id_elem.text} is in Image #{oid} CLONES id list, but it should not")
+ end
+
+
# Check state
state = current_state