Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
4da3202
feat(goca): add ImageResize client bindings and test
lexfrei Feb 26, 2026
23d5ad6
feat(image): add resize_image core logic and driver callback
lexfrei Feb 26, 2026
560e781
feat(api): add one.image.resize XML-RPC and gRPC endpoints
lexfrei Feb 26, 2026
d1ef90b
feat(goca): implement gRPC ImageResize and regenerate proto bindings
lexfrei Feb 26, 2026
a23f2e2
feat(datastore): add resize driver scripts for all backends
lexfrei Feb 26, 2026
286007d
feat(cli): add oneimage resize command and Ruby OCA binding
lexfrei Feb 26, 2026
ca75733
fix(image): address review findings for resize implementation
lexfrei Feb 26, 2026
a8496f5
fix(image): harden resize against injection, TOCTOU, and edge cases
lexfrei Feb 26, 2026
99a8056
fix(image): reject trailing garbage in resize size parameter
lexfrei Feb 26, 2026
f797fab
fix(image): validate callback payload and quote RBD source path
lexfrei Feb 26, 2026
cab3b94
fix(image): validate callback size and harden shell quoting
lexfrei Feb 26, 2026
f8d1165
fix(image): address review findings for resize scripts and callback
lexfrei Feb 26, 2026
66c1d20
fix(image): fix ceph quoting, dead code, and fragile test
lexfrei Feb 26, 2026
2d68bf6
docs(image): document resize size parameter format and concurrency sa…
lexfrei Feb 26, 2026
8393474
fix(image): strict callback size check and case-insensitive SPARSE
lexfrei Feb 26, 2026
8acf737
fix(image): tolerate whitespace in callback, validate SIZE in scripts
lexfrei Feb 26, 2026
204d306
fix(image): wrap resize SIZE in EXTRA_DATA element
lexfrei Feb 26, 2026
6445971
docs(image): fix MB -> MiB in XML-RPC resize comment
lexfrei Feb 26, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions include/ImageManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,15 @@ class ImageManager : public DriverManager<Driver<image_msg_t>>
*/
int flatten_snapshot(int iid, int sid, std::string& error);

/**
* Resizes an image to a new size (only upsize supported).
* @param iid id of image
* @param size new size in MiB (as string)
* @param error Error reason, if any
* @return 0 on success
*/
int resize_image(int iid, const std::string& size, std::string& error);

/**
* Flattens the backup chain by commiting changes to first (full) backup
* @param iid id of image
Expand Down Expand Up @@ -423,6 +432,8 @@ class ImageManager : public DriverManager<Driver<image_msg_t>>

void _restore(std::unique_ptr<image_msg_t> msg);

void _resize(std::unique_ptr<image_msg_t> msg);

static void _log(std::unique_ptr<image_msg_t> msg);

/**
Expand Down
1 change: 1 addition & 0 deletions include/ProtocolMessages.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ enum class ImageManagerMessages : unsigned short int
SNAP_FLATTEN,
RESTORE,
INCREMENT_FLATTEN,
RESIZE,
LOG,
ENUM_MAX
};
Expand Down
8 changes: 8 additions & 0 deletions install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -1620,6 +1620,7 @@ DATASTORE_DRIVER_DUMMY_SCRIPTS="src/datastore_mad/remotes/dummy/cp \
src/datastore_mad/remotes/dummy/snap_delete \
src/datastore_mad/remotes/dummy/snap_revert \
src/datastore_mad/remotes/dummy/snap_flatten \
src/datastore_mad/remotes/dummy/resize \
src/datastore_mad/remotes/dummy/rm \
src/datastore_mad/remotes/dummy/restore \
src/datastore_mad/remotes/dummy/export"
Expand All @@ -1632,6 +1633,7 @@ DATASTORE_DRIVER_FS_SCRIPTS="src/datastore_mad/remotes/fs/cp \
src/datastore_mad/remotes/fs/snap_delete \
src/datastore_mad/remotes/fs/snap_revert \
src/datastore_mad/remotes/fs/snap_flatten \
src/datastore_mad/remotes/fs/resize \
src/datastore_mad/remotes/fs/rm \
src/datastore_mad/remotes/fs/export"

Expand All @@ -1646,6 +1648,7 @@ DATASTORE_DRIVER_CEPH_SCRIPTS="src/datastore_mad/remotes/ceph/cp \
src/datastore_mad/remotes/ceph/snap_delete \
src/datastore_mad/remotes/ceph/snap_revert \
src/datastore_mad/remotes/ceph/snap_flatten \
src/datastore_mad/remotes/ceph/resize \
src/datastore_mad/remotes/ceph/ceph_utils.sh \
src/datastore_mad/remotes/ceph/export"

Expand All @@ -1659,6 +1662,7 @@ DATASTORE_DRIVER_DEV_SCRIPTS="src/datastore_mad/remotes/dev/cp \
src/datastore_mad/remotes/dev/snap_delete \
src/datastore_mad/remotes/dev/snap_revert \
src/datastore_mad/remotes/dev/snap_flatten \
src/datastore_mad/remotes/dev/resize \
src/datastore_mad/remotes/dev/clone"

DATASTORE_DRIVER_ISCSI_SCRIPTS="src/datastore_mad/remotes/iscsi_libvirt/cp \
Expand All @@ -1669,6 +1673,7 @@ DATASTORE_DRIVER_ISCSI_SCRIPTS="src/datastore_mad/remotes/iscsi_libvirt/cp \
src/datastore_mad/remotes/iscsi_libvirt/snap_delete \
src/datastore_mad/remotes/iscsi_libvirt/snap_revert \
src/datastore_mad/remotes/iscsi_libvirt/snap_flatten \
src/datastore_mad/remotes/iscsi_libvirt/resize \
src/datastore_mad/remotes/iscsi_libvirt/clone"

DATASTORE_DRIVER_RSYNC_SCRIPTS="src/datastore_mad/remotes/rsync/cp \
Expand All @@ -1679,6 +1684,7 @@ DATASTORE_DRIVER_RSYNC_SCRIPTS="src/datastore_mad/remotes/rsync/cp \
src/datastore_mad/remotes/rsync/snap_delete \
src/datastore_mad/remotes/rsync/snap_revert \
src/datastore_mad/remotes/rsync/snap_flatten \
src/datastore_mad/remotes/rsync/resize \
src/datastore_mad/remotes/rsync/rm \
src/datastore_mad/remotes/rsync/backup \
src/datastore_mad/remotes/rsync/backup_cancel \
Expand All @@ -1695,6 +1701,7 @@ DATASTORE_DRIVER_RESTIC_SCRIPTS="src/datastore_mad/remotes/restic/cp \
src/datastore_mad/remotes/restic/snap_delete \
src/datastore_mad/remotes/restic/snap_revert \
src/datastore_mad/remotes/restic/snap_flatten \
src/datastore_mad/remotes/restic/resize \
src/datastore_mad/remotes/restic/clone \
src/datastore_mad/remotes/restic/restore \
src/datastore_mad/remotes/restic/restic.rb \
Expand All @@ -1712,6 +1719,7 @@ DATASTORE_DRIVER_VIRTIOFS_SCRIPTS="src/datastore_mad/remotes/virtiofs/clone \
src/datastore_mad/remotes/virtiofs/snap_delete \
src/datastore_mad/remotes/virtiofs/snap_flatten \
src/datastore_mad/remotes/virtiofs/snap_revert \
src/datastore_mad/remotes/virtiofs/resize \
src/datastore_mad/remotes/virtiofs/stat"

DATASTORE_DRIVER_ETC_SCRIPTS="src/datastore_mad/remotes/datastore.conf"
Expand Down
2 changes: 1 addition & 1 deletion share/shell/bash_completion
Original file line number Diff line number Diff line change
Expand Up @@ -440,7 +440,7 @@ _oneimage() {
fi
opts="create clone delete persistent nonpersistent update enable chtype
disable chgrp chown chmod rename snapshot-delete snapshot-revert
snapshot-flatten list show top lock unlock orphans restore"
snapshot-flatten resize list show top lock unlock orphans restore"
cmd=oneimage
if [ "$COMP_CWORD" == 1 ]; then
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
Expand Down
22 changes: 22 additions & 0 deletions src/cli/oneimage
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,10 @@ CommandParser::CmdParser.new(ARGV) do
helper.retrieve_snapshot_id(@current_image, arg)
end

set :format, :size, 'Image size in MiB' do |arg|
OpenNebulaHelper.size_in_mb(arg)
end

########################################################################
# Commands
########################################################################
Expand Down Expand Up @@ -426,6 +430,24 @@ CommandParser::CmdParser.new(ARGV) do
end
end

resize_desc = <<-EOT.unindent
Resizes an image. The image must be in READY state and only
upsizing is supported (the new size must be greater than the
current size).

The size can be specified with the following suffixes:
- T: TiB
- G: GiB
- M: MiB
Default unit is MiB.
EOT

command :resize, resize_desc, :imageid, :size do
helper.perform_action(args[0], options, 'resizing image') do |o|
o.resize(args[1].to_s)
end
end

restore_desc = <<-EOT.unindent
Restore a backup image. It will restore the associated VM template to the VM template pool and
the disk images to the selected image datastore.
Expand Down
12 changes: 10 additions & 2 deletions src/datastore_mad/one_datastore.rb
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@ class DatastoreDriver < OpenNebulaDriver
:snap_revert => 'SNAP_REVERT',
:snap_flatten=> 'SNAP_FLATTEN',
:restore => 'RESTORE',
:increment_flatten => 'INCREMENT_FLATTEN'
:increment_flatten => 'INCREMENT_FLATTEN',
:resize => 'RESIZE'
}

# Default System datastores for OpenNebula, override in oned.conf
Expand All @@ -87,7 +88,8 @@ def initialize(ds_type, sys_ds_type, options = {})
ACTION[:snap_delete] => nil,
ACTION[:snap_revert] => nil,
ACTION[:snap_flatten] => nil,
ACTION[:restore] => nil
ACTION[:restore] => nil,
ACTION[:resize] => nil
}
}.merge!(options)

Expand Down Expand Up @@ -124,6 +126,7 @@ def initialize(ds_type, sys_ds_type, options = {})
register_action(ACTION[:snap_flatten].to_sym, method('snap_flatten'))
register_action(ACTION[:restore].to_sym, method('restore'))
register_action(ACTION[:increment_flatten].to_sym, method('increment_flatten'))
register_action(ACTION[:resize].to_sym, method('resize'))
end

############################################################################
Expand Down Expand Up @@ -185,6 +188,11 @@ def increment_flatten(id, drv_message)
do_image_action(id, ds, :increment_flatten, drv_message)
end

def resize(id, drv_message)
ds, _sys = get_ds_type(drv_message)
do_image_action(id, ds, :resize, drv_message)
end

private

def available?(ds, id, action)
Expand Down
97 changes: 97 additions & 0 deletions src/datastore_mad/remotes/ceph/resize
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
#!/bin/bash

# -------------------------------------------------------------------------- #
# Copyright 2002-2025, OpenNebula Project, OpenNebula Systems #
# #
# 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 resize a persistent image in a Ceph datastore
###############################################################################

# -------- 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}/../../etc/datastore/ceph/ceph.conf

# -------- Get image and datastore arguments from OpenNebula core ------------

DRV_ACTION=`cat -`
ID=$1

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/TEMPLATE/BRIDGE_LIST \
/DS_DRIVER_ACTION_DATA/IMAGE/SOURCE \
/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/CEPH_USER \
/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/CEPH_KEY \
/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/CEPH_CONF \
/DS_DRIVER_ACTION_DATA/EXTRA_DATA/SIZE)

unset i

BRIDGE_LIST="${XPATH_ELEMENTS[i++]}"
RBD_SRC="${XPATH_ELEMENTS[i++]}"
CEPH_USER="${XPATH_ELEMENTS[i++]}"
CEPH_KEY="${XPATH_ELEMENTS[i++]}"
CEPH_CONF="${XPATH_ELEMENTS[i++]}"
SIZE="${XPATH_ELEMENTS[i++]}"

if [ -z "$SIZE" ]; then
error_message "Missing SIZE in driver message."
exit -1
fi

DST_HOST=`get_destination_host $ID`

if [ -z "$DST_HOST" ]; then
error_message "Datastore template missing 'BRIDGE_LIST' attribute."
exit -1
fi

if [ -n "$CEPH_USER" ]; then
RBD="$RBD --id ${CEPH_USER}"
fi

if [ -n "$CEPH_KEY" ]; then
RBD="$RBD --keyfile ${CEPH_KEY}"
fi

if [ -n "$CEPH_CONF" ]; then
RBD="$RBD --conf ${CEPH_CONF}"
fi

RESIZE_CMD=$(cat <<EOF
$RBD resize --size "${SIZE}M" "$RBD_SRC"
EOF
)

ssh_exec_and_log "$DST_HOST" "$RESIZE_CMD" \
"Error resizing $RBD_SRC to ${SIZE}M"

echo "$SIZE"
1 change: 1 addition & 0 deletions src/datastore_mad/remotes/dev/resize
32 changes: 32 additions & 0 deletions src/datastore_mad/remotes/dummy/resize
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#!/bin/sh

# -------------------------------------------------------------------------- #
# Copyright 2002-2025, OpenNebula Project, OpenNebula Systems #
# #
# 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. #
#--------------------------------------------------------------------------- #
DRV_ACTION=`cat -`
ID=$1

DRIVER_PATH=$(dirname $0)
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/EXTRA_DATA/SIZE)

SIZE="${XPATH_ELEMENTS[0]}"

echo "$SIZE"
70 changes: 70 additions & 0 deletions src/datastore_mad/remotes/fs/resize
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
#!/bin/bash

# -------------------------------------------------------------------------- #
# Copyright 2002-2025, OpenNebula Project, OpenNebula Systems #
# #
# 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. #
#--------------------------------------------------------------------------- #
if [ -z "${ONE_LOCATION}" ]; then
TMCOMMON=/var/lib/one/remotes/tm/tm_common.sh
else
TMCOMMON=$ONE_LOCATION/var/remotes/tm/tm_common.sh
fi

. $TMCOMMON

DRIVER_PATH=$(dirname $0)
source ${DRIVER_PATH}/../libfs.sh

# -------- Get image and datastore arguments from OpenNebula core ------------

DRV_ACTION=`cat -`
ID=$1

XPATH="${DRIVER_PATH}/../xpath.rb -b $DRV_ACTION"

unset i j XPATH_ELEMENTS

while IFS= read -r -d '' element; do
XPATH_ELEMENTS[i++]="$element"
done < <($XPATH /DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/BRIDGE_LIST \
/DS_DRIVER_ACTION_DATA/IMAGE/SOURCE \
/DS_DRIVER_ACTION_DATA/IMAGE/TEMPLATE/SPARSE \
/DS_DRIVER_ACTION_DATA/EXTRA_DATA/SIZE)

BRIDGE_LIST="${XPATH_ELEMENTS[j++]}"
DISK_SRC="${XPATH_ELEMENTS[j++]}"
SPARSE="${XPATH_ELEMENTS[j++]}"
SIZE="${XPATH_ELEMENTS[j++]}"

if [ -z "$SIZE" ]; then
error_message "Missing SIZE in driver message."
exit -1
fi

RESIZE_OPTS=""
if [ "$(echo "$SPARSE" | tr A-Z a-z)" = "no" ]; then
RESIZE_OPTS="--preallocation=falloc"
fi

if [ -n "$BRIDGE_LIST" ]; then
DST_HOST=$(get_destination_host $ID)

ssh_exec_and_log "$DST_HOST" "qemu-img resize ${RESIZE_OPTS} \"${DISK_SRC}\" \"${SIZE}M\"" \
"Error resizing ${DISK_SRC} to ${SIZE}M"
else
exec_and_log "qemu-img resize ${RESIZE_OPTS} \"${DISK_SRC}\" \"${SIZE}M\"" \
"Error resizing ${DISK_SRC} to ${SIZE}M"
fi

echo "$SIZE"
1 change: 1 addition & 0 deletions src/datastore_mad/remotes/iscsi_libvirt/resize
1 change: 1 addition & 0 deletions src/datastore_mad/remotes/restic/resize
1 change: 1 addition & 0 deletions src/datastore_mad/remotes/rsync/resize
1 change: 1 addition & 0 deletions src/datastore_mad/remotes/virtiofs/resize
Loading