mirror of
https://github.com/OpenNebula/one.git
synced 2025-01-10 01:17:40 +03:00
Merge branch 'feature-1291'
This commit is contained in:
commit
8f809df025
102
include/Image.h
102
include/Image.h
@ -99,7 +99,32 @@ public:
|
||||
USED = 2, /** < Image in use */
|
||||
DISABLED = 3, /** < Image can not be instantiated by a VM */
|
||||
LOCKED = 4, /** < FS operation for the Image in process */
|
||||
ERROR = 5 /** < Error state the operation FAILED*/
|
||||
ERROR = 5, /** < Error state the operation FAILED*/
|
||||
CLONE = 6, /** < Image is being cloned */
|
||||
DELETE = 7, /** < DS is deleting the image */
|
||||
USED_PERS = 8 /** < Image is in use and persistent */
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the string representation of an ImageState
|
||||
* @param state The state
|
||||
* @return the string representation
|
||||
*/
|
||||
static string state_to_str(ImageState state)
|
||||
{
|
||||
switch(state)
|
||||
{
|
||||
case INIT: return "INIT"; break;
|
||||
case READY: return "READY"; break;
|
||||
case USED: return "USED"; break;
|
||||
case DISABLED: return "DISABLED"; break;
|
||||
case LOCKED: return "LOCKED"; break;
|
||||
case ERROR: return "ERROR"; break;
|
||||
case CLONE: return "CLONE"; break;
|
||||
case DELETE: return "DELETE"; break;
|
||||
case USED_PERS: return "USED"; break;
|
||||
default: return "";
|
||||
}
|
||||
};
|
||||
|
||||
// *************************************************************************
|
||||
@ -186,7 +211,7 @@ public:
|
||||
* Returns the type of the image
|
||||
* @return type
|
||||
*/
|
||||
ImageType get_type()
|
||||
ImageType get_type() const
|
||||
{
|
||||
return type;
|
||||
}
|
||||
@ -194,7 +219,7 @@ public:
|
||||
* Returns the image state
|
||||
* @return state of image
|
||||
*/
|
||||
ImageState get_state()
|
||||
ImageState get_state() const
|
||||
{
|
||||
return state;
|
||||
}
|
||||
@ -209,29 +234,63 @@ public:
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Return the ID of the image we are cloning this one from (if any)
|
||||
*/
|
||||
int get_cloning_id() const
|
||||
{
|
||||
return cloning_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the ID of the image we are cloning this one from (if any)
|
||||
*/
|
||||
void set_cloning_id(int id)
|
||||
{
|
||||
cloning_id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the cloning state of the image
|
||||
*/
|
||||
void clear_cloning_id()
|
||||
{
|
||||
cloning_id = -1;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/* Acess Image Counters (running vms and clonning operations ) */
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
int dec_running ()
|
||||
{
|
||||
return --running_vms;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
int inc_running()
|
||||
{
|
||||
return ++running_vms;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
int get_running()
|
||||
int get_running() const
|
||||
{
|
||||
return running_vms;
|
||||
}
|
||||
|
||||
int get_cloning() const
|
||||
{
|
||||
return cloning_ops;
|
||||
}
|
||||
|
||||
int dec_cloning()
|
||||
{
|
||||
return --cloning_ops;
|
||||
}
|
||||
|
||||
int inc_cloning()
|
||||
{
|
||||
return ++cloning_ops;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Image type.
|
||||
*
|
||||
@ -372,7 +431,15 @@ public:
|
||||
{
|
||||
return ds_name;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Clones this image template including image specific attributes: NAME,
|
||||
* TYPE, PATH, FSTYPE, SIZE and PERSISTENT
|
||||
* @param new_name Value for the NAME attribute
|
||||
* @return Pointer to the new tempalte 0 in case of success
|
||||
*/
|
||||
ImageTemplate * clone_template(const string& new_name) const;
|
||||
|
||||
private:
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
@ -435,6 +502,17 @@ private:
|
||||
*/
|
||||
int running_vms;
|
||||
|
||||
/**
|
||||
* Number of pending cloning operations
|
||||
*/
|
||||
int cloning_ops;
|
||||
|
||||
/**
|
||||
* Indicates if this Image is a clone of another one.
|
||||
* Once the clone process is complete, it should be set to -1
|
||||
*/
|
||||
int cloning_id;
|
||||
|
||||
/**
|
||||
* Datastore ID
|
||||
*/
|
||||
|
@ -104,6 +104,12 @@ public:
|
||||
*/
|
||||
void release_image(int iid, bool failed);
|
||||
|
||||
/**
|
||||
* Closes any cloning operation on the image, updating the state if needed
|
||||
* @param iid image id of the image to be released
|
||||
*/
|
||||
void release_cloning_image(int iid);
|
||||
|
||||
/**
|
||||
* Enables the image
|
||||
* @param to_enable true will enable the image.
|
||||
@ -119,6 +125,19 @@ public:
|
||||
*/
|
||||
int register_image(int iid, const string& ds_data);
|
||||
|
||||
/**
|
||||
* Clone an existing image to the repository
|
||||
* @param new_id of the new image
|
||||
* @param cloning_id of the image to be cloned
|
||||
* @param ds_data data of the associated datastore in XML format
|
||||
* @param error describing the error
|
||||
* @return 0 on success
|
||||
*/
|
||||
int clone_image(int new_id,
|
||||
int cloning_id,
|
||||
const string& ds_data,
|
||||
string& error);
|
||||
|
||||
/**
|
||||
* Deletes an image from the repository and the DB
|
||||
* @param iid id of image
|
||||
@ -209,4 +228,3 @@ private:
|
||||
};
|
||||
|
||||
#endif /*IMAGE_MANAGER_H*/
|
||||
|
||||
|
@ -65,11 +65,6 @@ private:
|
||||
*/
|
||||
ImagePool * ipool;
|
||||
|
||||
/**
|
||||
* Configuration file for the driver
|
||||
*/
|
||||
//Template driver_conf;
|
||||
|
||||
/**
|
||||
* Sends a copy request to the MAD.
|
||||
* @param oid the image id.
|
||||
@ -77,6 +72,13 @@ private:
|
||||
*/
|
||||
void cp(int oid, const string& drv_msg) const;
|
||||
|
||||
/**
|
||||
* Sends a clone request to the MAD.
|
||||
* @param oid the image id.
|
||||
* @param drv_msg xml data for the mad operation.
|
||||
*/
|
||||
void clone(int oid, const string& drv_msg) const;
|
||||
|
||||
/**
|
||||
* Sends a stat request to the MAD.
|
||||
* @param oid the id of the stat request
|
||||
|
@ -56,6 +56,8 @@ public:
|
||||
* @param ds_name the name of the datastore
|
||||
* @param ds_type disk type for the image
|
||||
* @param ds_data the datastore data
|
||||
* @param source_img_id If the new Image is a clone, this must be the
|
||||
* source Image ID. Otherwise, it must be set to -1
|
||||
* @param oid the id assigned to the Image
|
||||
* @param error_str Returns the error reason, if any
|
||||
* @return the oid assigned to the object,
|
||||
@ -72,6 +74,7 @@ public:
|
||||
const string& ds_name,
|
||||
Image::DiskType ds_type,
|
||||
const string& ds_data,
|
||||
int source_img_id,
|
||||
int * oid,
|
||||
string& error_str);
|
||||
|
||||
|
@ -29,6 +29,8 @@ class ImageTemplate : public Template
|
||||
public:
|
||||
ImageTemplate() : Template(true,'=',"TEMPLATE"){};
|
||||
|
||||
ImageTemplate(const ImageTemplate& tmpl):Template(tmpl){};
|
||||
|
||||
~ImageTemplate(){};
|
||||
|
||||
/**
|
||||
|
@ -326,13 +326,7 @@ public:
|
||||
const string& name,
|
||||
const string& value)
|
||||
{
|
||||
SingleAttribute * sattr = new SingleAttribute(name,value);
|
||||
|
||||
obj_template->erase(sattr->name());
|
||||
|
||||
obj_template->set(sattr);
|
||||
|
||||
return 0;
|
||||
return obj_template->replace(name, value);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -99,6 +99,26 @@ public:
|
||||
RequestAttributes& att);
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
class ImageClone : public RequestManagerImage
|
||||
{
|
||||
public:
|
||||
ImageClone():
|
||||
RequestManagerImage("ImageClone",
|
||||
"Clones an existing image",
|
||||
"A:sis")
|
||||
{
|
||||
auth_op = AuthRequest::USE;
|
||||
};
|
||||
|
||||
~ImageClone(){};
|
||||
|
||||
void request_execute(xmlrpc_c::paramList const& _paramList,
|
||||
RequestAttributes& att);
|
||||
};
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
@ -135,7 +135,33 @@ public:
|
||||
virtual void set(Attribute * attr);
|
||||
|
||||
/**
|
||||
* Adds a new single attribute to the template.
|
||||
* Adds a new attribute to the template (replacing it if
|
||||
* already defined)
|
||||
* @param name of the new attribute
|
||||
* @param value of the new attribute
|
||||
* @return 0 on success
|
||||
*/
|
||||
int replace(const string& name, const string& value);
|
||||
|
||||
/**
|
||||
* Adds a new attribute to the template (replacing it if
|
||||
* already defined)
|
||||
* @param name of the new attribute
|
||||
* @param value of the new attribute
|
||||
* @return 0 on success
|
||||
*/
|
||||
int replace(const string& name, int value)
|
||||
{
|
||||
ostringstream oss;
|
||||
|
||||
oss << value;
|
||||
|
||||
return replace(name, oss.str());
|
||||
}
|
||||
|
||||
/*
|
||||
* Adds a new single attribute to the template. It will replace an existing
|
||||
* one if replace_mode was set to true
|
||||
* @param name of the attribute
|
||||
* @param value of the attribute
|
||||
*/
|
||||
|
@ -873,11 +873,13 @@ DATASTORE_DRIVER_COMMON_SCRIPTS="src/datastore_mad/remotes/xpath.rb \
|
||||
DATASTORE_DRIVER_DUMMY_SCRIPTS="src/datastore_mad/remotes/dummy/cp \
|
||||
src/datastore_mad/remotes/dummy/mkfs \
|
||||
src/datastore_mad/remotes/dummy/stat \
|
||||
src/datastore_mad/remotes/dummy/clone \
|
||||
src/datastore_mad/remotes/dummy/rm"
|
||||
|
||||
DATASTORE_DRIVER_FS_SCRIPTS="src/datastore_mad/remotes/fs/cp \
|
||||
src/datastore_mad/remotes/fs/mkfs \
|
||||
src/datastore_mad/remotes/fs/stat \
|
||||
src/datastore_mad/remotes/fs/clone \
|
||||
src/datastore_mad/remotes/fs/rm"
|
||||
|
||||
DATASTORE_DRIVER_VMWARE_SCRIPTS="src/datastore_mad/remotes/vmware/cp \
|
||||
@ -889,12 +891,14 @@ DATASTORE_DRIVER_ISCSI_SCRIPTS="src/datastore_mad/remotes/iscsi/cp \
|
||||
src/datastore_mad/remotes/iscsi/mkfs \
|
||||
src/datastore_mad/remotes/iscsi/stat \
|
||||
src/datastore_mad/remotes/iscsi/rm \
|
||||
src/datastore_mad/remotes/iscsi/clone \
|
||||
src/datastore_mad/remotes/iscsi/iscsi.conf"
|
||||
|
||||
DATASTORE_DRIVER_LVM_SCRIPTS="src/datastore_mad/remotes/lvm/cp \
|
||||
src/datastore_mad/remotes/lvm/mkfs \
|
||||
src/datastore_mad/remotes/lvm/stat \
|
||||
src/datastore_mad/remotes/lvm/rm \
|
||||
src/datastore_mad/remotes/lvm/clone \
|
||||
src/datastore_mad/remotes/lvm/lvm.conf"
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
|
@ -34,6 +34,8 @@
|
||||
<xs:element name="SIZE" type="xs:integer"/>
|
||||
<xs:element name="STATE" type="xs:integer"/>
|
||||
<xs:element name="RUNNING_VMS" type="xs:integer"/>
|
||||
<xs:element name="CLONING_OPS" type="xs:integer"/>
|
||||
<xs:element name="CLONING_ID" type="xs:integer"/>
|
||||
<xs:element name="DATASTORE_ID" type="xs:integer"/>
|
||||
<xs:element name="DATASTORE" type="xs:string"/>
|
||||
<xs:element name="TEMPLATE" type="xs:anyType"/>
|
||||
|
@ -96,6 +96,22 @@ cmd=CommandParser::CmdParser.new(ARGV) do
|
||||
end
|
||||
end
|
||||
|
||||
clone_desc = <<-EOT.unindent
|
||||
Creates a new Image from an existing one
|
||||
EOT
|
||||
|
||||
command :clone, clone_desc, :imageid, :name do
|
||||
helper.perform_action(args[0],options,"cloned") do |image|
|
||||
res = image.clone(args[1])
|
||||
|
||||
if !OpenNebula.is_error?(res)
|
||||
puts "ID: #{res}"
|
||||
else
|
||||
puts res.message
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
delete_desc = <<-EOT.unindent
|
||||
Deletes the given Image
|
||||
EOT
|
||||
|
@ -98,6 +98,8 @@ cmd=CommandParser::CmdParser.new(ARGV) do
|
||||
|
||||
if !OpenNebula.is_error?(res)
|
||||
puts "ID: #{res}"
|
||||
else
|
||||
puts res.message
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -59,6 +59,18 @@ class EC2QueryServer < CloudServer
|
||||
'unkn' => :terminated
|
||||
}
|
||||
|
||||
EC2_IMAGE_STATES={
|
||||
"INIT" => "pending",
|
||||
"READY" => "available",
|
||||
"USED" => "available",
|
||||
"DISABLED" => nil,
|
||||
"LOCKED" => "pending",
|
||||
"ERROR" => "failed",
|
||||
"CLONE" => "available",
|
||||
"DELETE" => nil,
|
||||
"USED_PERS" => "available"
|
||||
}
|
||||
|
||||
###########################################################################
|
||||
|
||||
def initialize(client, oneadmin_client, config, logger)
|
||||
@ -251,6 +263,10 @@ class EC2QueryServer < CloudServer
|
||||
<name>#{ec2_state[:name]}</name>"
|
||||
end
|
||||
|
||||
def render_image_state(image)
|
||||
EC2_IMAGE_STATES[image.state_str]
|
||||
end
|
||||
|
||||
def render_launch_time(vm)
|
||||
return "<launchTime>#{Time.at(vm["STIME"].to_i).xmlschema}</launchTime>"
|
||||
end
|
||||
|
@ -1,26 +1,20 @@
|
||||
<?xml version="1.0"?>
|
||||
<DescribeImagesResponse xmlns="http://ec2.amazonaws.com/doc/<%=erb_version%>/">
|
||||
<imagesSet>
|
||||
<% impool.each do |im| %>
|
||||
<item>
|
||||
<imageId>ami-<%= sprintf('%08i', im.id) %></imageId>
|
||||
<imageLocation><%= im['SOURCE'].split('/').last %></imageLocation>
|
||||
<% if im['STATE'] == '3' || im['STATE'] == '5' %>
|
||||
<imageState>failed</imageState>
|
||||
<% elsif im['STATE'] == '1' || im['STATE'] == '2' %>
|
||||
<imageState>available</imageState>
|
||||
<% elsif im['STATE'] == '4'%>
|
||||
<imageState>pending</imageState>
|
||||
<% end %>
|
||||
<imageOwnerId><%= im['UNAME'] %></imageOwnerId>
|
||||
<% if im['PUBLIC'] == '0' %>
|
||||
<isPublic>false</isPublic>
|
||||
<% elsif im['PUBLIC'] == '1' %>
|
||||
<isPublic>true</isPublic>
|
||||
<% end %>
|
||||
<architecture>i386</architecture>
|
||||
<imageType>machine</imageType>
|
||||
</item>
|
||||
<% end %>
|
||||
</imagesSet>
|
||||
<DescribeImagesResponse xmlns="http://ec2.amazonaws.com/doc/<%=erb_version%>/">
|
||||
<imagesSet>
|
||||
<% impool.each do |im| %>
|
||||
<% if state_image = render_image_state(im) %>
|
||||
<item>
|
||||
<imageId>ami-<%= sprintf('%08i', im.id) %></imageId>
|
||||
<imageLocation><%= im['SOURCE'].split('/').last %></imageLocation>
|
||||
<imageState><%= state_image %></imageState>
|
||||
<imageOwnerId><%= im['UNAME'] %></imageOwnerId>
|
||||
<isPublic><%= im.public? ? "true" : "false" %></isPublic>
|
||||
<architecture>i386</architecture>
|
||||
<imageType>machine</imageType>
|
||||
</item>
|
||||
<% else
|
||||
next
|
||||
end
|
||||
end %>
|
||||
</imagesSet>
|
||||
</DescribeImagesResponse>
|
||||
|
@ -44,11 +44,12 @@ class DatastoreDriver < OpenNebulaDriver
|
||||
|
||||
# Image Driver Protocol constants
|
||||
ACTION = {
|
||||
:cp => "CP",
|
||||
:rm => "RM",
|
||||
:mkfs => "MKFS",
|
||||
:log => "LOG",
|
||||
:stat => "STAT"
|
||||
:cp => "CP",
|
||||
:rm => "RM",
|
||||
:mkfs => "MKFS",
|
||||
:log => "LOG",
|
||||
:stat => "STAT",
|
||||
:clone => "CLONE"
|
||||
}
|
||||
|
||||
# Register default actions for the protocol
|
||||
@ -61,7 +62,8 @@ class DatastoreDriver < OpenNebulaDriver
|
||||
ACTION[:stat] => nil,
|
||||
ACTION[:cp] => nil,
|
||||
ACTION[:rm] => nil,
|
||||
ACTION[:mkfs] => nil
|
||||
ACTION[:mkfs] => nil,
|
||||
ACTION[:clone]=> nil
|
||||
}
|
||||
}.merge!(options)
|
||||
|
||||
@ -80,7 +82,8 @@ class DatastoreDriver < OpenNebulaDriver
|
||||
register_action(ACTION[:cp].to_sym, method("cp"))
|
||||
register_action(ACTION[:rm].to_sym, method("rm"))
|
||||
register_action(ACTION[:mkfs].to_sym, method("mkfs"))
|
||||
register_action(ACTION[:stat].to_sym, method("stat"))
|
||||
register_action(ACTION[:stat].to_sym, method("stat"))
|
||||
register_action(ACTION[:clone].to_sym,method("clone"))
|
||||
end
|
||||
|
||||
############################################################################
|
||||
@ -107,6 +110,11 @@ class DatastoreDriver < OpenNebulaDriver
|
||||
do_image_action(id, ds, :stat, "#{drv_message} #{id}")
|
||||
end
|
||||
|
||||
def clone(id, drv_message)
|
||||
ds = get_ds_type(drv_message)
|
||||
do_image_action(id, ds, :clone, "#{drv_message} #{id}")
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def is_available?(ds, id, action)
|
||||
|
78
src/datastore_mad/remotes/common/clone
Executable file
78
src/datastore_mad/remotes/common/clone
Executable file
@ -0,0 +1,78 @@
|
||||
#!/bin/bash
|
||||
|
||||
# -------------------------------------------------------------------------- #
|
||||
# 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. #
|
||||
#--------------------------------------------------------------------------- #
|
||||
|
||||
###############################################################################
|
||||
# This script is used to copy a VM image (SRC) to the image repository as DST
|
||||
# Several SRC types are supported
|
||||
###############################################################################
|
||||
|
||||
# -------- Set up the environment to source common tools & conf ------------
|
||||
|
||||
if [ -z "${ONE_LOCATION}" ]; then
|
||||
LIB_LOCATION=/usr/lib/one
|
||||
else
|
||||
LIB_LOCATION=$ONE_LOCATION/lib
|
||||
fi
|
||||
|
||||
. $LIB_LOCATION/sh/scripts_common.sh
|
||||
|
||||
DRIVER_PATH=$(dirname $0)
|
||||
source ${DRIVER_PATH}/../libfs.sh
|
||||
|
||||
# -------- Get cp and datastore arguments from OpenNebula core ------------
|
||||
|
||||
DRV_ACTION=$1
|
||||
ID=$2
|
||||
|
||||
XPATH="${DRIVER_PATH}/../xpath.rb -b $DRV_ACTION"
|
||||
|
||||
unset i XPATH_ELEMENTS
|
||||
|
||||
while IFS= read -r -d '' element; do
|
||||
XPATH_ELEMENTS[i++]="$element"
|
||||
done < <($XPATH /DS_DRIVER_ACTION_DATA/DATASTORE/BASE_PATH \
|
||||
/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/UMASK \
|
||||
/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/DS_MAD \
|
||||
/DS_DRIVER_ACTION_DATA/IMAGE/PATH)
|
||||
|
||||
BASE_PATH="${XPATH_ELEMENTS[0]}"
|
||||
UMASK="${XPATH_ELEMENTS[1]}"
|
||||
DS_MAD="${XPATH_ELEMENTS[2]}"
|
||||
SRC="${XPATH_ELEMENTS[3]}"
|
||||
|
||||
mkdir -p "$BASE_PATH"
|
||||
set_up_datastore "$BASE_PATH" "$RESTRICTED_DIRS" "$SAFE_DIRS" "$UMASK"
|
||||
|
||||
DST=`generate_image_path`
|
||||
|
||||
case "$DS_MAD" in
|
||||
vmware)
|
||||
CP_FLAGS="-r"
|
||||
;;
|
||||
*)
|
||||
CP_FLAGS="-f"
|
||||
;;
|
||||
esac
|
||||
|
||||
# ------------ Copy the image to the repository -------------
|
||||
|
||||
log "Copying local image $SRC to the image repository"
|
||||
|
||||
exec_and_log "cp $CP_FLAGS $SRC $DST" "Error copying $SRC to $DST"
|
||||
|
||||
echo "$DST"
|
19
src/datastore_mad/remotes/dummy/clone
Executable file
19
src/datastore_mad/remotes/dummy/clone
Executable file
@ -0,0 +1,19 @@
|
||||
#!/bin/sh
|
||||
|
||||
# -------------------------------------------------------------------------- #
|
||||
# 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. #
|
||||
#--------------------------------------------------------------------------- #
|
||||
|
||||
echo "dummy_path"
|
1
src/datastore_mad/remotes/fs/clone
Symbolic link
1
src/datastore_mad/remotes/fs/clone
Symbolic link
@ -0,0 +1 @@
|
||||
../common/clone
|
94
src/datastore_mad/remotes/iscsi/clone
Executable file
94
src/datastore_mad/remotes/iscsi/clone
Executable file
@ -0,0 +1,94 @@
|
||||
#!/bin/bash
|
||||
|
||||
# -------------------------------------------------------------------------- #
|
||||
# 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. #
|
||||
#--------------------------------------------------------------------------- #
|
||||
|
||||
###############################################################################
|
||||
# This script is used to copy a VM image (SRC) to the image repository as DST
|
||||
# Several SRC types are supported
|
||||
###############################################################################
|
||||
# -------- Set up the environment to source common tools & conf ------------
|
||||
if [ -z "${ONE_LOCATION}" ]; then
|
||||
LIB_LOCATION=/usr/lib/one
|
||||
else
|
||||
LIB_LOCATION=$ONE_LOCATION/lib
|
||||
fi
|
||||
|
||||
. $LIB_LOCATION/sh/scripts_common.sh
|
||||
|
||||
DRIVER_PATH=$(dirname $0)
|
||||
source ${DRIVER_PATH}/../libfs.sh
|
||||
source ${DRIVER_PATH}/iscsi.conf
|
||||
|
||||
# -------- Get cp and datastore arguments from OpenNebula core ------------
|
||||
|
||||
DRV_ACTION=$1
|
||||
ID=$2
|
||||
|
||||
XPATH="${DRIVER_PATH}/../xpath.rb -b $DRV_ACTION"
|
||||
|
||||
unset i XPATH_ELEMENTS
|
||||
|
||||
while IFS= read -r -d '' element; do
|
||||
XPATH_ELEMENTS[i++]="$element"
|
||||
done < <($XPATH /DS_DRIVER_ACTION_DATA/DATASTORE/BASE_PATH \
|
||||
/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/RESTRICTED_DIRS \
|
||||
/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/SAFE_DIRS \
|
||||
/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/UMASK \
|
||||
/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/HOST \
|
||||
/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VG_NAME \
|
||||
/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/BASE_IQN \
|
||||
/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/BASE_TID \
|
||||
/DS_DRIVER_ACTION_DATA/IMAGE/PATH \
|
||||
/DS_DRIVER_ACTION_DATA/IMAGE/SIZE)
|
||||
|
||||
BASE_PATH="${XPATH_ELEMENTS[0]}"
|
||||
RESTRICTED_DIRS="${XPATH_ELEMENTS[1]}"
|
||||
SAFE_DIRS="${XPATH_ELEMENTS[2]}"
|
||||
UMASK="${XPATH_ELEMENTS[3]}"
|
||||
DST_HOST="${XPATH_ELEMENTS[4]:-$HOST}"
|
||||
VG_NAME="${XPATH_ELEMENTS[5]:-$VG_NAME}"
|
||||
BASE_IQN="${XPATH_ELEMENTS[6]:-$BASE_IQN}"
|
||||
BASE_TID="${XPATH_ELEMENTS[7]:-$BASE_TID}"
|
||||
SRC="${XPATH_ELEMENTS[8]}"
|
||||
SIZE="${XPATH_ELEMENTS[9]}"
|
||||
|
||||
set_up_datastore "$BASE_PATH" "$RESTRICTED_DIRS" "$SAFE_DIRS" "$UMASK"
|
||||
|
||||
LV_NAME="lv-one-${ID}"
|
||||
IQN="$BASE_IQN:$DST_HOST.$VG_NAME.$LV_NAME"
|
||||
DEV="/dev/$VG_NAME/$LV_NAME"
|
||||
|
||||
let TID=ID+BASE_TID
|
||||
|
||||
LV_SRC=$(echo $SRC|awk -F. '{print $NF}')
|
||||
DEV_SRC="/dev/$VG_NAME/$LV_SRC"
|
||||
|
||||
CLONE_CMD=$(cat <<EOF
|
||||
set -e
|
||||
$SUDO $LVCREATE -L${SIZE}M ${VG_NAME} -n ${LV_NAME}
|
||||
$SUDO $DD if=$DEV_SRC of=$DEV bs=64k
|
||||
|
||||
$SUDO $(tgtadm_target_new "$TID" "$IQN")
|
||||
$SUDO $(tgtadm_target_bind_all "$TID")
|
||||
$SUDO $(tgtadm_logicalunit_new "$TID" "$DEV")
|
||||
EOF
|
||||
)
|
||||
|
||||
ssh_exec_and_log "$DST_HOST" "$CLONE_CMD" \
|
||||
"Error cloning $DEV_SRC to $DEV in $DST_HOST"
|
||||
|
||||
echo "$IQN"
|
84
src/datastore_mad/remotes/lvm/clone
Executable file
84
src/datastore_mad/remotes/lvm/clone
Executable file
@ -0,0 +1,84 @@
|
||||
#!/bin/bash
|
||||
|
||||
# -------------------------------------------------------------------------- #
|
||||
# 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. #
|
||||
#--------------------------------------------------------------------------- #
|
||||
|
||||
###############################################################################
|
||||
# This script is used to copy a VM image (SRC) to the image repository as DST
|
||||
# Several SRC types are supported
|
||||
###############################################################################
|
||||
# -------- Set up the environment to source common tools & conf ------------
|
||||
if [ -z "${ONE_LOCATION}" ]; then
|
||||
LIB_LOCATION=/usr/lib/one
|
||||
else
|
||||
LIB_LOCATION=$ONE_LOCATION/lib
|
||||
fi
|
||||
|
||||
. $LIB_LOCATION/sh/scripts_common.sh
|
||||
|
||||
DRIVER_PATH=$(dirname $0)
|
||||
source ${DRIVER_PATH}/../libfs.sh
|
||||
source ${DRIVER_PATH}/lvm.conf
|
||||
|
||||
# -------- Get cp and datastore arguments from OpenNebula core ------------
|
||||
|
||||
DRV_ACTION=$1
|
||||
ID=$2
|
||||
|
||||
XPATH="${DRIVER_PATH}/../xpath.rb -b $DRV_ACTION"
|
||||
|
||||
unset i XPATH_ELEMENTS
|
||||
|
||||
while IFS= read -r -d '' element; do
|
||||
XPATH_ELEMENTS[i++]="$element"
|
||||
done < <($XPATH /DS_DRIVER_ACTION_DATA/DATASTORE/BASE_PATH \
|
||||
/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/UMASK \
|
||||
/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/HOST \
|
||||
/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VG_NAME \
|
||||
/DS_DRIVER_ACTION_DATA/IMAGE/PATH \
|
||||
/DS_DRIVER_ACTION_DATA/IMAGE/SIZE)
|
||||
|
||||
BASE_PATH="${XPATH_ELEMENTS[0]}"
|
||||
UMASK="${XPATH_ELEMENTS[1]}"
|
||||
DST_HOST="${XPATH_ELEMENTS[2]:-$HOST}"
|
||||
VG_NAME="${XPATH_ELEMENTS[3]:-$VG_NAME}"
|
||||
SRC="${XPATH_ELEMENTS[4]}"
|
||||
SIZE="${XPATH_ELEMENTS[5]}"
|
||||
|
||||
SAFE_DIRS=""
|
||||
|
||||
SRC_HOST=`echo $SRC|cut -d. -f1`
|
||||
SRC_PATH=`echo $SRC|cut -d. -f2`
|
||||
|
||||
LV_SRC=$(echo $SRC_PATH|cut -d. -f2)
|
||||
DEV_SRC="/dev/$VG_NAME/$LV_SRC"
|
||||
|
||||
set_up_datastore "$BASE_PATH" "$RESTRICTED_DIRS" "$SAFE_DIRS" "$UMASK"
|
||||
|
||||
LV_NAME="lv-one-${ID}"
|
||||
LVM_SOURCE="$DST_HOST:$VG_NAME.$LV_NAME"
|
||||
DEV="/dev/$VG_NAME/$LV_NAME"
|
||||
|
||||
CLONE_CMD=$(cat <<EOF
|
||||
set -e
|
||||
$SUDO $LVCREATE -L${SIZE}M ${VG_NAME} -n ${LV_NAME}
|
||||
$SUDO $DD if=$DEV_SRC of=$DEV bs=64k
|
||||
EOF
|
||||
)
|
||||
|
||||
ssh_exec_and_log "$DST_HOST" "$CLONE_CMD" "Error registering $DST_HOST:$DEV"
|
||||
|
||||
echo "$LVM_SOURCE"
|
1
src/datastore_mad/remotes/vmware/clone
Symbolic link
1
src/datastore_mad/remotes/vmware/clone
Symbolic link
@ -0,0 +1 @@
|
||||
../common/clone
|
@ -49,6 +49,8 @@ Image::Image(int _uid,
|
||||
size_mb(0),
|
||||
state(INIT),
|
||||
running_vms(0),
|
||||
cloning_ops(0),
|
||||
cloning_id(-1),
|
||||
ds_id(-1),
|
||||
ds_name("")
|
||||
{
|
||||
@ -334,6 +336,8 @@ string& Image::to_xml(string& xml) const
|
||||
"<SIZE>" << size_mb << "</SIZE>" <<
|
||||
"<STATE>" << state << "</STATE>" <<
|
||||
"<RUNNING_VMS>" << running_vms << "</RUNNING_VMS>" <<
|
||||
"<CLONING_OPS>" << cloning_ops << "</CLONING_OPS>" <<
|
||||
"<CLONING_ID>" << cloning_id << "</CLONING_ID>" <<
|
||||
"<DATASTORE_ID>" << ds_id << "</DATASTORE_ID>"<<
|
||||
"<DATASTORE>" << ds_name << "</DATASTORE>" <<
|
||||
obj_template->to_xml(template_xml) <<
|
||||
@ -360,27 +364,29 @@ int Image::from_xml(const string& xml)
|
||||
update_from_str(xml);
|
||||
|
||||
// Get class base attributes
|
||||
rc += xpath(oid, "/IMAGE/ID", -1);
|
||||
rc += xpath(uid, "/IMAGE/UID", -1);
|
||||
rc += xpath(gid, "/IMAGE/GID", -1);
|
||||
rc += xpath(oid, "/IMAGE/ID", -1);
|
||||
rc += xpath(uid, "/IMAGE/UID", -1);
|
||||
rc += xpath(gid, "/IMAGE/GID", -1);
|
||||
|
||||
rc += xpath(uname, "/IMAGE/UNAME", "not_found");
|
||||
rc += xpath(gname, "/IMAGE/GNAME", "not_found");
|
||||
rc += xpath(uname, "/IMAGE/UNAME", "not_found");
|
||||
rc += xpath(gname, "/IMAGE/GNAME", "not_found");
|
||||
|
||||
rc += xpath(name, "/IMAGE/NAME", "not_found");
|
||||
rc += xpath(name, "/IMAGE/NAME", "not_found");
|
||||
|
||||
rc += xpath(int_type, "/IMAGE/TYPE", 0);
|
||||
rc += xpath(int_disk_type, "/IMAGE/DISK_TYPE", 0);
|
||||
rc += xpath(persistent_img, "/IMAGE/PERSISTENT", 0);
|
||||
rc += xpath(regtime, "/IMAGE/REGTIME", 0);
|
||||
rc += xpath(int_type, "/IMAGE/TYPE", 0);
|
||||
rc += xpath(int_disk_type, "/IMAGE/DISK_TYPE", 0);
|
||||
rc += xpath(persistent_img, "/IMAGE/PERSISTENT",0);
|
||||
rc += xpath(regtime, "/IMAGE/REGTIME", 0);
|
||||
|
||||
rc += xpath(source, "/IMAGE/SOURCE", "not_found");
|
||||
rc += xpath(size_mb, "/IMAGE/SIZE", 0);
|
||||
rc += xpath(int_state, "/IMAGE/STATE", 0);
|
||||
rc += xpath(running_vms, "/IMAGE/RUNNING_VMS", -1);
|
||||
rc += xpath(source, "/IMAGE/SOURCE", "not_found");
|
||||
rc += xpath(size_mb, "/IMAGE/SIZE", 0);
|
||||
rc += xpath(int_state, "/IMAGE/STATE", 0);
|
||||
rc += xpath(running_vms, "/IMAGE/RUNNING_VMS", -1);
|
||||
rc += xpath(cloning_ops, "/IMAGE/CLONING_OPS", -1);
|
||||
rc += xpath(cloning_id, "/IMAGE/CLONING_ID", -1);
|
||||
|
||||
rc += xpath(ds_id, "/IMAGE/DATASTORE_ID", -1);
|
||||
rc += xpath(ds_name,"/IMAGE/DATASTORE", "not_found");
|
||||
rc += xpath(ds_id, "/IMAGE/DATASTORE_ID", -1);
|
||||
rc += xpath(ds_name, "/IMAGE/DATASTORE", "not_found");
|
||||
|
||||
// Permissions
|
||||
rc += perms_from_xml();
|
||||
@ -541,6 +547,33 @@ int Image::set_type(string& _type)
|
||||
/* ------------------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
ImageTemplate * Image::clone_template(const string& new_name) const
|
||||
{
|
||||
|
||||
ImageTemplate * tmpl = new ImageTemplate(
|
||||
*(static_cast<ImageTemplate *>(obj_template)));
|
||||
|
||||
tmpl->replace("NAME", new_name);
|
||||
tmpl->replace("TYPE", type_to_str(type));
|
||||
tmpl->replace("PATH", source);
|
||||
tmpl->replace("FSTYPE", fs_type);
|
||||
tmpl->replace("SIZE", size_mb);
|
||||
|
||||
if ( isPersistent() )
|
||||
{
|
||||
tmpl->replace("PERSISTENT", "YES");
|
||||
}
|
||||
else
|
||||
{
|
||||
tmpl->replace("PERSISTENT", "NO");
|
||||
}
|
||||
|
||||
return tmpl;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
Image::ImageType Image::str_to_type(string& str_type)
|
||||
{
|
||||
Image::ImageType it = OS;
|
||||
@ -566,4 +599,4 @@ Image::ImageType Image::str_to_type(string& str_type)
|
||||
}
|
||||
|
||||
return it;
|
||||
}
|
||||
}
|
||||
|
@ -96,32 +96,27 @@ int ImageManager::acquire_image(Image *img, string& error)
|
||||
ipool->update(img);
|
||||
break;
|
||||
|
||||
case Image::USED:
|
||||
if (img->isPersistent())
|
||||
{
|
||||
error = "Cannot acquire persistent image, it is already in use";
|
||||
rc = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
img->inc_running();
|
||||
ipool->update(img);
|
||||
}
|
||||
case Image::USED_PERS:
|
||||
error = "Cannot acquire persistent image, it is already in use";
|
||||
rc = -1;
|
||||
break;
|
||||
|
||||
case Image::USED:
|
||||
img->inc_running();
|
||||
ipool->update(img);
|
||||
break;
|
||||
|
||||
case Image::INIT:
|
||||
case Image::DISABLED:
|
||||
error = "Cannot acquire image, it is disabled";
|
||||
rc = -1;
|
||||
break;
|
||||
case Image::LOCKED:
|
||||
error = "Cannot acquire image, it is locked";
|
||||
rc = -1;
|
||||
break;
|
||||
case Image::ERROR:
|
||||
error = "Cannot acquire image, it is in an error state";
|
||||
rc = -1;
|
||||
break;
|
||||
default:
|
||||
case Image::DELETE:
|
||||
case Image::CLONE:
|
||||
ostringstream oss;
|
||||
oss << "Cannot acquire image in state: "
|
||||
<< Image::state_to_str(img->get_state());
|
||||
|
||||
error = oss.str();
|
||||
rc = -1;
|
||||
break;
|
||||
}
|
||||
@ -134,8 +129,6 @@ int ImageManager::acquire_image(Image *img, string& error)
|
||||
|
||||
void ImageManager::release_image(int iid, bool failed)
|
||||
{
|
||||
int rvms;
|
||||
|
||||
Image * img;
|
||||
|
||||
ostringstream disk_file;
|
||||
@ -149,21 +142,25 @@ void ImageManager::release_image(int iid, bool failed)
|
||||
|
||||
switch (img->get_state())
|
||||
{
|
||||
case Image::USED:
|
||||
rvms = img->dec_running();
|
||||
case Image::USED_PERS:
|
||||
img->dec_running();
|
||||
|
||||
if (img->isPersistent())
|
||||
if (failed == true)
|
||||
{
|
||||
if (failed == true)
|
||||
{
|
||||
img->set_state(Image::ERROR);
|
||||
}
|
||||
else
|
||||
{
|
||||
img->set_state(Image::READY);
|
||||
}
|
||||
img->set_state(Image::ERROR);
|
||||
}
|
||||
else if ( rvms == 0 )
|
||||
else
|
||||
{
|
||||
img->set_state(Image::READY);
|
||||
}
|
||||
|
||||
ipool->update(img);
|
||||
|
||||
img->unlock();
|
||||
break;
|
||||
|
||||
case Image::USED:
|
||||
if ( img->dec_running() == 0 && img->get_cloning() == 0 )
|
||||
{
|
||||
img->set_state(Image::READY);
|
||||
}
|
||||
@ -173,8 +170,8 @@ void ImageManager::release_image(int iid, bool failed)
|
||||
img->unlock();
|
||||
break;
|
||||
|
||||
case Image::LOCKED: //SAVE_AS images are LOCKED till released
|
||||
if ( img->isSaving() )
|
||||
case Image::LOCKED:
|
||||
if ( img->isSaving() ) //SAVE_AS images are LOCKED till released
|
||||
{
|
||||
if (failed == true)
|
||||
{
|
||||
@ -189,20 +186,84 @@ void ImageManager::release_image(int iid, bool failed)
|
||||
}
|
||||
else
|
||||
{
|
||||
NebulaLog::log("ImM",Log::ERROR,
|
||||
"Trying to release image in wrong state.");
|
||||
stringstream oss;
|
||||
oss << "Releasing image in wrong state: "
|
||||
<< Image::state_to_str(img->get_state());
|
||||
|
||||
NebulaLog::log("ImM", Log::ERROR, oss.str());
|
||||
}
|
||||
|
||||
img->unlock();
|
||||
break;
|
||||
break;
|
||||
|
||||
case Image::CLONE:
|
||||
case Image::DELETE:
|
||||
case Image::INIT:
|
||||
case Image::DISABLED:
|
||||
case Image::READY:
|
||||
case Image::ERROR:
|
||||
ostringstream oss;
|
||||
oss << "Releasing image in wrong state: "
|
||||
<< Image::state_to_str(img->get_state());
|
||||
|
||||
NebulaLog::log("ImM", Log::ERROR, oss.str());
|
||||
|
||||
img->unlock();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
void ImageManager::release_cloning_image(int iid)
|
||||
{
|
||||
Image * img;
|
||||
|
||||
ostringstream disk_file;
|
||||
|
||||
img = ipool->get(iid,true);
|
||||
|
||||
if ( img == 0 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
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 )
|
||||
{
|
||||
img->set_state(Image::READY);
|
||||
}
|
||||
|
||||
ipool->update(img);
|
||||
img->unlock();
|
||||
break;
|
||||
|
||||
case Image::DELETE:
|
||||
case Image::INIT:
|
||||
case Image::DISABLED:
|
||||
case Image::READY:
|
||||
case Image::ERROR:
|
||||
NebulaLog::log("ImM",Log::ERROR,
|
||||
"Trying to release image in wrong state.");
|
||||
default:
|
||||
img->unlock();
|
||||
case Image::USED_PERS:
|
||||
case Image::LOCKED:
|
||||
|
||||
ostringstream oss;
|
||||
oss << "Releasing image in wrong state: "
|
||||
<< Image::state_to_str(img->get_state());
|
||||
|
||||
NebulaLog::log("ImM", Log::ERROR, oss.str());
|
||||
|
||||
img->unlock();
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -272,8 +333,10 @@ int ImageManager::delete_image(int iid, const string& ds_data)
|
||||
int size;
|
||||
int ds_id;
|
||||
|
||||
int uid;
|
||||
int gid;
|
||||
int uid;
|
||||
int gid;
|
||||
int cloning_id = -1;
|
||||
|
||||
Group* group;
|
||||
User * user;
|
||||
|
||||
@ -281,6 +344,7 @@ int ImageManager::delete_image(int iid, const string& ds_data)
|
||||
UserPool * upool = nd.get_upool();
|
||||
GroupPool* gpool = nd.get_gpool();
|
||||
|
||||
|
||||
img = ipool->get(iid,true);
|
||||
|
||||
if ( img == 0 )
|
||||
@ -299,17 +363,26 @@ int ImageManager::delete_image(int iid, const string& ds_data)
|
||||
break;
|
||||
|
||||
case Image::USED:
|
||||
case Image::USED_PERS:
|
||||
case Image::CLONE:
|
||||
img->unlock();
|
||||
return -1; //Cannot remove images in use
|
||||
break;
|
||||
|
||||
case Image::INIT:
|
||||
case Image::DISABLED:
|
||||
case Image::LOCKED:
|
||||
case Image::ERROR:
|
||||
case Image::DELETE:
|
||||
break;
|
||||
|
||||
case Image::LOCKED:
|
||||
cloning_id = img->get_cloning_id();
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
/* ------------------- Send RM operation request to the DS -------------- */
|
||||
|
||||
const ImageManagerDriver* imd = get();
|
||||
|
||||
if ( imd == 0 )
|
||||
@ -382,6 +455,113 @@ int ImageManager::delete_image(int iid, const string& ds_data)
|
||||
}
|
||||
}
|
||||
|
||||
/* --------------- Update cloning image if needed ----------------------- */
|
||||
|
||||
if ( cloning_id != -1 )
|
||||
{
|
||||
release_cloning_image(cloning_id);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
int ImageManager::clone_image(int new_id,
|
||||
int cloning_id,
|
||||
const string& ds_data,
|
||||
string& error)
|
||||
{
|
||||
const ImageManagerDriver* imd = get();
|
||||
|
||||
ostringstream oss;
|
||||
Image * img;
|
||||
|
||||
string path;
|
||||
string img_tmpl;
|
||||
string* drv_msg;
|
||||
|
||||
if ( imd == 0 )
|
||||
{
|
||||
error = "Could not get datastore driver";
|
||||
|
||||
NebulaLog::log("ImM", Log::ERROR, error);
|
||||
return -1;
|
||||
}
|
||||
|
||||
img = ipool->get(cloning_id, true);
|
||||
|
||||
if (img == 0)
|
||||
{
|
||||
error = "Cannot clone image, it does not exist";
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch(img->get_state())
|
||||
{
|
||||
case Image::READY:
|
||||
img->inc_cloning();
|
||||
|
||||
if (img->isPersistent())
|
||||
{
|
||||
img->set_state(Image::CLONE);
|
||||
}
|
||||
else
|
||||
{
|
||||
img->set_state(Image::USED);
|
||||
}
|
||||
|
||||
ipool->update(img);
|
||||
|
||||
img->unlock();
|
||||
break;
|
||||
|
||||
case Image::USED_PERS:
|
||||
img->inc_cloning();
|
||||
|
||||
ipool->update(img);
|
||||
|
||||
img->unlock();
|
||||
break;
|
||||
|
||||
case Image::USED:
|
||||
case Image::CLONE:
|
||||
case Image::INIT:
|
||||
case Image::DISABLED:
|
||||
case Image::ERROR:
|
||||
case Image::DELETE:
|
||||
case Image::LOCKED:
|
||||
ostringstream oss;
|
||||
oss << "Cannot clone image in state: "
|
||||
<< Image::state_to_str(img->get_state());
|
||||
|
||||
error = oss.str();
|
||||
img->unlock();
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
|
||||
img = ipool->get(new_id,true);
|
||||
|
||||
if (img == 0) //TODO: Rollback clonning counter
|
||||
{
|
||||
error = "Target image deleted during clonning operation";
|
||||
return -1;
|
||||
}
|
||||
|
||||
drv_msg = format_message(img->to_xml(img_tmpl), ds_data);
|
||||
|
||||
imd->clone(img->get_oid(), *drv_msg);
|
||||
|
||||
oss << "Cloning image " << img->get_path()
|
||||
<<" to repository as image "<<img->get_oid();
|
||||
|
||||
NebulaLog::log("ImM", Log::INFO, oss);
|
||||
|
||||
img->unlock();
|
||||
|
||||
delete drv_msg;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -38,6 +38,17 @@ void ImageManagerDriver::cp(int oid,
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
void ImageManagerDriver::clone(int oid,
|
||||
const string& drv_msg) const
|
||||
{
|
||||
ostringstream os;
|
||||
|
||||
os << "CLONE " << oid << " " << drv_msg << endl;
|
||||
|
||||
write(os);
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
void ImageManagerDriver::stat(int oid,
|
||||
const string& drv_msg) const
|
||||
{
|
||||
@ -115,6 +126,7 @@ static void cp_action(istringstream& is,
|
||||
int id,
|
||||
const string& result)
|
||||
{
|
||||
int cloning_id;
|
||||
string source;
|
||||
string info;
|
||||
|
||||
@ -150,14 +162,26 @@ static void cp_action(istringstream& is,
|
||||
|
||||
ipool->update(image);
|
||||
|
||||
cloning_id = image->get_cloning_id();
|
||||
|
||||
image->clear_cloning_id();
|
||||
|
||||
image->unlock();
|
||||
|
||||
NebulaLog::log("ImM", Log::INFO, "Image copied and ready to use.");
|
||||
|
||||
if ( cloning_id != -1 ) // An Image clone operation finished
|
||||
{
|
||||
Nebula& nd = Nebula::instance();
|
||||
ImageManager * im = nd.get_imagem();
|
||||
|
||||
im ->release_cloning_image(cloning_id);
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
error:
|
||||
oss << "Error copying image in the repository";
|
||||
oss << "Error copying image in the datastore";
|
||||
|
||||
getline(is, info);
|
||||
|
||||
@ -180,6 +204,88 @@ error:
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
static void clone_action(istringstream& is,
|
||||
ImagePool* ipool,
|
||||
int id,
|
||||
const string& result)
|
||||
{
|
||||
int cloning_id;
|
||||
string source;
|
||||
string info;
|
||||
|
||||
Image * image;
|
||||
|
||||
ostringstream oss;
|
||||
|
||||
Nebula& nd = Nebula::instance();
|
||||
ImageManager * im = nd.get_imagem();
|
||||
|
||||
image = ipool->get(id, true);
|
||||
|
||||
if ( image == 0 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
cloning_id = image->get_cloning_id();
|
||||
|
||||
if ( result == "FAILURE" )
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
|
||||
if ( is.good() )
|
||||
{
|
||||
is >> source >> ws;
|
||||
}
|
||||
|
||||
if ( is.fail() )
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
|
||||
image->set_source(source);
|
||||
|
||||
image->set_state(Image::READY);
|
||||
|
||||
ipool->update(image);
|
||||
|
||||
image->clear_cloning_id();
|
||||
|
||||
image->unlock();
|
||||
|
||||
NebulaLog::log("ImM", Log::INFO, "Image cloned and ready to use.");
|
||||
|
||||
im ->release_cloning_image(cloning_id);
|
||||
|
||||
return;
|
||||
|
||||
error:
|
||||
oss << "Error cloning image ";
|
||||
|
||||
getline(is, info);
|
||||
|
||||
if (!info.empty() && (info[0] != '-'))
|
||||
{
|
||||
oss << ": " << info;
|
||||
}
|
||||
|
||||
NebulaLog::log("ImM", Log::ERROR, oss);
|
||||
|
||||
image->set_template_error_message(oss.str());
|
||||
image->set_state(Image::ERROR);
|
||||
|
||||
ipool->update(image);
|
||||
|
||||
image->unlock();
|
||||
|
||||
im ->release_cloning_image(cloning_id);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
static void mkfs_action(istringstream& is,
|
||||
ImagePool* ipool,
|
||||
int id,
|
||||
@ -371,13 +477,6 @@ error:
|
||||
|
||||
NebulaLog::log("ImM", Log::ERROR, oss);
|
||||
|
||||
image->set_template_error_message(oss.str());
|
||||
image->set_state(Image::ERROR);
|
||||
|
||||
ipool->update(image);
|
||||
|
||||
image->unlock();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@ -439,6 +538,10 @@ void ImageManagerDriver::protocol(
|
||||
{
|
||||
cp_action(is, ipool, id, result);
|
||||
}
|
||||
else if ( action == "CLONE" )
|
||||
{
|
||||
clone_action(is, ipool, id, result);
|
||||
}
|
||||
else if ( action == "MKFS" )
|
||||
{
|
||||
mkfs_action(is, ipool, id, result);
|
||||
|
@ -69,6 +69,7 @@ int ImagePool::allocate (
|
||||
const string& ds_name,
|
||||
Image::DiskType disk_type,
|
||||
const string& ds_data,
|
||||
int cloning_id,
|
||||
int * oid,
|
||||
string& error_str)
|
||||
{
|
||||
@ -106,6 +107,11 @@ int ImagePool::allocate (
|
||||
|
||||
img->disk_type = disk_type;
|
||||
|
||||
if ( cloning_id != -1 )
|
||||
{
|
||||
img->set_cloning_id(cloning_id);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Insert the Object in the pool & Register the image in the repository
|
||||
// ---------------------------------------------------------------------
|
||||
@ -116,11 +122,21 @@ int ImagePool::allocate (
|
||||
Nebula& nd = Nebula::instance();
|
||||
ImageManager * imagem = nd.get_imagem();
|
||||
|
||||
if ( imagem->register_image(*oid, ds_data) == -1 )
|
||||
if (cloning_id == -1)
|
||||
{
|
||||
error_str = "Failed to copy image to repository. "
|
||||
"Image left in ERROR state.";
|
||||
return -1;
|
||||
if ( imagem->register_image(*oid, ds_data) == -1 )
|
||||
{
|
||||
error_str = "Failed to copy image to repository. "
|
||||
"Image left in ERROR state.";
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (imagem->clone_image(*oid, cloning_id, ds_data, error_str) == -1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -318,12 +318,12 @@ function tgtadm_target_new {
|
||||
IQN="$2"
|
||||
|
||||
echo "$TGTADM --lld iscsi --op new --mode target --tid $ID "\
|
||||
"--targetname $IQN;"
|
||||
"--targetname $IQN"
|
||||
}
|
||||
|
||||
function tgtadm_target_bind_all {
|
||||
ID="$1"
|
||||
echo "$TGTADM --lld iscsi --op bind --mode target --tid $ID -I ALL"
|
||||
echo "$TGTADM --lld iscsi --op bind --mode target --tid $ID -I ALL"
|
||||
}
|
||||
|
||||
function tgtadm_logicalunit_new {
|
||||
|
@ -31,6 +31,8 @@ import org.w3c.dom.Node;
|
||||
*/
|
||||
public class ClusterPool extends Pool implements Iterable<Cluster>{
|
||||
|
||||
public static final int NONE_CLUSTER_ID = -1;
|
||||
|
||||
private static final String ELEMENT_NAME = "CLUSTER";
|
||||
private static final String INFO_METHOD = "clusterpool.info";
|
||||
|
||||
|
@ -18,6 +18,7 @@ package org.opennebula.client.datastore;
|
||||
import org.opennebula.client.Client;
|
||||
import org.opennebula.client.OneResponse;
|
||||
import org.opennebula.client.PoolElement;
|
||||
import org.opennebula.client.cluster.ClusterPool;
|
||||
import org.w3c.dom.Node;
|
||||
|
||||
/**
|
||||
@ -57,6 +58,21 @@ public class Datastore extends PoolElement
|
||||
// Static XML-RPC methods
|
||||
// =================================
|
||||
|
||||
/**
|
||||
* Allocates a new Datastore in OpenNebula.
|
||||
*
|
||||
* @param client XML-RPC Client.
|
||||
* @param description A string containing the template of the datastore.
|
||||
* @param clusterId Id of the cluster
|
||||
* @return If successful the message contains the associated
|
||||
* id generated for this Datastore.
|
||||
*/
|
||||
public static OneResponse allocate(Client client,
|
||||
String description, int clusterId)
|
||||
{
|
||||
return client.call(ALLOCATE, description, clusterId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocates a new Datastore in OpenNebula.
|
||||
*
|
||||
@ -67,7 +83,7 @@ public class Datastore extends PoolElement
|
||||
*/
|
||||
public static OneResponse allocate(Client client, String description)
|
||||
{
|
||||
return client.call(ALLOCATE, description);
|
||||
return allocate(client, description, ClusterPool.NONE_CLUSTER_ID);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -125,7 +141,7 @@ public class Datastore extends PoolElement
|
||||
|
||||
/**
|
||||
* Changes the owner/group
|
||||
*
|
||||
*
|
||||
* @param client XML-RPC Client.
|
||||
* @param id The id of the target datastore we want to modify.
|
||||
* @param uid The new owner user ID. Set it to -1 to leave the current one.
|
||||
@ -139,7 +155,7 @@ public class Datastore extends PoolElement
|
||||
|
||||
/**
|
||||
* Changes the datastore permissions
|
||||
*
|
||||
*
|
||||
* @param client XML-RPC Client.
|
||||
* @param id The id of the target datastore.
|
||||
* @param owner_u 1 to allow, 0 deny, -1 do not change
|
||||
@ -166,7 +182,7 @@ public class Datastore extends PoolElement
|
||||
|
||||
/**
|
||||
* Changes the permissions
|
||||
*
|
||||
*
|
||||
* @param client XML-RPC Client.
|
||||
* @param id The id of the target object.
|
||||
* @param octet Permissions octet, e.g. 640
|
||||
@ -179,7 +195,7 @@ public class Datastore extends PoolElement
|
||||
|
||||
/**
|
||||
* Changes the permissions
|
||||
*
|
||||
*
|
||||
* @param client XML-RPC Client.
|
||||
* @param id The id of the target object.
|
||||
* @param octet Permissions octed , e.g. 640
|
||||
@ -261,7 +277,7 @@ public class Datastore extends PoolElement
|
||||
|
||||
/**
|
||||
* Changes the owner/group
|
||||
*
|
||||
*
|
||||
* @param uid The new owner user ID. Set it to -1 to leave the current one.
|
||||
* @param gid The new group ID. Set it to -1 to leave the current one.
|
||||
* @return If an error occurs the error message contains the reason.
|
||||
@ -273,7 +289,7 @@ public class Datastore extends PoolElement
|
||||
|
||||
/**
|
||||
* Changes the owner
|
||||
*
|
||||
*
|
||||
* @param uid The new owner user ID.
|
||||
* @return If an error occurs the error message contains the reason.
|
||||
*/
|
||||
@ -284,7 +300,7 @@ public class Datastore extends PoolElement
|
||||
|
||||
/**
|
||||
* Changes the group
|
||||
*
|
||||
*
|
||||
* @param gid The new group ID.
|
||||
* @return If an error occurs the error message contains the reason.
|
||||
*/
|
||||
@ -295,7 +311,7 @@ public class Datastore extends PoolElement
|
||||
|
||||
/**
|
||||
* Changes the datastore permissions
|
||||
*
|
||||
*
|
||||
* @param owner_u 1 to allow, 0 deny, -1 do not change
|
||||
* @param owner_m 1 to allow, 0 deny, -1 do not change
|
||||
* @param owner_a 1 to allow, 0 deny, -1 do not change
|
||||
|
@ -36,9 +36,11 @@ public class Host extends PoolElement{
|
||||
private static final String MONITORING = METHOD_PREFIX + "monitoring";
|
||||
|
||||
private static final String[] HOST_STATES =
|
||||
{"INIT", "MONITORING_MONITORED", "MONITORED", "ERROR", "DISABLED",
|
||||
{"INIT", "MONITORING_MONITORED", "MONITORED", "ERROR", "DISABLED",
|
||||
"MONITORING_ERROR"};
|
||||
|
||||
private static final String[] SHORT_HOST_STATES =
|
||||
{"init", "update", "on", "err", "off", "retry"};
|
||||
|
||||
/**
|
||||
* Creates a new Host representation.
|
||||
@ -290,24 +292,8 @@ public class Host extends PoolElement{
|
||||
*/
|
||||
public String shortStateStr()
|
||||
{
|
||||
String st = stateStr();
|
||||
|
||||
if(st == null)
|
||||
return null;
|
||||
else if(st.equals("ERROR"))
|
||||
return "err";
|
||||
else if (st.equals("DISABLED"))
|
||||
return "off";
|
||||
else if (st.equals("INIT"))
|
||||
return "init";
|
||||
else if (st.equals("MONITORING_MONITORED"))
|
||||
return "update";
|
||||
else if (st.equals("MONITORED"))
|
||||
return "on";
|
||||
else if (st.equals("MONITORING_ERROR"))
|
||||
return "retry";
|
||||
|
||||
return "";
|
||||
int state = state();
|
||||
return state != -1 ? SHORT_HOST_STATES[state()] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -28,20 +28,23 @@ public class Image extends PoolElement
|
||||
{
|
||||
|
||||
private static final String METHOD_PREFIX = "image.";
|
||||
private static final String ALLOCATE = METHOD_PREFIX + "allocate";
|
||||
private static final String INFO = METHOD_PREFIX + "info";
|
||||
private static final String DELETE = METHOD_PREFIX + "delete";
|
||||
private static final String UPDATE = METHOD_PREFIX + "update";
|
||||
private static final String ENABLE = METHOD_PREFIX + "enable";
|
||||
private static final String CHOWN = METHOD_PREFIX + "chown";
|
||||
private static final String CHMOD = METHOD_PREFIX + "chmod";
|
||||
private static final String CHTYPE = METHOD_PREFIX + "chtype";
|
||||
private static final String ALLOCATE = METHOD_PREFIX + "allocate";
|
||||
private static final String INFO = METHOD_PREFIX + "info";
|
||||
private static final String DELETE = METHOD_PREFIX + "delete";
|
||||
private static final String UPDATE = METHOD_PREFIX + "update";
|
||||
private static final String ENABLE = METHOD_PREFIX + "enable";
|
||||
private static final String PERSISTENT = METHOD_PREFIX + "persistent";
|
||||
private static final String CHOWN = METHOD_PREFIX + "chown";
|
||||
private static final String CHMOD = METHOD_PREFIX + "chmod";
|
||||
private static final String CHTYPE = METHOD_PREFIX + "chtype";
|
||||
private static final String CLONE = METHOD_PREFIX + "clone";
|
||||
|
||||
private static final String[] IMAGE_STATES =
|
||||
{"INIT", "READY", "USED", "DISABLED"};
|
||||
{"INIT", "READY", "USED", "DISABLED", "LOCKED",
|
||||
"ERROR", "CLONE", "DELETE", "USED_PERS"};
|
||||
|
||||
private static final String[] SHORT_IMAGE_STATES =
|
||||
{"init", "rdy", "used", "disa"};
|
||||
{"init", "rdy", "used", "disa", "lock", "err", "clon", "dele", "used"};
|
||||
|
||||
private static final String[] IMAGE_TYPES =
|
||||
{"OS", "CDROM", "DATABLOCK"};
|
||||
@ -76,7 +79,7 @@ public class Image extends PoolElement
|
||||
*
|
||||
* @param client XML-RPC Client.
|
||||
* @param description A string containing the template of the image.
|
||||
* @param clusterId The cluster ID. If it is -1, this image
|
||||
* @param datastoreId The cluster ID. If it is -1, this image
|
||||
* won't be added to any cluster.
|
||||
*
|
||||
* @return If successful the message contains the associated
|
||||
@ -85,22 +88,9 @@ public class Image extends PoolElement
|
||||
public static OneResponse allocate(
|
||||
Client client,
|
||||
String description,
|
||||
int clusterId)
|
||||
int datastoreId)
|
||||
{
|
||||
return client.call(ALLOCATE, description, clusterId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocates a new Image in OpenNebula.
|
||||
*
|
||||
* @param client XML-RPC Client.
|
||||
* @param description A string containing the template of the image.
|
||||
* @return If successful the message contains the associated
|
||||
* id generated for this Image.
|
||||
*/
|
||||
public static OneResponse allocate(Client client, String description)
|
||||
{
|
||||
return allocate(client, description, -1);
|
||||
return client.call(ALLOCATE, description, datastoreId);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -154,6 +144,19 @@ public class Image extends PoolElement
|
||||
return client.call(ENABLE, id, enable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Image as persistent or not persistent.
|
||||
*
|
||||
* @param client XML-RPC Client.
|
||||
* @param id The image id of the target image we want to modify.
|
||||
* @param persistent True to make it persistent, false non-persistent
|
||||
* @return If successful the message contains the image id.
|
||||
*/
|
||||
public static OneResponse persistent(Client client, int id, boolean persistent)
|
||||
{
|
||||
return client.call(PERSISTENT, id, persistent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Publishes or unpublishes an image.
|
||||
*
|
||||
@ -249,6 +252,19 @@ public class Image extends PoolElement
|
||||
return client.call(CHTYPE, id, type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clones this Image into a new one
|
||||
*
|
||||
* @param client XML-RPC Client.
|
||||
* @param id The Image id of the target Image.
|
||||
* @param name Name for the new Image.
|
||||
* @return If successful the message contains the new Image ID.
|
||||
*/
|
||||
public static OneResponse clone(Client client, int id, String name)
|
||||
{
|
||||
return client.call(CLONE, id, name);
|
||||
}
|
||||
|
||||
// =================================
|
||||
// Instanced object XML-RPC methods
|
||||
// =================================
|
||||
@ -318,6 +334,37 @@ public class Image extends PoolElement
|
||||
return enable(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Image as persistent or not persistent.
|
||||
*
|
||||
* @param persistent True for enabling, false for disabling.
|
||||
* @return If successful the message contains the image id.
|
||||
*/
|
||||
public OneResponse persistent(boolean persistent)
|
||||
{
|
||||
return persistent(client, id, persistent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Image as persistent
|
||||
*
|
||||
* @return If successful the message contains the image id.
|
||||
*/
|
||||
public OneResponse persistent()
|
||||
{
|
||||
return persistent(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Image as persistent or not persistent.
|
||||
*
|
||||
* @return If successful the message contains the image id.
|
||||
*/
|
||||
public OneResponse nonpersistent()
|
||||
{
|
||||
return persistent(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Publishes or unpublishes the image.
|
||||
*
|
||||
@ -440,6 +487,17 @@ public class Image extends PoolElement
|
||||
return chtype(client, id, type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clones this Image into a new one
|
||||
*
|
||||
* @param name Name for the new Image.
|
||||
* @return If successful the message contains the new Image ID.
|
||||
*/
|
||||
public OneResponse clone(String name)
|
||||
{
|
||||
return clone(client, id, name);
|
||||
}
|
||||
|
||||
// =================================
|
||||
// Helpers
|
||||
// =================================
|
||||
|
@ -97,7 +97,7 @@ public class VirtualMachine extends PoolElement{
|
||||
"shut",
|
||||
"shut",
|
||||
"fail",
|
||||
"dele",
|
||||
"clea",
|
||||
"unkn" };
|
||||
|
||||
/**
|
||||
@ -523,7 +523,7 @@ public class VirtualMachine extends PoolElement{
|
||||
*/
|
||||
public OneResponse restart()
|
||||
{
|
||||
return action("shutdown");
|
||||
return action("restart");
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,12 +1,12 @@
|
||||
/*******************************************************************************
|
||||
* 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.
|
||||
@ -22,6 +22,7 @@ import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.opennebula.client.Client;
|
||||
import org.opennebula.client.OneResponse;
|
||||
import org.opennebula.client.datastore.Datastore;
|
||||
import org.opennebula.client.image.*;
|
||||
|
||||
|
||||
@ -47,6 +48,33 @@ public class ImageTest
|
||||
"ATT2 = \"VAL2\"";
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait until the Image changes to the specified state.
|
||||
* There is a time-out of 10 seconds.
|
||||
*/
|
||||
void waitAssert(Image img, String state)
|
||||
{
|
||||
int n_steps = 10;
|
||||
int step = 1000;
|
||||
|
||||
int i = 0;
|
||||
|
||||
img.info();
|
||||
|
||||
while( !( img.stateString().equals(state) || i > n_steps )
|
||||
&& !img.stateString().equals("ERROR") )
|
||||
{
|
||||
try{ Thread.sleep(step); } catch (Exception e){}
|
||||
|
||||
img.info();
|
||||
i++;
|
||||
}
|
||||
|
||||
assertTrue(
|
||||
"Image timeout, wanted state: " + state + "; it is in state "
|
||||
+ img.stateString(), img.stateString().equals(state) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws java.lang.Exception
|
||||
*/
|
||||
@ -71,10 +99,12 @@ public class ImageTest
|
||||
@Before
|
||||
public void setUp() throws Exception
|
||||
{
|
||||
res = Image.allocate(client, template());
|
||||
res = Image.allocate(client, template(), 1);
|
||||
|
||||
int imgid = res.isError() ? -1 : Integer.parseInt(res.getMessage());
|
||||
int imgid = res.isError() ? -1 : Integer.parseInt(res.getMessage());
|
||||
image = new Image(imgid, client);
|
||||
|
||||
waitAssert(image, "READY");
|
||||
}
|
||||
|
||||
/**
|
||||
@ -91,15 +121,15 @@ public class ImageTest
|
||||
{
|
||||
image.delete();
|
||||
|
||||
res = Image.allocate(client, template());
|
||||
assertTrue( !res.isError() );
|
||||
res = Image.allocate(client, template(), 1);
|
||||
assertTrue( res.getErrorMessage(), !res.isError() );
|
||||
|
||||
int imgid = res.isError() ? -1 : Integer.parseInt(res.getMessage());
|
||||
int imgid = res.isError() ? -1 : Integer.parseInt(res.getMessage());
|
||||
image = new Image(imgid, client);
|
||||
|
||||
|
||||
res = imagePool.info();
|
||||
assertTrue( !res.isError() );
|
||||
assertTrue( res.getErrorMessage(), !res.isError() );
|
||||
|
||||
boolean found = false;
|
||||
for(Image img : imagePool)
|
||||
@ -110,12 +140,37 @@ public class ImageTest
|
||||
assertTrue( found );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void clone_method()
|
||||
{
|
||||
res = image.clone("cloned_image");
|
||||
assertTrue(res.getErrorMessage(), !res.isError());
|
||||
|
||||
int imgid = res.isError() ? -1 : Integer.parseInt(res.getMessage());
|
||||
Image cloned_image = new Image(imgid, client);
|
||||
|
||||
res = imagePool.info();
|
||||
assertTrue( res.getErrorMessage(), !res.isError() );
|
||||
|
||||
boolean found = false;
|
||||
for(Image img : imagePool)
|
||||
{
|
||||
found = found || img.getName().equals("cloned_image");
|
||||
}
|
||||
|
||||
assertTrue( found );
|
||||
|
||||
res = cloned_image.info();
|
||||
assertTrue( res.getErrorMessage(), !res.isError() );
|
||||
assertTrue( cloned_image.getName().equals("cloned_image") );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void info()
|
||||
{
|
||||
res = image.info();
|
||||
assertTrue( !res.isError() );
|
||||
|
||||
assertTrue( res.getErrorMessage(), !res.isError() );
|
||||
|
||||
// assertTrue( image.getId().equals("0") );
|
||||
// assertTrue( image.id() == 0 );
|
||||
assertTrue( image.getName().equals("test_img_"+cont) );
|
||||
@ -125,7 +180,7 @@ public class ImageTest
|
||||
public void update()
|
||||
{
|
||||
res = image.info();
|
||||
assertTrue( !res.isError() );
|
||||
assertTrue( res.getErrorMessage(), !res.isError() );
|
||||
|
||||
assertTrue( image.xpath("TEMPLATE/ATT1").equals( "VAL1" ) );
|
||||
assertTrue( image.xpath("TEMPLATE/ATT2").equals( "VAL2" ) );
|
||||
@ -134,65 +189,61 @@ public class ImageTest
|
||||
"ATT3 = VAL3";
|
||||
|
||||
res = image.update(new_template);
|
||||
assertTrue( !res.isError() );
|
||||
assertTrue( res.getErrorMessage(), !res.isError() );
|
||||
|
||||
|
||||
res = image.info();
|
||||
assertTrue( !res.isError() );
|
||||
assertTrue( res.getErrorMessage(), !res.isError() );
|
||||
assertTrue( image.xpath("TEMPLATE/ATT1").equals( "" ) );
|
||||
assertTrue( image.xpath("TEMPLATE/ATT2").equals( "NEW_VAL" ) );
|
||||
assertTrue( image.xpath("TEMPLATE/ATT3").equals( "VAL3" ) );
|
||||
}
|
||||
|
||||
|
||||
// TODO
|
||||
// @Test
|
||||
@Test
|
||||
public void enable()
|
||||
{
|
||||
res = image.enable();
|
||||
assertTrue( !res.isError() );
|
||||
assertTrue( res.getErrorMessage(), !res.isError() );
|
||||
|
||||
image.info();
|
||||
assertTrue( image.isEnabled() );
|
||||
}
|
||||
|
||||
// TODO
|
||||
// @Test
|
||||
@Test
|
||||
public void disable()
|
||||
{
|
||||
res = image.disable();
|
||||
assertTrue( !res.isError() );
|
||||
assertTrue( res.getErrorMessage(), !res.isError() );
|
||||
|
||||
image.info();
|
||||
assertTrue( !image.isEnabled() );
|
||||
assertTrue( res.getErrorMessage(), !image.isEnabled() );
|
||||
}
|
||||
// TODO
|
||||
/*
|
||||
|
||||
@Test
|
||||
public void publish()
|
||||
{
|
||||
res = image.publish();
|
||||
assertTrue( !res.isError() );
|
||||
assertTrue( res.getErrorMessage(), !res.isError() );
|
||||
|
||||
image.info();
|
||||
assertTrue( image.isPublic() );
|
||||
assertTrue( image.xpath("PERMISSIONS/GROUP_U").equals( "1" ) );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void unpublish()
|
||||
{
|
||||
res = image.unpublish();
|
||||
assertTrue( !res.isError() );
|
||||
assertTrue( res.getErrorMessage(), !res.isError() );
|
||||
|
||||
image.info();
|
||||
assertTrue( !image.isPublic() );
|
||||
assertTrue( image.xpath("PERMISSIONS/GROUP_U").equals( "0" ) );
|
||||
}
|
||||
*/
|
||||
|
||||
@Test
|
||||
public void attributes()
|
||||
{
|
||||
res = image.info();
|
||||
assertTrue( !res.isError() );
|
||||
assertTrue( res.getErrorMessage(), !res.isError() );
|
||||
|
||||
// assertTrue( image.xpath("ID").equals("0") );
|
||||
assertTrue( image.xpath("NAME").equals("test_img_"+cont) );
|
||||
@ -202,7 +253,7 @@ public class ImageTest
|
||||
public void delete()
|
||||
{
|
||||
res = image.delete();
|
||||
assertTrue( !res.isError() );
|
||||
assertTrue( res.getErrorMessage(), !res.isError() );
|
||||
|
||||
// res = image.info();
|
||||
// assertTrue( res.isError() );
|
||||
|
@ -298,7 +298,7 @@ TM_MAD = [
|
||||
|
||||
DATASTORE_MAD = [
|
||||
executable = "one_datastore",
|
||||
arguments = "-t 15 -d fs,vmware,iscsi,dummy"
|
||||
arguments = "-t 15 -d fs,vmware,iscsi,lvm"
|
||||
]
|
||||
|
||||
#*******************************************************************************
|
||||
@ -406,10 +406,9 @@ HM_MAD = [
|
||||
# absolute path or relative to $ONE_LOCATION/lib/mads (or
|
||||
# /usr/lib/one/mads/ if OpenNebula was installed in /)
|
||||
#
|
||||
# arguments :
|
||||
# --authn: list of authentication modules separated by commas, if not
|
||||
# defined all the modules available will be enabled
|
||||
# --authz: authorization module
|
||||
# authn : list of authentication modules separated by commas, if not
|
||||
# defined all the modules available will be enabled
|
||||
# authz : list of authentication modules separated by commas
|
||||
#
|
||||
# SESSION_EXPIRATION_TIME: Time in seconds to keep an authenticated token as
|
||||
# valid. During this time, the driver is not used. Use 0 to disable session
|
||||
@ -422,8 +421,8 @@ HM_MAD = [
|
||||
|
||||
AUTH_MAD = [
|
||||
executable = "one_auth_mad",
|
||||
arguments = "--authn ssh,x509,ldap,server_cipher,server_x509"
|
||||
# arguments = "--authz quota --authn ssh,x509,ldap,server_cipher,server_x509"
|
||||
authn = "ssh,x509,ldap,server_cipher,server_x509"
|
||||
# , authz = "quota"
|
||||
]
|
||||
|
||||
SESSION_EXPIRATION_TIME = 900
|
||||
|
@ -34,10 +34,11 @@ module OpenNebula
|
||||
:delete => "image.delete",
|
||||
:chown => "image.chown",
|
||||
:chmod => "image.chmod",
|
||||
:chtype => "image.chtype"
|
||||
:chtype => "image.chtype",
|
||||
:clone => "image.clone"
|
||||
}
|
||||
|
||||
IMAGE_STATES=%w{INIT READY USED DISABLED LOCKED ERROR}
|
||||
IMAGE_STATES=%w{INIT READY USED DISABLED LOCKED ERROR CLONE DELETE USED_PERS}
|
||||
|
||||
SHORT_IMAGE_STATES={
|
||||
"INIT" => "init",
|
||||
@ -45,7 +46,10 @@ module OpenNebula
|
||||
"USED" => "used",
|
||||
"DISABLED" => "disa",
|
||||
"LOCKED" => "lock",
|
||||
"ERROR" => "err"
|
||||
"ERROR" => "err",
|
||||
"CLONE" => "clon",
|
||||
"DELETE" => "dele",
|
||||
"USED_PERS" => "used"
|
||||
}
|
||||
|
||||
IMAGE_TYPES=%w{OS CDROM DATABLOCK}
|
||||
@ -183,6 +187,20 @@ module OpenNebula
|
||||
return rc
|
||||
end
|
||||
|
||||
# Clones this Image into a new one
|
||||
#
|
||||
# @param [String] name for the new Image.
|
||||
#
|
||||
# @return [Integer, OpenNebula::Error] The new Image ID in case
|
||||
# of success, Error otherwise
|
||||
def clone(name)
|
||||
return Error.new('ID not defined') if !@pe_id
|
||||
|
||||
rc = @client.call(IMAGE_METHODS[:clone], @pe_id, name)
|
||||
|
||||
return rc
|
||||
end
|
||||
|
||||
#######################################################################
|
||||
# Helpers to get Image information
|
||||
#######################################################################
|
||||
|
@ -143,12 +143,12 @@ module OpenNebula
|
||||
group_m, group_a, other_u, other_m, other_a)
|
||||
end
|
||||
|
||||
# Clones this template into a new one
|
||||
# Clones this Template into a new one
|
||||
#
|
||||
# @param name [String] Name for the new Template.
|
||||
# @param [String] name for the new Template.
|
||||
#
|
||||
# @return [Integer, OpenNebula::Error] The new Template ID in case
|
||||
# of success, Error otherwise
|
||||
# of success, Error otherwise
|
||||
def clone(name)
|
||||
return Error.new('ID not defined') if !@pe_id
|
||||
|
||||
|
@ -57,6 +57,8 @@ module Migrator
|
||||
doc = Document.new(row[:body])
|
||||
|
||||
doc.root.add_element("DISK_TYPE").text = "0"
|
||||
doc.root.add_element("CLONING_ID").text = "-1"
|
||||
doc.root.add_element("CLONING_OPS").text = "0"
|
||||
|
||||
@db[:image_pool].insert(
|
||||
:oid => row[:oid],
|
||||
|
@ -327,6 +327,7 @@ void RequestManager::register_xml_methods()
|
||||
xmlrpc_c::methodPtr image_persistent(new ImagePersistent());
|
||||
xmlrpc_c::methodPtr image_enable(new ImageEnable());
|
||||
xmlrpc_c::methodPtr image_chtype(new ImageChangeType());
|
||||
xmlrpc_c::methodPtr image_clone(new ImageClone());
|
||||
|
||||
// Chown Methods
|
||||
xmlrpc_c::methodPtr vm_chown(new VirtualMachineChown());
|
||||
@ -440,6 +441,7 @@ void RequestManager::register_xml_methods()
|
||||
RequestManagerRegistry.addMethod("one.image.chown", image_chown);
|
||||
RequestManagerRegistry.addMethod("one.image.chmod", image_chmod);
|
||||
RequestManagerRegistry.addMethod("one.image.chtype", image_chtype);
|
||||
RequestManagerRegistry.addMethod("one.image.clone", image_clone);
|
||||
|
||||
RequestManagerRegistry.addMethod("one.imagepool.info", imagepool_info);
|
||||
|
||||
|
@ -458,6 +458,7 @@ void ImageAllocate::request_execute(xmlrpc_c::paramList const& params,
|
||||
ds_name,
|
||||
ds_disk_type,
|
||||
ds_data,
|
||||
-1,
|
||||
&id,
|
||||
error_str);
|
||||
if ( rc < 0 )
|
||||
|
@ -160,3 +160,147 @@ void ImageChangeType::request_execute(xmlrpc_c::paramList const& paramList,
|
||||
|
||||
success_response(id, att);
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
void ImageClone::request_execute(
|
||||
xmlrpc_c::paramList const& paramList,
|
||||
RequestAttributes& att)
|
||||
{
|
||||
int clone_id = xmlrpc_c::value_int(paramList.getInt(1));
|
||||
string name = xmlrpc_c::value_string(paramList.getString(2));
|
||||
|
||||
int rc, new_id, ds_id, size;
|
||||
string error_str, ds_name, ds_data;
|
||||
|
||||
Image::DiskType disk_type;
|
||||
PoolObjectAuth perms, ds_perms;
|
||||
|
||||
ImageTemplate * tmpl;
|
||||
Template img_usage;
|
||||
Image * img;
|
||||
Datastore * ds;
|
||||
|
||||
Nebula& nd = Nebula::instance();
|
||||
|
||||
DatastorePool * dspool = nd.get_dspool();
|
||||
ImagePool * ipool = static_cast<ImagePool *>(pool);
|
||||
|
||||
// ------------------------- Get source Image info -------------------------
|
||||
|
||||
img = ipool->get(clone_id, true);
|
||||
|
||||
if ( img == 0 )
|
||||
{
|
||||
failure_response(NO_EXISTS,
|
||||
get_error(object_name(auth_object), clone_id),
|
||||
att);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
tmpl = img->clone_template(name);
|
||||
|
||||
img->get_permissions(perms);
|
||||
|
||||
ds_id = img->get_ds_id();
|
||||
ds_name = img->get_ds_name();
|
||||
size = img->get_size();
|
||||
|
||||
img->unlock();
|
||||
|
||||
// ------------------------- Get Datastore info ----------------------------
|
||||
|
||||
ds = dspool->get(ds_id, true);
|
||||
|
||||
if ( ds == 0 )
|
||||
{
|
||||
failure_response(NO_EXISTS,
|
||||
get_error(object_name(PoolObjectSQL::DATASTORE), ds_id),
|
||||
att);
|
||||
|
||||
delete tmpl;
|
||||
return;
|
||||
}
|
||||
|
||||
ds->get_permissions(ds_perms);
|
||||
|
||||
disk_type = ds->get_disk_type();
|
||||
|
||||
ds->to_xml(ds_data);
|
||||
|
||||
ds->unlock();
|
||||
|
||||
// ------------- Set authorization request ---------------------------------
|
||||
|
||||
img_usage.add("DATASTORE", ds_id);
|
||||
img_usage.add("SIZE", size);
|
||||
|
||||
if ( att.uid != 0 )
|
||||
{
|
||||
AuthRequest ar(att.uid, att.gid);
|
||||
string tmpl_str;
|
||||
|
||||
// ------------------ Check permissions and ACLs ----------------------
|
||||
|
||||
tmpl->to_xml(tmpl_str);
|
||||
|
||||
ar.add_create_auth(auth_object, tmpl_str); // CREATE IMAGE
|
||||
|
||||
ar.add_auth(AuthRequest::USE, ds_perms); // USE DATASTORE
|
||||
|
||||
if (UserPool::authorize(ar) == -1)
|
||||
{
|
||||
failure_response(AUTHORIZATION,
|
||||
authorization_error(ar.message, att),
|
||||
att);
|
||||
|
||||
delete tmpl;
|
||||
return;
|
||||
}
|
||||
|
||||
// -------------------------- Check Quotas ----------------------------
|
||||
|
||||
if ( quota_authorization(&img_usage, att) == false )
|
||||
{
|
||||
delete tmpl;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
rc = ipool->allocate(att.uid,
|
||||
att.gid,
|
||||
att.uname,
|
||||
att.gname,
|
||||
tmpl,
|
||||
ds_id,
|
||||
ds_name,
|
||||
disk_type,
|
||||
ds_data,
|
||||
clone_id,
|
||||
&new_id,
|
||||
error_str);
|
||||
if ( rc < 0 )
|
||||
{
|
||||
quota_rollback(&img_usage, att);
|
||||
|
||||
failure_response(INTERNAL, allocate_error(error_str), att);
|
||||
return;
|
||||
}
|
||||
|
||||
ds = dspool->get(ds_id, true);
|
||||
|
||||
if ( ds != 0 ) // TODO: error otherwise or leave image in ERROR?
|
||||
{
|
||||
ds->add_image(new_id);
|
||||
|
||||
dspool->update(ds);
|
||||
|
||||
ds->unlock();
|
||||
}
|
||||
|
||||
success_response(new_id, att);
|
||||
}
|
||||
|
||||
|
||||
|
@ -571,6 +571,7 @@ void VirtualMachineSaveDisk::request_execute(xmlrpc_c::paramList const& paramLis
|
||||
ds_name,
|
||||
ds_disk_type,
|
||||
ds_data,
|
||||
-1,
|
||||
&iid,
|
||||
error_str);
|
||||
if (rc < 0)
|
||||
@ -582,6 +583,17 @@ void VirtualMachineSaveDisk::request_execute(xmlrpc_c::paramList const& paramLis
|
||||
return;
|
||||
}
|
||||
|
||||
ds = dspool->get(ds_id, true);
|
||||
|
||||
if ( ds != 0 ) // TODO: error otherwise or leave image in ERROR?
|
||||
{
|
||||
ds->add_image(iid);
|
||||
|
||||
dspool->update(ds);
|
||||
|
||||
ds->unlock();
|
||||
}
|
||||
|
||||
// Return the new allocated Image ID
|
||||
success_response(iid, att);
|
||||
}
|
||||
|
@ -200,6 +200,7 @@ void Template::marshall(string &str, const char delim)
|
||||
delete attr;
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
@ -227,6 +228,36 @@ void Template::set(Attribute * attr)
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
int Template::replace(const string& name, const string& value)
|
||||
{
|
||||
pair<multimap<string, Attribute *>::iterator,
|
||||
multimap<string, Attribute *>::iterator> index;
|
||||
|
||||
index = attributes.equal_range(name);
|
||||
|
||||
if (index.first != index.second )
|
||||
{
|
||||
multimap<string, Attribute *>::iterator i;
|
||||
|
||||
for ( i = index.first; i != index.second; i++)
|
||||
{
|
||||
Attribute * attr = i->second;
|
||||
delete attr;
|
||||
}
|
||||
|
||||
attributes.erase(index.first, index.second);
|
||||
}
|
||||
|
||||
SingleAttribute * sattr = new SingleAttribute(name,value);
|
||||
|
||||
attributes.insert(make_pair(sattr->name(), sattr));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
int Template::remove(const string& name, vector<Attribute *>& values)
|
||||
{
|
||||
multimap<string, Attribute *>::iterator i;
|
||||
@ -241,7 +272,7 @@ int Template::remove(const string& name, vector<Attribute *>& values)
|
||||
values.push_back(i->second);
|
||||
}
|
||||
|
||||
attributes.erase(index.first,index.second);
|
||||
attributes.erase(index.first, index.second);
|
||||
|
||||
return j;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user