1
0
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:
Ruben S. Montero 2012-06-19 14:30:50 +02:00
commit 8f809df025
41 changed files with 1352 additions and 236 deletions

View File

@ -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
*/

View File

@ -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*/

View File

@ -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

View File

@ -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);

View File

@ -29,6 +29,8 @@ class ImageTemplate : public Template
public:
ImageTemplate() : Template(true,'=',"TEMPLATE"){};
ImageTemplate(const ImageTemplate& tmpl):Template(tmpl){};
~ImageTemplate(){};
/**

View File

@ -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);
}
/**

View File

@ -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);
};
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

View File

@ -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
*/

View File

@ -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"
#-------------------------------------------------------------------------------

View File

@ -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"/>

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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>

View File

@ -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)

View 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"

View 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"

View File

@ -0,0 +1 @@
../common/clone

View 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"

View 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"

View File

@ -0,0 +1 @@
../common/clone

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -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);

View File

@ -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;
}
}
}

View File

@ -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 {

View File

@ -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";

View File

@ -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

View File

@ -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;
}
/**

View File

@ -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
// =================================

View File

@ -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");
}
/**

View File

@ -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() );

View File

@ -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

View File

@ -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
#######################################################################

View File

@ -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

View File

@ -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],

View File

@ -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);

View File

@ -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 )

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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;
}