mirror of
https://github.com/ceph/ceph
synced 2025-04-04 15:36:24 +00:00
rbd: add group snap info command
... to show information about a group snapshot. And also include group snap ID in `group snap ls` output. Fixes: https://tracker.ceph.com/issues/66011 Signed-off-by: Ramana Raja <rraja@redhat.com>
This commit is contained in:
parent
103cd8e78b
commit
e5ccce14c4
@ -6,6 +6,12 @@
|
|||||||
including `timezone.utc` makes it explicit and avoids the potential of the
|
including `timezone.utc` makes it explicit and avoids the potential of the
|
||||||
returned timestamp getting misinterpreted -- in Python 3, many `datetime`
|
returned timestamp getting misinterpreted -- in Python 3, many `datetime`
|
||||||
methods treat "naive" `datetime` objects as local times.
|
methods treat "naive" `datetime` objects as local times.
|
||||||
|
* RBD: `rbd group info` and `rbd group snap info` commands are introduced to
|
||||||
|
show information about a group and a group snapshot respectively.
|
||||||
|
* RBD: `rbd group snap ls` output now includes the group snap IDs. The header
|
||||||
|
of the column showing the state of a group snapshot in the unformatted CLI
|
||||||
|
output is changed from 'STATUS' to 'STATE'. The state of a group snapshot
|
||||||
|
that was shown as 'ok' is now shown as 'complete', which is more descriptive.
|
||||||
|
|
||||||
>=19.0.0
|
>=19.0.0
|
||||||
|
|
||||||
|
@ -367,6 +367,9 @@ Commands
|
|||||||
:command:`group snap list` *group-spec*
|
:command:`group snap list` *group-spec*
|
||||||
List snapshots of a group.
|
List snapshots of a group.
|
||||||
|
|
||||||
|
:command:`group snap info` *group-snap-spec*
|
||||||
|
Get information about a snapshot of a group.
|
||||||
|
|
||||||
:command:`group snap rm` *group-snap-spec*
|
:command:`group snap rm` *group-snap-spec*
|
||||||
Remove a snapshot from a group.
|
Remove a snapshot from a group.
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ list_groups()
|
|||||||
check_group_exists()
|
check_group_exists()
|
||||||
{
|
{
|
||||||
local group_name=$1
|
local group_name=$1
|
||||||
list_groups | grep $group_name
|
list_groups | grep -w $group_name
|
||||||
}
|
}
|
||||||
|
|
||||||
remove_group()
|
remove_group()
|
||||||
@ -165,7 +165,7 @@ check_snapshot_in_group()
|
|||||||
{
|
{
|
||||||
local group_name=$1
|
local group_name=$1
|
||||||
local snap_name=$2
|
local snap_name=$2
|
||||||
list_snapshots $group_name | grep $snap_name
|
list_snapshots $group_name | grep -w $snap_name
|
||||||
}
|
}
|
||||||
|
|
||||||
check_snapshots_count_in_group()
|
check_snapshots_count_in_group()
|
||||||
@ -182,12 +182,43 @@ check_snapshot_not_in_group()
|
|||||||
{
|
{
|
||||||
local group_name=$1
|
local group_name=$1
|
||||||
local snap_name=$2
|
local snap_name=$2
|
||||||
for v in $(list_snapshots $group_name | awk '{print $1}'); do
|
|
||||||
if [ "$v" = "$snap_name" ]; then
|
check_group_exists $group_name || return 1
|
||||||
return 1
|
! check_snapshot_in_group $group_name $snap_name
|
||||||
fi
|
}
|
||||||
done
|
|
||||||
return 0
|
check_snap_id_in_list_snapshots()
|
||||||
|
{
|
||||||
|
local group_name=$1
|
||||||
|
local snap_name=$2
|
||||||
|
|
||||||
|
local snap_id_in_info=$(
|
||||||
|
rbd group snap info $group_name@$snap_name --format=json |
|
||||||
|
jq -r '.id')
|
||||||
|
[[ -n "$snap_id_in_info" ]] || return 1
|
||||||
|
|
||||||
|
local snap_id_in_list=$(
|
||||||
|
rbd group snap ls $group_name --format=json |
|
||||||
|
jq --arg snap_name $snap_name -r '
|
||||||
|
.[] | select(.snapshot == $snap_name) | .id')
|
||||||
|
test "$snap_id_in_list" = "$snap_id_in_info"
|
||||||
|
}
|
||||||
|
|
||||||
|
check_snapshot_info()
|
||||||
|
{
|
||||||
|
local group_name=$1
|
||||||
|
local snap_name=$2
|
||||||
|
local image_count=$3
|
||||||
|
|
||||||
|
local snap_info=$(rbd group snap info $group_name@$snap_name --format=json)
|
||||||
|
local actual_snap_name=$(jq -r ".name" <<< "$snap_info")
|
||||||
|
test "$actual_snap_name" = "$snap_name" || return 1
|
||||||
|
|
||||||
|
local snap_state=$(jq -r ".state" <<< "$snap_info")
|
||||||
|
test "$snap_state" = "complete" || return 1
|
||||||
|
|
||||||
|
local actual_image_count=$(jq '.images | length' <<< "$snap_info")
|
||||||
|
test "$actual_image_count" = "$image_count"
|
||||||
}
|
}
|
||||||
|
|
||||||
echo "TEST: create remove consistency group"
|
echo "TEST: create remove consistency group"
|
||||||
@ -217,23 +248,24 @@ echo "PASSED"
|
|||||||
echo "TEST: create remove snapshots of consistency group"
|
echo "TEST: create remove snapshots of consistency group"
|
||||||
image="test_image"
|
image="test_image"
|
||||||
group="test_consistency_group"
|
group="test_consistency_group"
|
||||||
snap="group_snap"
|
snaps=("group_snap1" "group_snap2" "group_snap3" "group_snap4")
|
||||||
new_snap="new_group_snap"
|
|
||||||
sec_snap="group_snap2"
|
|
||||||
create_image $image
|
create_image $image
|
||||||
create_group $group
|
create_group $group
|
||||||
|
create_snapshot $group ${snaps[0]}
|
||||||
|
check_snapshot_info $group ${snaps[0]} 0
|
||||||
add_image_to_group $image $group
|
add_image_to_group $image $group
|
||||||
create_snapshot $group $snap
|
create_snapshot $group ${snaps[1]}
|
||||||
check_snapshot_in_group $group $snap
|
check_snapshot_info $group ${snaps[1]} 1
|
||||||
rename_snapshot $group $snap $new_snap
|
rename_snapshot $group ${snaps[1]} ${snaps[2]}
|
||||||
check_snapshot_not_in_group $group $snap
|
check_snapshot_info $group ${snaps[2]} 1
|
||||||
create_snapshot $group $sec_snap
|
check_snapshot_not_in_group $group ${snaps[1]}
|
||||||
check_snapshot_in_group $group $sec_snap
|
create_snapshot $group ${snaps[3]}
|
||||||
rollback_snapshot $group $new_snap
|
check_snapshot_in_group $group ${snaps[3]}
|
||||||
remove_snapshot $group $new_snap
|
rollback_snapshot $group ${snaps[2]}
|
||||||
check_snapshot_not_in_group $group $new_snap
|
remove_snapshot $group ${snaps[2]}
|
||||||
remove_snapshot $group $sec_snap
|
check_snapshot_not_in_group $group ${snaps[2]}
|
||||||
check_snapshot_not_in_group $group $sec_snap
|
remove_snapshot $group ${snaps[3]}
|
||||||
|
check_snapshot_not_in_group $group ${snaps[3]}
|
||||||
remove_group $group
|
remove_group $group
|
||||||
remove_image $image
|
remove_image $image
|
||||||
echo "PASSED"
|
echo "PASSED"
|
||||||
@ -247,6 +279,7 @@ create_group $group
|
|||||||
add_image_to_group $image $group
|
add_image_to_group $image $group
|
||||||
create_snapshots $group $snap 10
|
create_snapshots $group $snap 10
|
||||||
check_snapshots_count_in_group $group $snap 10
|
check_snapshots_count_in_group $group $snap 10
|
||||||
|
check_snap_id_in_list_snapshots $group ${snap}1
|
||||||
remove_snapshots $group $snap 10
|
remove_snapshots $group $snap 10
|
||||||
create_snapshots $group $snap 100
|
create_snapshots $group $snap 100
|
||||||
check_snapshots_count_in_group $group $snap 100
|
check_snapshots_count_in_group $group $snap 100
|
||||||
|
@ -249,11 +249,27 @@ typedef enum {
|
|||||||
RBD_GROUP_SNAP_STATE_COMPLETE
|
RBD_GROUP_SNAP_STATE_COMPLETE
|
||||||
} rbd_group_snap_state_t;
|
} rbd_group_snap_state_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char *image_name;
|
||||||
|
int64_t pool_id;
|
||||||
|
uint64_t snap_id;
|
||||||
|
} rbd_group_image_snap_info_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char *name;
|
char *name;
|
||||||
rbd_group_snap_state_t state;
|
rbd_group_snap_state_t state;
|
||||||
} rbd_group_snap_info_t;
|
} rbd_group_snap_info_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char *id;
|
||||||
|
char *name;
|
||||||
|
char *image_snap_name;
|
||||||
|
rbd_group_snap_state_t state;
|
||||||
|
//rbd_group_snap_namespace_type_t namespace_type;
|
||||||
|
size_t image_snaps_count;
|
||||||
|
rbd_group_image_snap_info_t *image_snaps;
|
||||||
|
} rbd_group_snap_info2_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int64_t group_pool;
|
int64_t group_pool;
|
||||||
char *group_name;
|
char *group_name;
|
||||||
@ -1491,6 +1507,18 @@ CEPH_RBD_API int rbd_group_snap_list(rados_ioctx_t group_p,
|
|||||||
CEPH_RBD_API int rbd_group_snap_list_cleanup(rbd_group_snap_info_t *snaps,
|
CEPH_RBD_API int rbd_group_snap_list_cleanup(rbd_group_snap_info_t *snaps,
|
||||||
size_t group_snap_info_size,
|
size_t group_snap_info_size,
|
||||||
size_t num_entries);
|
size_t num_entries);
|
||||||
|
CEPH_RBD_API int rbd_group_snap_list2(rados_ioctx_t group_p,
|
||||||
|
const char *group_name,
|
||||||
|
rbd_group_snap_info2_t *snaps,
|
||||||
|
size_t *num_entries);
|
||||||
|
CEPH_RBD_API void rbd_group_snap_list2_cleanup(rbd_group_snap_info2_t *snaps,
|
||||||
|
size_t num_entries);
|
||||||
|
CEPH_RBD_API int rbd_group_snap_get_info(rados_ioctx_t group_p,
|
||||||
|
const char *group_name,
|
||||||
|
const char *snap_name,
|
||||||
|
rbd_group_snap_info2_t *group_snap);
|
||||||
|
CEPH_RBD_API void rbd_group_snap_get_info_cleanup(
|
||||||
|
rbd_group_snap_info2_t *group_snap);
|
||||||
CEPH_RBD_API int rbd_group_snap_rollback(rados_ioctx_t group_p,
|
CEPH_RBD_API int rbd_group_snap_rollback(rados_ioctx_t group_p,
|
||||||
const char *group_name,
|
const char *group_name,
|
||||||
const char *snap_name);
|
const char *snap_name);
|
||||||
|
@ -161,11 +161,26 @@ namespace librbd {
|
|||||||
|
|
||||||
typedef rbd_group_snap_state_t group_snap_state_t;
|
typedef rbd_group_snap_state_t group_snap_state_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
std::string image_name;
|
||||||
|
int64_t pool_id;
|
||||||
|
uint64_t snap_id;
|
||||||
|
} group_image_snap_info_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
std::string name;
|
std::string name;
|
||||||
group_snap_state_t state;
|
group_snap_state_t state;
|
||||||
} group_snap_info_t;
|
} group_snap_info_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
std::string id;
|
||||||
|
std::string name;
|
||||||
|
std::string image_snap_name;
|
||||||
|
group_snap_state_t state;
|
||||||
|
//group_snap_namespace_type_t namespace_type;
|
||||||
|
std::vector<group_image_snap_info_t> image_snaps;
|
||||||
|
} group_snap_info2_t;
|
||||||
|
|
||||||
typedef rbd_image_info_t image_info_t;
|
typedef rbd_image_info_t image_info_t;
|
||||||
|
|
||||||
class CEPH_RBD_API ProgressContext
|
class CEPH_RBD_API ProgressContext
|
||||||
@ -443,6 +458,11 @@ public:
|
|||||||
int group_snap_list(IoCtx& group_ioctx, const char *group_name,
|
int group_snap_list(IoCtx& group_ioctx, const char *group_name,
|
||||||
std::vector<group_snap_info_t> *snaps,
|
std::vector<group_snap_info_t> *snaps,
|
||||||
size_t group_snap_info_size);
|
size_t group_snap_info_size);
|
||||||
|
int group_snap_list2(IoCtx& group_ioctx, const char *group_name,
|
||||||
|
std::vector<group_snap_info2_t> *snaps);
|
||||||
|
int group_snap_get_info(IoCtx& group_ioctx, const char *group_name,
|
||||||
|
const char *snap_name,
|
||||||
|
group_snap_info2_t *group_snap);
|
||||||
int group_snap_rollback(IoCtx& io_ctx, const char *group_name,
|
int group_snap_rollback(IoCtx& io_ctx, const char *group_name,
|
||||||
const char *snap_name);
|
const char *snap_name);
|
||||||
int group_snap_rollback_with_progress(IoCtx& io_ctx, const char *group_name,
|
int group_snap_rollback_with_progress(IoCtx& io_ctx, const char *group_name,
|
||||||
|
@ -53,26 +53,16 @@ snap_t get_group_snap_id(I* ictx,
|
|||||||
return CEPH_NOSNAP;
|
return CEPH_NOSNAP;
|
||||||
}
|
}
|
||||||
|
|
||||||
int group_snap_list(librados::IoCtx& group_ioctx, const char *group_name,
|
int group_snap_list(librados::IoCtx& group_ioctx, const std::string& group_id,
|
||||||
std::vector<cls::rbd::GroupSnapshot> *cls_snaps)
|
std::vector<cls::rbd::GroupSnapshot> *cls_snaps)
|
||||||
{
|
{
|
||||||
CephContext *cct = (CephContext *)group_ioctx.cct();
|
CephContext *cct = (CephContext *)group_ioctx.cct();
|
||||||
|
|
||||||
string group_id;
|
|
||||||
vector<string> ind_snap_names;
|
|
||||||
|
|
||||||
int r = cls_client::dir_get_id(&group_ioctx, RBD_GROUP_DIRECTORY,
|
|
||||||
group_name, &group_id);
|
|
||||||
if (r < 0) {
|
|
||||||
lderr(cct) << "error reading group id object: "
|
|
||||||
<< cpp_strerror(r)
|
|
||||||
<< dendl;
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
string group_header_oid = util::group_header_name(group_id);
|
string group_header_oid = util::group_header_name(group_id);
|
||||||
|
|
||||||
const int max_read = 1024;
|
const int max_read = 1024;
|
||||||
cls::rbd::GroupSnapshot snap_last;
|
cls::rbd::GroupSnapshot snap_last;
|
||||||
|
int r;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
vector<cls::rbd::GroupSnapshot> snaps_page;
|
vector<cls::rbd::GroupSnapshot> snaps_page;
|
||||||
@ -476,6 +466,48 @@ int notify_quiesce(std::vector<I*> &ictxs, ProgressContext &prog_ctx,
|
|||||||
return ret_code;
|
return ret_code;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int GroupSnapshot_to_group_snap_info2(
|
||||||
|
librados::IoCtx& group_ioctx, const std::string& group_id,
|
||||||
|
const cls::rbd::GroupSnapshot& cls_group_snap,
|
||||||
|
group_snap_info2_t* group_snap)
|
||||||
|
{
|
||||||
|
std::vector<group_image_snap_info_t> image_snaps;
|
||||||
|
image_snaps.reserve(cls_group_snap.snaps.size());
|
||||||
|
|
||||||
|
for (const auto& snap : cls_group_snap.snaps) {
|
||||||
|
librbd::IoCtx image_ioctx;
|
||||||
|
int r = util::create_ioctx(group_ioctx, "image", snap.pool, {},
|
||||||
|
&image_ioctx);
|
||||||
|
if (r < 0) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string image_name;
|
||||||
|
r = cls_client::dir_get_name(&image_ioctx, RBD_DIRECTORY, snap.image_id,
|
||||||
|
&image_name);
|
||||||
|
if (r < 0) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
image_snaps.push_back(
|
||||||
|
group_image_snap_info_t {
|
||||||
|
std::move(image_name),
|
||||||
|
snap.pool,
|
||||||
|
snap.snap_id
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
group_snap->id = cls_group_snap.id;
|
||||||
|
group_snap->name = cls_group_snap.name;
|
||||||
|
group_snap->state = static_cast<group_snap_state_t>(cls_group_snap.state);
|
||||||
|
group_snap->image_snap_name = calc_ind_image_snap_name(group_ioctx.get_id(),
|
||||||
|
group_id,
|
||||||
|
cls_group_snap.id);
|
||||||
|
group_snap->image_snaps = std::move(image_snaps);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
|
||||||
template <typename I>
|
template <typename I>
|
||||||
@ -560,7 +592,7 @@ int Group<I>::remove(librados::IoCtx& io_ctx, const char *group_name)
|
|||||||
string group_header_oid = util::group_header_name(group_id);
|
string group_header_oid = util::group_header_name(group_id);
|
||||||
|
|
||||||
std::vector<cls::rbd::GroupSnapshot> snaps;
|
std::vector<cls::rbd::GroupSnapshot> snaps;
|
||||||
r = group_snap_list(io_ctx, group_name, &snaps);
|
r = group_snap_list(io_ctx, group_id, &snaps);
|
||||||
if (r < 0 && r != -ENOENT) {
|
if (r < 0 && r != -ENOENT) {
|
||||||
lderr(cct) << "error listing group snapshots" << dendl;
|
lderr(cct) << "error listing group snapshots" << dendl;
|
||||||
return r;
|
return r;
|
||||||
@ -1158,7 +1190,7 @@ int Group<I>::snap_remove(librados::IoCtx& group_ioctx, const char *group_name,
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::vector<cls::rbd::GroupSnapshot> snaps;
|
std::vector<cls::rbd::GroupSnapshot> snaps;
|
||||||
r = group_snap_list(group_ioctx, group_name, &snaps);
|
r = group_snap_list(group_ioctx, group_id, &snaps);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
@ -1199,7 +1231,7 @@ int Group<I>::snap_rename(librados::IoCtx& group_ioctx, const char *group_name,
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::vector<cls::rbd::GroupSnapshot> group_snaps;
|
std::vector<cls::rbd::GroupSnapshot> group_snaps;
|
||||||
r = group_snap_list(group_ioctx, group_name, &group_snaps);
|
r = group_snap_list(group_ioctx, group_id, &group_snaps);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
@ -1228,22 +1260,78 @@ int Group<I>::snap_rename(librados::IoCtx& group_ioctx, const char *group_name,
|
|||||||
|
|
||||||
template <typename I>
|
template <typename I>
|
||||||
int Group<I>::snap_list(librados::IoCtx& group_ioctx, const char *group_name,
|
int Group<I>::snap_list(librados::IoCtx& group_ioctx, const char *group_name,
|
||||||
std::vector<group_snap_info_t> *snaps)
|
std::vector<group_snap_info2_t> *group_snaps)
|
||||||
{
|
{
|
||||||
std::vector<cls::rbd::GroupSnapshot> cls_snaps;
|
CephContext *cct = (CephContext *)group_ioctx.cct();
|
||||||
|
|
||||||
int r = group_snap_list(group_ioctx, group_name, &cls_snaps);
|
std::string group_id;
|
||||||
|
int r = cls_client::dir_get_id(&group_ioctx, RBD_GROUP_DIRECTORY,
|
||||||
|
group_name, &group_id);
|
||||||
|
if (r < 0) {
|
||||||
|
lderr(cct) << "error reading group id object: " << cpp_strerror(r)
|
||||||
|
<< dendl;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<cls::rbd::GroupSnapshot> cls_group_snaps;
|
||||||
|
r = group_snap_list(group_ioctx, group_id, &cls_group_snaps);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto snap : cls_snaps) {
|
std::vector<group_snap_info2_t> group_snaps_tmp(cls_group_snaps.size());
|
||||||
snaps->push_back(
|
for (size_t i = 0; i < cls_group_snaps.size(); i++) {
|
||||||
group_snap_info_t {
|
r = GroupSnapshot_to_group_snap_info2(group_ioctx, group_id,
|
||||||
snap.name,
|
cls_group_snaps[i],
|
||||||
static_cast<group_snap_state_t>(snap.state)});
|
&group_snaps_tmp[i]);
|
||||||
|
if (r < 0) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*group_snaps = std::move(group_snaps_tmp);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename I>
|
||||||
|
int Group<I>::snap_get_info(librados::IoCtx& group_ioctx,
|
||||||
|
const char *group_name, const char *snap_name,
|
||||||
|
group_snap_info2_t* group_snap)
|
||||||
|
{
|
||||||
|
CephContext *cct = (CephContext *)group_ioctx.cct();
|
||||||
|
|
||||||
|
std::string group_id;
|
||||||
|
int r = cls_client::dir_get_id(&group_ioctx, RBD_GROUP_DIRECTORY,
|
||||||
|
group_name, &group_id);
|
||||||
|
if (r < 0) {
|
||||||
|
lderr(cct) << "error reading group id object: " << cpp_strerror(r)
|
||||||
|
<< dendl;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<cls::rbd::GroupSnapshot> cls_group_snaps;
|
||||||
|
r = group_snap_list(group_ioctx, group_id, &cls_group_snaps);
|
||||||
|
if (r < 0) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
const cls::rbd::GroupSnapshot *cls_group_snap_ptr = nullptr;
|
||||||
|
for (const auto& cls_group_snap : cls_group_snaps) {
|
||||||
|
if (cls_group_snap.name == snap_name) {
|
||||||
|
cls_group_snap_ptr = &cls_group_snap;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (cls_group_snap_ptr == nullptr) {
|
||||||
|
return -ENOENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = GroupSnapshot_to_group_snap_info2(group_ioctx, group_id,
|
||||||
|
*cls_group_snap_ptr, group_snap);
|
||||||
|
if (r < 0) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1264,7 +1352,7 @@ int Group<I>::snap_rollback(librados::IoCtx& group_ioctx,
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::vector<cls::rbd::GroupSnapshot> snaps;
|
std::vector<cls::rbd::GroupSnapshot> snaps;
|
||||||
r = group_snap_list(group_ioctx, group_name, &snaps);
|
r = group_snap_list(group_ioctx, group_id, &snaps);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
@ -47,7 +47,10 @@ struct Group {
|
|||||||
static int snap_rename(librados::IoCtx& group_ioctx, const char *group_name,
|
static int snap_rename(librados::IoCtx& group_ioctx, const char *group_name,
|
||||||
const char *old_snap_name, const char *new_snap_name);
|
const char *old_snap_name, const char *new_snap_name);
|
||||||
static int snap_list(librados::IoCtx& group_ioctx, const char *group_name,
|
static int snap_list(librados::IoCtx& group_ioctx, const char *group_name,
|
||||||
std::vector<group_snap_info_t> *snaps);
|
std::vector<group_snap_info2_t> *snaps);
|
||||||
|
static int snap_get_info(librados::IoCtx& group_ioctx,
|
||||||
|
const char *group_name, const char *snap_name,
|
||||||
|
group_snap_info2_t* group_snap);
|
||||||
static int snap_rollback(librados::IoCtx& group_ioctx,
|
static int snap_rollback(librados::IoCtx& group_ioctx,
|
||||||
const char *group_name, const char *snap_name,
|
const char *group_name, const char *snap_name,
|
||||||
ProgressContext& pctx);
|
ProgressContext& pctx);
|
||||||
|
@ -263,12 +263,31 @@ void group_info_cpp_to_c(const librbd::group_info_t &cpp_info,
|
|||||||
c_info->pool = cpp_info.pool;
|
c_info->pool = cpp_info.pool;
|
||||||
}
|
}
|
||||||
|
|
||||||
void group_snap_info_cpp_to_c(const librbd::group_snap_info_t &cpp_info,
|
void group_snap_info_cpp_to_c(const librbd::group_snap_info2_t &cpp_info,
|
||||||
rbd_group_snap_info_t *c_info) {
|
rbd_group_snap_info_t *c_info) {
|
||||||
c_info->name = strdup(cpp_info.name.c_str());
|
c_info->name = strdup(cpp_info.name.c_str());
|
||||||
c_info->state = cpp_info.state;
|
c_info->state = cpp_info.state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void group_snap_info2_cpp_to_c(const librbd::group_snap_info2_t &cpp_info,
|
||||||
|
rbd_group_snap_info2_t *c_info) {
|
||||||
|
c_info->id = strdup(cpp_info.id.c_str());
|
||||||
|
c_info->name = strdup(cpp_info.name.c_str());
|
||||||
|
c_info->image_snap_name = strdup(cpp_info.image_snap_name.c_str());
|
||||||
|
c_info->state = cpp_info.state;
|
||||||
|
c_info->image_snaps_count = cpp_info.image_snaps.size();
|
||||||
|
c_info->image_snaps = static_cast<rbd_group_image_snap_info_t*>(calloc(
|
||||||
|
cpp_info.image_snaps.size(), sizeof(rbd_group_image_snap_info_t)));
|
||||||
|
size_t i = 0;
|
||||||
|
for (const auto& cpp_image_snap : cpp_info.image_snaps) {
|
||||||
|
c_info->image_snaps[i].image_name = strdup(
|
||||||
|
cpp_image_snap.image_name.c_str());
|
||||||
|
c_info->image_snaps[i].pool_id = cpp_image_snap.pool_id;
|
||||||
|
c_info->image_snaps[i].snap_id = cpp_image_snap.snap_id;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void mirror_image_info_cpp_to_c(const librbd::mirror_image_info_t &cpp_info,
|
void mirror_image_info_cpp_to_c(const librbd::mirror_image_info_t &cpp_info,
|
||||||
rbd_mirror_image_info_t *c_info) {
|
rbd_mirror_image_info_t *c_info) {
|
||||||
c_info->global_id = strdup(cpp_info.global_id.c_str());
|
c_info->global_id = strdup(cpp_info.global_id.c_str());
|
||||||
@ -1436,11 +1455,34 @@ namespace librbd {
|
|||||||
return -ERANGE;
|
return -ERANGE;
|
||||||
}
|
}
|
||||||
|
|
||||||
int r = librbd::api::Group<>::snap_list(group_ioctx, group_name, snaps);
|
std::vector<group_snap_info2_t> snaps2;
|
||||||
|
int r = librbd::api::Group<>::snap_list(group_ioctx, group_name, &snaps2);
|
||||||
|
|
||||||
|
for (const auto& snap : snaps2) {
|
||||||
|
snaps->push_back(
|
||||||
|
group_snap_info_t {
|
||||||
|
snap.name,
|
||||||
|
snap.state
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
tracepoint(librbd, group_snap_list_exit, r);
|
tracepoint(librbd, group_snap_list_exit, r);
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int RBD::group_snap_list2(IoCtx& group_ioctx, const char *group_name,
|
||||||
|
std::vector<group_snap_info2_t> *snaps)
|
||||||
|
{
|
||||||
|
return librbd::api::Group<>::snap_list(group_ioctx, group_name, snaps);
|
||||||
|
}
|
||||||
|
|
||||||
|
int RBD::group_snap_get_info(IoCtx& group_ioctx, const char *group_name,
|
||||||
|
const char *snap_name,
|
||||||
|
group_snap_info2_t *group_snap) {
|
||||||
|
return librbd::api::Group<>::snap_get_info(group_ioctx, group_name,
|
||||||
|
snap_name, group_snap);
|
||||||
|
}
|
||||||
|
|
||||||
int RBD::group_snap_rename(IoCtx& group_ioctx, const char *group_name,
|
int RBD::group_snap_rename(IoCtx& group_ioctx, const char *group_name,
|
||||||
const char *old_snap_name,
|
const char *old_snap_name,
|
||||||
const char *new_snap_name)
|
const char *new_snap_name)
|
||||||
@ -7230,6 +7272,34 @@ extern "C" int rbd_group_snap_rename(rados_ioctx_t group_p,
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern "C" int rbd_group_snap_get_info(
|
||||||
|
rados_ioctx_t group_p, const char *group_name, const char *snap_name,
|
||||||
|
rbd_group_snap_info2_t *group_snap)
|
||||||
|
{
|
||||||
|
librados::IoCtx group_ioctx;
|
||||||
|
librados::IoCtx::from_rados_ioctx_t(group_p, group_ioctx);
|
||||||
|
|
||||||
|
librbd::group_snap_info2_t cpp_group_snap;
|
||||||
|
int r = librbd::api::Group<>::snap_get_info(group_ioctx, group_name,
|
||||||
|
snap_name, &cpp_group_snap);
|
||||||
|
if (r < 0) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
group_snap_info2_cpp_to_c(cpp_group_snap, group_snap);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" void rbd_group_snap_get_info_cleanup(
|
||||||
|
rbd_group_snap_info2_t *group_snap) {
|
||||||
|
free(group_snap->id);
|
||||||
|
free(group_snap->name);
|
||||||
|
free(group_snap->image_snap_name);
|
||||||
|
for (size_t i = 0; i < group_snap->image_snaps_count; ++i) {
|
||||||
|
free(group_snap->image_snaps[i].image_name);
|
||||||
|
}
|
||||||
|
free(group_snap->image_snaps);
|
||||||
|
}
|
||||||
|
|
||||||
extern "C" int rbd_group_snap_list(rados_ioctx_t group_p,
|
extern "C" int rbd_group_snap_list(rados_ioctx_t group_p,
|
||||||
const char *group_name,
|
const char *group_name,
|
||||||
rbd_group_snap_info_t *snaps,
|
rbd_group_snap_info_t *snaps,
|
||||||
@ -7251,7 +7321,7 @@ extern "C" int rbd_group_snap_list(rados_ioctx_t group_p,
|
|||||||
return -ERANGE;
|
return -ERANGE;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<librbd::group_snap_info_t> cpp_snaps;
|
std::vector<librbd::group_snap_info2_t> cpp_snaps;
|
||||||
int r = librbd::api::Group<>::snap_list(group_ioctx, group_name, &cpp_snaps);
|
int r = librbd::api::Group<>::snap_list(group_ioctx, group_name, &cpp_snaps);
|
||||||
|
|
||||||
if (r == -ENOENT) {
|
if (r == -ENOENT) {
|
||||||
@ -7293,6 +7363,40 @@ extern "C" int rbd_group_snap_list_cleanup(rbd_group_snap_info_t *snaps,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern "C" int rbd_group_snap_list2(rados_ioctx_t group_p,
|
||||||
|
const char *group_name,
|
||||||
|
rbd_group_snap_info2_t *snaps,
|
||||||
|
size_t *snaps_size)
|
||||||
|
{
|
||||||
|
librados::IoCtx group_ioctx;
|
||||||
|
librados::IoCtx::from_rados_ioctx_t(group_p, group_ioctx);
|
||||||
|
|
||||||
|
std::vector<librbd::group_snap_info2_t> cpp_snaps;
|
||||||
|
int r = librbd::api::Group<>::snap_list(group_ioctx, group_name, &cpp_snaps);
|
||||||
|
if (r < 0) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*snaps_size < cpp_snaps.size()) {
|
||||||
|
*snaps_size = cpp_snaps.size();
|
||||||
|
return -ERANGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < cpp_snaps.size(); ++i) {
|
||||||
|
group_snap_info2_cpp_to_c(cpp_snaps[i], &snaps[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
*snaps_size = cpp_snaps.size();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" void rbd_group_snap_list2_cleanup(rbd_group_snap_info2_t *snaps,
|
||||||
|
size_t len) {
|
||||||
|
for (size_t i = 0; i < len; ++i) {
|
||||||
|
rbd_group_snap_get_info_cleanup(&snaps[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
extern "C" int rbd_group_snap_rollback(rados_ioctx_t group_p,
|
extern "C" int rbd_group_snap_rollback(rados_ioctx_t group_p,
|
||||||
const char *group_name,
|
const char *group_name,
|
||||||
const char *snap_name)
|
const char *snap_name)
|
||||||
|
@ -224,9 +224,18 @@ cdef extern from "rbd/librbd.h" nogil:
|
|||||||
_RBD_GROUP_SNAP_STATE_INCOMPLETE "RBD_GROUP_SNAP_STATE_INCOMPLETE"
|
_RBD_GROUP_SNAP_STATE_INCOMPLETE "RBD_GROUP_SNAP_STATE_INCOMPLETE"
|
||||||
_RBD_GROUP_SNAP_STATE_COMPLETE "RBD_GROUP_SNAP_STATE_COMPLETE"
|
_RBD_GROUP_SNAP_STATE_COMPLETE "RBD_GROUP_SNAP_STATE_COMPLETE"
|
||||||
|
|
||||||
ctypedef struct rbd_group_snap_info_t:
|
ctypedef struct rbd_group_image_snap_info_t:
|
||||||
|
char *image_name
|
||||||
|
int64_t pool_id
|
||||||
|
uint64_t snap_id
|
||||||
|
|
||||||
|
ctypedef struct rbd_group_snap_info2_t:
|
||||||
|
char *id
|
||||||
char *name
|
char *name
|
||||||
|
char *image_snap_name
|
||||||
rbd_group_snap_state_t state
|
rbd_group_snap_state_t state
|
||||||
|
size_t image_snaps_count
|
||||||
|
rbd_group_image_snap_info_t *image_snaps
|
||||||
|
|
||||||
ctypedef enum rbd_image_migration_state_t:
|
ctypedef enum rbd_image_migration_state_t:
|
||||||
_RBD_IMAGE_MIGRATION_STATE_UNKNOWN "RBD_IMAGE_MIGRATION_STATE_UNKNOWN"
|
_RBD_IMAGE_MIGRATION_STATE_UNKNOWN "RBD_IMAGE_MIGRATION_STATE_UNKNOWN"
|
||||||
@ -700,14 +709,18 @@ cdef extern from "rbd/librbd.h" nogil:
|
|||||||
const char *old_snap_name,
|
const char *old_snap_name,
|
||||||
const char *new_snap_name)
|
const char *new_snap_name)
|
||||||
|
|
||||||
int rbd_group_snap_list(rados_ioctx_t group_p,
|
int rbd_group_snap_get_info(rados_ioctx_t group_p, const char *group_name,
|
||||||
const char *group_name,
|
const char *snap_name,
|
||||||
rbd_group_snap_info_t *snaps,
|
rbd_group_snap_info2_t *group_snap)
|
||||||
size_t group_snap_info_size,
|
void rbd_group_snap_get_info_cleanup(rbd_group_snap_info2_t *group_snap)
|
||||||
size_t *snaps_size)
|
|
||||||
|
int rbd_group_snap_list2(rados_ioctx_t group_p,
|
||||||
|
const char *group_name,
|
||||||
|
rbd_group_snap_info2_t *snaps,
|
||||||
|
size_t *snaps_size)
|
||||||
|
void rbd_group_snap_list2_cleanup(rbd_group_snap_info2_t *snaps,
|
||||||
|
size_t len)
|
||||||
|
|
||||||
void rbd_group_snap_list_cleanup(rbd_group_snap_info_t *snaps,
|
|
||||||
size_t group_snap_info_size, size_t len)
|
|
||||||
int rbd_group_snap_rollback(rados_ioctx_t group_p, const char *group_name,
|
int rbd_group_snap_rollback(rados_ioctx_t group_p, const char *group_name,
|
||||||
const char *snap_name)
|
const char *snap_name)
|
||||||
|
|
||||||
|
@ -228,9 +228,18 @@ cdef nogil:
|
|||||||
_RBD_GROUP_SNAP_STATE_INCOMPLETE "RBD_GROUP_SNAP_STATE_INCOMPLETE"
|
_RBD_GROUP_SNAP_STATE_INCOMPLETE "RBD_GROUP_SNAP_STATE_INCOMPLETE"
|
||||||
_RBD_GROUP_SNAP_STATE_COMPLETE "RBD_GROUP_SNAP_STATE_COMPLETE"
|
_RBD_GROUP_SNAP_STATE_COMPLETE "RBD_GROUP_SNAP_STATE_COMPLETE"
|
||||||
|
|
||||||
ctypedef struct rbd_group_snap_info_t:
|
ctypedef struct rbd_group_image_snap_info_t:
|
||||||
|
char *image_name
|
||||||
|
int64_t pool_id
|
||||||
|
uint64_t snap_id
|
||||||
|
|
||||||
|
ctypedef struct rbd_group_snap_info2_t:
|
||||||
|
char *id
|
||||||
char *name
|
char *name
|
||||||
|
char *image_snap_name
|
||||||
rbd_group_snap_state_t state
|
rbd_group_snap_state_t state
|
||||||
|
size_t image_snaps_count
|
||||||
|
rbd_group_image_snap_info_t *image_snaps
|
||||||
|
|
||||||
ctypedef enum rbd_image_migration_state_t:
|
ctypedef enum rbd_image_migration_state_t:
|
||||||
_RBD_IMAGE_MIGRATION_STATE_UNKNOWN "RBD_IMAGE_MIGRATION_STATE_UNKNOWN"
|
_RBD_IMAGE_MIGRATION_STATE_UNKNOWN "RBD_IMAGE_MIGRATION_STATE_UNKNOWN"
|
||||||
@ -886,14 +895,19 @@ cdef nogil:
|
|||||||
const char *old_snap_name,
|
const char *old_snap_name,
|
||||||
const char *new_snap_name):
|
const char *new_snap_name):
|
||||||
pass
|
pass
|
||||||
int rbd_group_snap_list(rados_ioctx_t group_p,
|
int rbd_group_snap_list2(rados_ioctx_t group_p,
|
||||||
const char *group_name,
|
const char *group_name,
|
||||||
rbd_group_snap_info_t *snaps,
|
rbd_group_snap_info2_t *snaps,
|
||||||
size_t group_snap_info_size,
|
size_t *snaps_size):
|
||||||
size_t *snaps_size):
|
|
||||||
pass
|
pass
|
||||||
void rbd_group_snap_list_cleanup(rbd_group_snap_info_t *snaps,
|
void rbd_group_snap_list2_cleanup(rbd_group_snap_info2_t *snaps,
|
||||||
size_t group_snap_info_size, size_t len):
|
size_t len):
|
||||||
|
pass
|
||||||
|
int rbd_group_snap_get_info(rados_ioctx_t group_p, const char *group_name,
|
||||||
|
const char *snap_name,
|
||||||
|
rbd_group_snap_info2_t *group_snap):
|
||||||
|
pass
|
||||||
|
void rbd_group_snap_get_info_cleanup(rbd_group_snap_info2_t *group_snap):
|
||||||
pass
|
pass
|
||||||
int rbd_group_snap_rollback(rados_ioctx_t group_p, const char *group_name,
|
int rbd_group_snap_rollback(rados_ioctx_t group_p, const char *group_name,
|
||||||
const char *snap_name):
|
const char *snap_name):
|
||||||
|
@ -2778,6 +2778,71 @@ cdef class Group(object):
|
|||||||
if ret != 0:
|
if ret != 0:
|
||||||
raise make_ex(ret, 'error removing group snapshot', group_errno_to_exception)
|
raise make_ex(ret, 'error removing group snapshot', group_errno_to_exception)
|
||||||
|
|
||||||
|
def get_snap_info(self, snap_name):
|
||||||
|
"""
|
||||||
|
Get information about a group snapshot.
|
||||||
|
|
||||||
|
:param snap_name: the name of the snapshot to get
|
||||||
|
:type name: str
|
||||||
|
|
||||||
|
:raises: :class:`ObjectNotFound`
|
||||||
|
:raises: :class:`InvalidArgument`
|
||||||
|
:raises: :class:`FunctionNotSupported`
|
||||||
|
|
||||||
|
:returns: dict - contains the following keys:
|
||||||
|
|
||||||
|
* ``id`` (str) - ID of the group snapshot
|
||||||
|
|
||||||
|
* ``name`` (str) - name of the group snapshot
|
||||||
|
|
||||||
|
* ``state`` (int) - state of the group snapshot
|
||||||
|
|
||||||
|
* ``image_snap_name`` (str) - name of the image snapshots
|
||||||
|
|
||||||
|
* ``image_snaps`` (list) - image snapshots that constitute the group snapshot.
|
||||||
|
|
||||||
|
Each image snapshot is itself a dictionary with keys:
|
||||||
|
|
||||||
|
* ``pool_id`` (int) - ID of the image's pool
|
||||||
|
|
||||||
|
* ``snap_id`` (int) - ID of the image snapshot
|
||||||
|
|
||||||
|
* ``image_name`` (str) - name of the image
|
||||||
|
|
||||||
|
"""
|
||||||
|
snap_name = cstr(snap_name, 'snap_name')
|
||||||
|
cdef:
|
||||||
|
char *_snap_name = snap_name
|
||||||
|
rbd_group_snap_info2_t group_snap
|
||||||
|
|
||||||
|
with nogil:
|
||||||
|
ret = rbd_group_snap_get_info(self._ioctx, self._name,
|
||||||
|
_snap_name, &group_snap)
|
||||||
|
if ret != 0:
|
||||||
|
raise make_ex(ret, 'error showing a group snapshot',
|
||||||
|
group_errno_to_exception)
|
||||||
|
image_snaps = []
|
||||||
|
for i in range(group_snap.image_snaps_count):
|
||||||
|
image_snap = &group_snap.image_snaps[i]
|
||||||
|
image_snaps.append(
|
||||||
|
{
|
||||||
|
'pool_id': image_snap.pool_id,
|
||||||
|
'snap_id': image_snap.snap_id,
|
||||||
|
'image_name': decode_cstr(image_snap.image_name),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
snap_info = {
|
||||||
|
'id': decode_cstr(group_snap.id),
|
||||||
|
'name': decode_cstr(group_snap.name),
|
||||||
|
'state': group_snap.state,
|
||||||
|
'image_snap_name': decode_cstr(group_snap.image_snap_name),
|
||||||
|
'image_snaps': image_snaps
|
||||||
|
}
|
||||||
|
|
||||||
|
rbd_group_snap_get_info_cleanup(&group_snap)
|
||||||
|
|
||||||
|
return snap_info
|
||||||
|
|
||||||
def rename_snap(self, old_snap_name, new_snap_name):
|
def rename_snap(self, old_snap_name, new_snap_name):
|
||||||
"""
|
"""
|
||||||
Rename group's snapshot.
|
Rename group's snapshot.
|
||||||
@ -2802,7 +2867,7 @@ cdef class Group(object):
|
|||||||
|
|
||||||
def list_snaps(self):
|
def list_snaps(self):
|
||||||
"""
|
"""
|
||||||
Iterate over the images of a group.
|
Iterate over the snapshots of a group.
|
||||||
|
|
||||||
:returns: :class:`GroupSnapIterator`
|
:returns: :class:`GroupSnapIterator`
|
||||||
"""
|
"""
|
||||||
@ -5934,47 +5999,72 @@ cdef class GroupSnapIterator(object):
|
|||||||
"""
|
"""
|
||||||
Iterator over snaps specs for a group.
|
Iterator over snaps specs for a group.
|
||||||
|
|
||||||
Yields a dictionary containing information about a snapshot.
|
Yields a dictionary containing information about a group snapshot.
|
||||||
|
|
||||||
Keys are:
|
Keys are:
|
||||||
|
|
||||||
* ``name`` (str) - name of the snapshot
|
* ``id`` (str) - ID of the group snapshot
|
||||||
|
|
||||||
* ``state`` (int) - state of the snapshot
|
* ``name`` (str) - name of the group snapshot
|
||||||
|
|
||||||
|
* ``state`` (int) - state of the group snapshot
|
||||||
|
|
||||||
|
* ``image_snap_name`` (str) - name of the image snapshots
|
||||||
|
|
||||||
|
* ``image_snaps`` (list) - image snapshots that constitute the group snapshot.
|
||||||
|
|
||||||
|
Each image snapshot is itself a dictionary with keys:
|
||||||
|
|
||||||
|
* ``pool_id`` (int) - ID of the image's pool
|
||||||
|
|
||||||
|
* ``snap_id`` (int) - ID of the image snapshot
|
||||||
|
|
||||||
|
* ``image_name`` (str) - name of the image
|
||||||
"""
|
"""
|
||||||
|
|
||||||
cdef rbd_group_snap_info_t *snaps
|
cdef rbd_group_snap_info2_t *group_snaps
|
||||||
cdef size_t num_snaps
|
cdef size_t num_group_snaps
|
||||||
cdef object group
|
cdef object group
|
||||||
|
|
||||||
def __init__(self, Group group):
|
def __init__(self, Group group):
|
||||||
self.group = group
|
self.group = group
|
||||||
self.snaps = NULL
|
self.group_snaps = NULL
|
||||||
self.num_snaps = 10
|
self.num_group_snaps = 10
|
||||||
while True:
|
while True:
|
||||||
self.snaps = <rbd_group_snap_info_t*>realloc_chk(self.snaps,
|
self.group_snaps = <rbd_group_snap_info2_t*>realloc_chk(
|
||||||
self.num_snaps *
|
self.group_snaps, self.num_group_snaps * sizeof(rbd_group_snap_info2_t))
|
||||||
sizeof(rbd_group_snap_info_t))
|
|
||||||
with nogil:
|
with nogil:
|
||||||
ret = rbd_group_snap_list(group._ioctx, group._name, self.snaps,
|
ret = rbd_group_snap_list2(group._ioctx, group._name, self.group_snaps,
|
||||||
sizeof(rbd_group_snap_info_t),
|
&self.num_group_snaps)
|
||||||
&self.num_snaps)
|
|
||||||
|
|
||||||
if ret >= 0:
|
if ret >= 0:
|
||||||
break
|
break
|
||||||
elif ret != -errno.ERANGE:
|
elif ret != -errno.ERANGE:
|
||||||
raise make_ex(ret, 'error listing snapshots for group %s' % group.name, group_errno_to_exception)
|
raise make_ex(ret, 'error listing snapshots for group %s' % group.name, group_errno_to_exception)
|
||||||
|
|
||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
for i in range(self.num_snaps):
|
for i in range(self.num_group_snaps):
|
||||||
|
group_snap = &self.group_snaps[i]
|
||||||
|
image_snaps = []
|
||||||
|
for j in range(group_snap.image_snaps_count):
|
||||||
|
image_snap = &group_snap.image_snaps[j]
|
||||||
|
image_snaps.append(
|
||||||
|
{
|
||||||
|
'pool_id': image_snap.pool_id,
|
||||||
|
'snap_id': image_snap.snap_id,
|
||||||
|
'image_name': decode_cstr(image_snap.image_name),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
yield {
|
yield {
|
||||||
'name' : decode_cstr(self.snaps[i].name),
|
'id': decode_cstr(group_snap.id),
|
||||||
'state' : self.snaps[i].state,
|
'name': decode_cstr(group_snap.name),
|
||||||
}
|
'state': group_snap.state,
|
||||||
|
'image_snap_name': decode_cstr(group_snap.image_snap_name),
|
||||||
|
'image_snaps': image_snaps,
|
||||||
|
}
|
||||||
|
|
||||||
def __dealloc__(self):
|
def __dealloc__(self):
|
||||||
if self.snaps:
|
if self.group_snaps:
|
||||||
rbd_group_snap_list_cleanup(self.snaps,
|
rbd_group_snap_list2_cleanup(self.group_snaps,
|
||||||
sizeof(rbd_group_snap_info_t),
|
self.num_group_snaps)
|
||||||
self.num_snaps)
|
free(self.group_snaps)
|
||||||
free(self.snaps)
|
|
||||||
|
@ -53,6 +53,7 @@
|
|||||||
group remove (group rm) Delete a group.
|
group remove (group rm) Delete a group.
|
||||||
group rename Rename a group within pool.
|
group rename Rename a group within pool.
|
||||||
group snap create Make a snapshot of a group.
|
group snap create Make a snapshot of a group.
|
||||||
|
group snap info Show information about a group snapshot.
|
||||||
group snap list (... ls) List snapshots of a group.
|
group snap list (... ls) List snapshots of a group.
|
||||||
group snap remove (... rm) Remove a snapshot from a group.
|
group snap remove (... rm) Remove a snapshot from a group.
|
||||||
group snap rename Rename group's snapshot.
|
group snap rename Rename group's snapshot.
|
||||||
@ -1070,6 +1071,27 @@
|
|||||||
--skip-quiesce do not run quiesce hooks
|
--skip-quiesce do not run quiesce hooks
|
||||||
--ignore-quiesce-error ignore quiesce hook error
|
--ignore-quiesce-error ignore quiesce hook error
|
||||||
|
|
||||||
|
rbd help group snap info
|
||||||
|
usage: rbd group snap info [--pool <pool>] [--namespace <namespace>]
|
||||||
|
[--group <group>] [--snap <snap>]
|
||||||
|
[--format <format>] [--pretty-format]
|
||||||
|
<group-snap-spec>
|
||||||
|
|
||||||
|
Show information about a group snapshot.
|
||||||
|
|
||||||
|
Positional arguments
|
||||||
|
<group-snap-spec> group specification
|
||||||
|
(example:
|
||||||
|
[<pool-name>/[<namespace>/]]<group-name>@<snap-name>)
|
||||||
|
|
||||||
|
Optional arguments
|
||||||
|
-p [ --pool ] arg pool name
|
||||||
|
--namespace arg namespace name
|
||||||
|
--group arg group name
|
||||||
|
--snap arg snapshot name
|
||||||
|
--format arg output format (plain, json, or xml) [default: plain]
|
||||||
|
--pretty-format pretty formatting (json and xml)
|
||||||
|
|
||||||
rbd help group snap list
|
rbd help group snap list
|
||||||
usage: rbd group snap list [--format <format>] [--pretty-format]
|
usage: rbd group snap list [--format <format>] [--pretty-format]
|
||||||
[--pool <pool>] [--namespace <namespace>]
|
[--pool <pool>] [--namespace <namespace>]
|
||||||
|
@ -489,3 +489,263 @@ TEST_F(TestGroup, add_snapshotPP)
|
|||||||
ASSERT_EQ(0, rbd.group_snap_remove(ioctx, group_name, snap_name));
|
ASSERT_EQ(0, rbd.group_snap_remove(ioctx, group_name, snap_name));
|
||||||
ASSERT_EQ(0, rbd.group_remove(ioctx, group_name));
|
ASSERT_EQ(0, rbd.group_remove(ioctx, group_name));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(TestGroup, snap_get_info)
|
||||||
|
{
|
||||||
|
REQUIRE_FORMAT_V2();
|
||||||
|
|
||||||
|
std::string pool_name2 = get_temp_pool_name("test-librbd-");
|
||||||
|
ASSERT_EQ(0, rados_pool_create(_cluster, pool_name2.c_str()));
|
||||||
|
|
||||||
|
rados_ioctx_t ioctx;
|
||||||
|
ASSERT_EQ(0, rados_ioctx_create(_cluster, _pool_name.c_str(), &ioctx));
|
||||||
|
|
||||||
|
rados_ioctx_t ioctx2;
|
||||||
|
ASSERT_EQ(0, rados_ioctx_create(_cluster, pool_name2.c_str(), &ioctx2));
|
||||||
|
|
||||||
|
const char *gp_name = "gp_snapgetinfo";
|
||||||
|
ASSERT_EQ(0, rbd_group_create(ioctx2, gp_name));
|
||||||
|
ASSERT_EQ(0, rbd_group_image_add(ioctx2, gp_name, ioctx,
|
||||||
|
m_image_name.c_str()));
|
||||||
|
|
||||||
|
const char *gp_snap_name = "snap_snapshot";
|
||||||
|
ASSERT_EQ(0, rbd_group_snap_create(ioctx2, gp_name, gp_snap_name));
|
||||||
|
|
||||||
|
rbd_group_snap_info2_t gp_snap_info;
|
||||||
|
ASSERT_EQ(-ENOENT, rbd_group_snap_get_info(ioctx2, "absent", gp_snap_name,
|
||||||
|
&gp_snap_info));
|
||||||
|
ASSERT_EQ(-ENOENT, rbd_group_snap_get_info(ioctx2, gp_name, "absent",
|
||||||
|
&gp_snap_info));
|
||||||
|
|
||||||
|
ASSERT_EQ(0, rbd_group_snap_get_info(ioctx2, gp_name, gp_snap_name,
|
||||||
|
&gp_snap_info));
|
||||||
|
ASSERT_STREQ(gp_snap_name, gp_snap_info.name);
|
||||||
|
ASSERT_EQ(RBD_GROUP_SNAP_STATE_COMPLETE, gp_snap_info.state);
|
||||||
|
ASSERT_EQ(1U, gp_snap_info.image_snaps_count);
|
||||||
|
ASSERT_EQ(m_image_name, gp_snap_info.image_snaps[0].image_name);
|
||||||
|
ASSERT_EQ(rados_ioctx_get_id(ioctx), gp_snap_info.image_snaps[0].pool_id);
|
||||||
|
|
||||||
|
rbd_group_snap_get_info_cleanup(&gp_snap_info);
|
||||||
|
ASSERT_EQ(0, rbd_group_snap_remove(ioctx2, gp_name, gp_snap_name));
|
||||||
|
ASSERT_EQ(0, rbd_group_remove(ioctx2, gp_name));
|
||||||
|
rados_ioctx_destroy(ioctx2);
|
||||||
|
rados_ioctx_destroy(ioctx);
|
||||||
|
ASSERT_EQ(0, rados_pool_delete(_cluster, pool_name2.c_str()));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(TestGroup, snap_get_infoPP)
|
||||||
|
{
|
||||||
|
REQUIRE_FORMAT_V2();
|
||||||
|
|
||||||
|
std::string pool_name2 = get_temp_pool_name("test-librbd-");
|
||||||
|
ASSERT_EQ(0, _rados.pool_create(pool_name2.c_str()));
|
||||||
|
|
||||||
|
librados::IoCtx ioctx2;
|
||||||
|
ASSERT_EQ(0, _rados.ioctx_create(pool_name2.c_str(), ioctx2));
|
||||||
|
|
||||||
|
const char *gp_name = "gp_snapgetinfoPP";
|
||||||
|
ASSERT_EQ(0, m_rbd.group_create(ioctx2, gp_name));
|
||||||
|
ASSERT_EQ(0, m_rbd.group_image_add(ioctx2, gp_name, m_ioctx,
|
||||||
|
m_image_name.c_str()));
|
||||||
|
|
||||||
|
const char *gp_snap_name = "snap_snapshot";
|
||||||
|
ASSERT_EQ(0, m_rbd.group_snap_create(ioctx2, gp_name, gp_snap_name));
|
||||||
|
|
||||||
|
librbd::group_snap_info2_t gp_snap_info;
|
||||||
|
ASSERT_EQ(-ENOENT, m_rbd.group_snap_get_info(ioctx2, "absent", gp_snap_name,
|
||||||
|
&gp_snap_info));
|
||||||
|
ASSERT_EQ(-ENOENT, m_rbd.group_snap_get_info(ioctx2, gp_name, "absent",
|
||||||
|
&gp_snap_info));
|
||||||
|
|
||||||
|
ASSERT_EQ(0, m_rbd.group_snap_get_info(ioctx2, gp_name, gp_snap_name,
|
||||||
|
&gp_snap_info));
|
||||||
|
ASSERT_EQ(gp_snap_name, gp_snap_info.name);
|
||||||
|
ASSERT_EQ(RBD_GROUP_SNAP_STATE_COMPLETE, gp_snap_info.state);
|
||||||
|
ASSERT_EQ(1U, gp_snap_info.image_snaps.size());
|
||||||
|
ASSERT_EQ(m_image_name, gp_snap_info.image_snaps[0].image_name);
|
||||||
|
ASSERT_EQ(m_ioctx.get_id(), gp_snap_info.image_snaps[0].pool_id);
|
||||||
|
|
||||||
|
ASSERT_EQ(0, m_rbd.group_snap_remove(ioctx2, gp_name, gp_snap_name));
|
||||||
|
ASSERT_EQ(0, m_rbd.group_remove(ioctx2, gp_name));
|
||||||
|
ASSERT_EQ(0, _rados.pool_delete(pool_name2.c_str()));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(TestGroup, snap_list2)
|
||||||
|
{
|
||||||
|
REQUIRE_FORMAT_V2();
|
||||||
|
|
||||||
|
std::string pool_name2 = get_temp_pool_name("test-librbd-");
|
||||||
|
ASSERT_EQ(0, rados_pool_create(_cluster, pool_name2.c_str()));
|
||||||
|
|
||||||
|
rados_ioctx_t ioctx;
|
||||||
|
ASSERT_EQ(0, rados_ioctx_create(_cluster, _pool_name.c_str(), &ioctx));
|
||||||
|
|
||||||
|
rados_ioctx_t ioctx2;
|
||||||
|
ASSERT_EQ(0, rados_ioctx_create(_cluster, pool_name2.c_str(), &ioctx2));
|
||||||
|
|
||||||
|
std::string image_name2 = get_temp_image_name();
|
||||||
|
uint64_t features;
|
||||||
|
int order = 0;
|
||||||
|
ASSERT_TRUE(get_features(&features));
|
||||||
|
ASSERT_EQ(0, rbd_create2(ioctx2, image_name2.c_str(), m_image_size, features,
|
||||||
|
&order));
|
||||||
|
|
||||||
|
const char *gp_name = "gp_snaplist2";
|
||||||
|
ASSERT_EQ(0, rbd_group_create(ioctx, gp_name));
|
||||||
|
|
||||||
|
size_t num_snaps = 10U;
|
||||||
|
auto gp_snaps = static_cast<rbd_group_snap_info2_t*>(calloc(
|
||||||
|
num_snaps, sizeof(rbd_group_snap_info2_t)));
|
||||||
|
ASSERT_EQ(-ENOENT, rbd_group_snap_list2(ioctx, "absent", gp_snaps,
|
||||||
|
&num_snaps));
|
||||||
|
ASSERT_EQ(0, rbd_group_snap_list2(ioctx, gp_name, gp_snaps, &num_snaps));
|
||||||
|
ASSERT_EQ(0U, num_snaps);
|
||||||
|
|
||||||
|
const char* const gp_snap_names[] = {
|
||||||
|
"snap_snapshot0", "snap_snapshot1", "snap_snapshot2", "snap_snapshot3"};
|
||||||
|
ASSERT_EQ(0, rbd_group_snap_create(ioctx, gp_name, gp_snap_names[0]));
|
||||||
|
|
||||||
|
ASSERT_EQ(0, rbd_group_image_add(ioctx, gp_name, ioctx,
|
||||||
|
m_image_name.c_str()));
|
||||||
|
ASSERT_EQ(0, rbd_group_snap_create(ioctx, gp_name, gp_snap_names[1]));
|
||||||
|
|
||||||
|
ASSERT_EQ(0, rbd_group_image_add(ioctx, gp_name, ioctx2,
|
||||||
|
image_name2.c_str()));
|
||||||
|
ASSERT_EQ(0, rbd_group_snap_create(ioctx, gp_name, gp_snap_names[2]));
|
||||||
|
|
||||||
|
ASSERT_EQ(0, rbd_group_image_remove(ioctx, gp_name, ioctx,
|
||||||
|
m_image_name.c_str()));
|
||||||
|
ASSERT_EQ(0, rbd_group_snap_create(ioctx, gp_name, gp_snap_names[3]));
|
||||||
|
|
||||||
|
num_snaps = 3U;
|
||||||
|
ASSERT_EQ(-ERANGE, rbd_group_snap_list2(ioctx, gp_name, gp_snaps,
|
||||||
|
&num_snaps));
|
||||||
|
ASSERT_EQ(4U, num_snaps);
|
||||||
|
ASSERT_EQ(0, rbd_group_snap_list2(ioctx, gp_name, gp_snaps, &num_snaps));
|
||||||
|
ASSERT_EQ(4U, num_snaps);
|
||||||
|
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
ASSERT_EQ(RBD_GROUP_SNAP_STATE_COMPLETE, gp_snaps[i].state);
|
||||||
|
if (!strcmp(gp_snaps[i].name, gp_snap_names[0])) {
|
||||||
|
ASSERT_EQ(0U, gp_snaps[i].image_snaps_count);
|
||||||
|
} else if (!strcmp(gp_snaps[i].name, gp_snap_names[1])) {
|
||||||
|
ASSERT_EQ(1U, gp_snaps[i].image_snaps_count);
|
||||||
|
ASSERT_EQ(m_image_name, gp_snaps[i].image_snaps[0].image_name);
|
||||||
|
ASSERT_EQ(rados_ioctx_get_id(ioctx), gp_snaps[i].image_snaps[0].pool_id);
|
||||||
|
} else if (!strcmp(gp_snaps[i].name, gp_snap_names[2])) {
|
||||||
|
ASSERT_EQ(2U, gp_snaps[i].image_snaps_count);
|
||||||
|
for (int j = 0; j < 2; j++) {
|
||||||
|
if (m_image_name == gp_snaps[i].image_snaps[j].image_name) {
|
||||||
|
ASSERT_EQ(rados_ioctx_get_id(ioctx),
|
||||||
|
gp_snaps[i].image_snaps[j].pool_id);
|
||||||
|
} else if (image_name2 == gp_snaps[i].image_snaps[j].image_name) {
|
||||||
|
ASSERT_EQ(rados_ioctx_get_id(ioctx2),
|
||||||
|
gp_snaps[i].image_snaps[j].pool_id);
|
||||||
|
} else {
|
||||||
|
FAIL() << "Unexpected image in group snap: "
|
||||||
|
<< gp_snaps[i].image_snaps[j].image_name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (!strcmp(gp_snaps[i].name, gp_snap_names[3])) {
|
||||||
|
ASSERT_EQ(1U, gp_snaps[i].image_snaps_count);
|
||||||
|
ASSERT_EQ(image_name2, gp_snaps[i].image_snaps[0].image_name);
|
||||||
|
ASSERT_EQ(rados_ioctx_get_id(ioctx2),
|
||||||
|
gp_snaps[i].image_snaps[0].pool_id);
|
||||||
|
} else {
|
||||||
|
FAIL() << "Unexpected group snap: " << gp_snaps[i].name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& gp_snap_name : gp_snap_names) {
|
||||||
|
ASSERT_EQ(0, rbd_group_snap_remove(ioctx, gp_name, gp_snap_name));
|
||||||
|
}
|
||||||
|
rbd_group_snap_list2_cleanup(gp_snaps, num_snaps);
|
||||||
|
free(gp_snaps);
|
||||||
|
ASSERT_EQ(0, rbd_group_snap_list2(ioctx, gp_name, NULL, &num_snaps));
|
||||||
|
ASSERT_EQ(0U, num_snaps);
|
||||||
|
ASSERT_EQ(0, rbd_group_remove(ioctx, gp_name));
|
||||||
|
rados_ioctx_destroy(ioctx2);
|
||||||
|
rados_ioctx_destroy(ioctx);
|
||||||
|
ASSERT_EQ(0, rados_pool_delete(_cluster, pool_name2.c_str()));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(TestGroup, snap_list2PP)
|
||||||
|
{
|
||||||
|
REQUIRE_FORMAT_V2();
|
||||||
|
|
||||||
|
std::string pool_name2 = get_temp_pool_name("test-librbd-");
|
||||||
|
ASSERT_EQ(0, _rados.pool_create(pool_name2.c_str()));
|
||||||
|
|
||||||
|
librados::IoCtx ioctx2;
|
||||||
|
ASSERT_EQ(0, _rados.ioctx_create(pool_name2.c_str(), ioctx2));
|
||||||
|
|
||||||
|
std::string image_name2 = get_temp_image_name();
|
||||||
|
ASSERT_EQ(0, create_image_pp(m_rbd, ioctx2, image_name2.c_str(),
|
||||||
|
m_image_size));
|
||||||
|
|
||||||
|
const char *gp_name = "gp_snaplist2PP";
|
||||||
|
ASSERT_EQ(0, m_rbd.group_create(m_ioctx, gp_name));
|
||||||
|
|
||||||
|
std::vector<librbd::group_snap_info2_t> gp_snaps;
|
||||||
|
ASSERT_EQ(-ENOENT, m_rbd.group_snap_list2(m_ioctx, "absent", &gp_snaps));
|
||||||
|
ASSERT_EQ(0, m_rbd.group_snap_list2(m_ioctx, gp_name, &gp_snaps));
|
||||||
|
ASSERT_EQ(0U, gp_snaps.size());
|
||||||
|
|
||||||
|
const char* const gp_snap_names[] = {
|
||||||
|
"snap_snapshot0", "snap_snapshot1", "snap_snapshot2", "snap_snapshot3"};
|
||||||
|
|
||||||
|
ASSERT_EQ(0, m_rbd.group_snap_create(m_ioctx, gp_name, gp_snap_names[0]));
|
||||||
|
|
||||||
|
ASSERT_EQ(0, m_rbd.group_image_add(m_ioctx, gp_name, m_ioctx,
|
||||||
|
m_image_name.c_str()));
|
||||||
|
ASSERT_EQ(0, m_rbd.group_snap_create(m_ioctx, gp_name, gp_snap_names[1]));
|
||||||
|
|
||||||
|
ASSERT_EQ(0, m_rbd.group_image_add(m_ioctx, gp_name, ioctx2,
|
||||||
|
image_name2.c_str()));
|
||||||
|
ASSERT_EQ(0, m_rbd.group_snap_create(m_ioctx, gp_name, gp_snap_names[2]));
|
||||||
|
|
||||||
|
ASSERT_EQ(0, m_rbd.group_image_remove(m_ioctx, gp_name,
|
||||||
|
m_ioctx, m_image_name.c_str()));
|
||||||
|
ASSERT_EQ(0, m_rbd.group_snap_create(m_ioctx, gp_name, gp_snap_names[3]));
|
||||||
|
|
||||||
|
ASSERT_EQ(0, m_rbd.group_snap_list2(m_ioctx, gp_name, &gp_snaps));
|
||||||
|
ASSERT_EQ(4U, gp_snaps.size());
|
||||||
|
|
||||||
|
for (const auto& gp_snap : gp_snaps) {
|
||||||
|
ASSERT_EQ(RBD_GROUP_SNAP_STATE_COMPLETE, gp_snap.state);
|
||||||
|
if (gp_snap.name == gp_snap_names[0]) {
|
||||||
|
ASSERT_EQ(0U, gp_snap.image_snaps.size());
|
||||||
|
} else if (gp_snap.name == gp_snap_names[1]) {
|
||||||
|
ASSERT_EQ(1U, gp_snap.image_snaps.size());
|
||||||
|
ASSERT_EQ(m_image_name, gp_snap.image_snaps[0].image_name);
|
||||||
|
ASSERT_EQ(m_ioctx.get_id(), gp_snap.image_snaps[0].pool_id);
|
||||||
|
} else if (gp_snap.name == gp_snap_names[2]) {
|
||||||
|
ASSERT_EQ(2U, gp_snap.image_snaps.size());
|
||||||
|
for (const auto& image_snap : gp_snap.image_snaps) {
|
||||||
|
if (image_snap.image_name == m_image_name) {
|
||||||
|
ASSERT_EQ(m_ioctx.get_id(), image_snap.pool_id);
|
||||||
|
} else if (image_snap.image_name == image_name2) {
|
||||||
|
ASSERT_EQ(ioctx2.get_id(), image_snap.pool_id);
|
||||||
|
} else {
|
||||||
|
FAIL() << "Unexpected image in group snap: "
|
||||||
|
<< image_snap.image_name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (gp_snap.name == gp_snap_names[3]) {
|
||||||
|
ASSERT_EQ(1U, gp_snap.image_snaps.size());
|
||||||
|
ASSERT_EQ(image_name2, gp_snap.image_snaps[0].image_name);
|
||||||
|
ASSERT_EQ(ioctx2.get_id(), gp_snap.image_snaps[0].pool_id);
|
||||||
|
} else {
|
||||||
|
FAIL() << "Unexpected group snap: " << gp_snap.name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& gp_snap_name : gp_snap_names) {
|
||||||
|
ASSERT_EQ(0, m_rbd.group_snap_remove(m_ioctx, gp_name, gp_snap_name));
|
||||||
|
}
|
||||||
|
std::vector<librbd::group_snap_info2_t> gp_snaps2;
|
||||||
|
ASSERT_EQ(0, m_rbd.group_snap_list2(m_ioctx, gp_name, &gp_snaps2));
|
||||||
|
ASSERT_EQ(0U, gp_snaps2.size());
|
||||||
|
ASSERT_EQ(0, m_rbd.group_remove(m_ioctx, gp_name));
|
||||||
|
ASSERT_EQ(0, _rados.pool_delete(pool_name2.c_str()));
|
||||||
|
}
|
||||||
|
@ -20,7 +20,7 @@ from rados import (Rados,
|
|||||||
LIBRADOS_OP_FLAG_FADVISE_NOCACHE,
|
LIBRADOS_OP_FLAG_FADVISE_NOCACHE,
|
||||||
LIBRADOS_OP_FLAG_FADVISE_RANDOM)
|
LIBRADOS_OP_FLAG_FADVISE_RANDOM)
|
||||||
from rbd import (RBD, Group, Image, ImageNotFound, InvalidArgument, ImageExists,
|
from rbd import (RBD, Group, Image, ImageNotFound, InvalidArgument, ImageExists,
|
||||||
ImageBusy, ImageHasSnapshots, ReadOnlyImage,
|
ImageBusy, ImageHasSnapshots, ReadOnlyImage, ObjectNotFound,
|
||||||
FunctionNotSupported, ArgumentOutOfRange,
|
FunctionNotSupported, ArgumentOutOfRange,
|
||||||
ECANCELED, OperationCanceled,
|
ECANCELED, OperationCanceled,
|
||||||
DiskQuotaExceeded, ConnectionShutdown, PermissionError,
|
DiskQuotaExceeded, ConnectionShutdown, PermissionError,
|
||||||
@ -49,7 +49,7 @@ from rbd import (RBD, Group, Image, ImageNotFound, InvalidArgument, ImageExists,
|
|||||||
RBD_SNAP_CREATE_IGNORE_QUIESCE_ERROR,
|
RBD_SNAP_CREATE_IGNORE_QUIESCE_ERROR,
|
||||||
RBD_WRITE_ZEROES_FLAG_THICK_PROVISION,
|
RBD_WRITE_ZEROES_FLAG_THICK_PROVISION,
|
||||||
RBD_ENCRYPTION_FORMAT_LUKS1, RBD_ENCRYPTION_FORMAT_LUKS2,
|
RBD_ENCRYPTION_FORMAT_LUKS1, RBD_ENCRYPTION_FORMAT_LUKS2,
|
||||||
RBD_ENCRYPTION_FORMAT_LUKS)
|
RBD_ENCRYPTION_FORMAT_LUKS, RBD_GROUP_SNAP_STATE_COMPLETE)
|
||||||
|
|
||||||
rados = None
|
rados = None
|
||||||
ioctx = None
|
ioctx = None
|
||||||
@ -2809,6 +2809,8 @@ def test_list_groups_after_removed():
|
|||||||
eq([], RBD().group_list(ioctx))
|
eq([], RBD().group_list(ioctx))
|
||||||
|
|
||||||
class TestGroups(object):
|
class TestGroups(object):
|
||||||
|
img_snap_keys = ['image_name', 'pool_id', 'snap_id']
|
||||||
|
gp_snap_keys = ['id', 'image_snap_name', 'image_snaps', 'name', 'state']
|
||||||
|
|
||||||
def setup_method(self, method):
|
def setup_method(self, method):
|
||||||
global snap_name
|
global snap_name
|
||||||
@ -2882,6 +2884,35 @@ class TestGroups(object):
|
|||||||
with Image(ioctx, image_name) as image:
|
with Image(ioctx, image_name) as image:
|
||||||
eq(0, image.op_features() & RBD_OPERATION_FEATURE_GROUP)
|
eq(0, image.op_features() & RBD_OPERATION_FEATURE_GROUP)
|
||||||
|
|
||||||
|
def test_group_snap_get_info(self):
|
||||||
|
self.image_names.append(create_image())
|
||||||
|
self.image_names.sort()
|
||||||
|
self.group.add_image(ioctx, self.image_names[0])
|
||||||
|
self.group.add_image(ioctx, self.image_names[1])
|
||||||
|
pool_id = ioctx.get_pool_id()
|
||||||
|
|
||||||
|
assert_raises(ObjectNotFound, self.group.get_snap_info, "")
|
||||||
|
|
||||||
|
self.group.create_snap(snap_name)
|
||||||
|
snap_info_dict = self.group.get_snap_info(snap_name)
|
||||||
|
image_names = []
|
||||||
|
assert sorted(snap_info_dict.keys()) == self.gp_snap_keys
|
||||||
|
assert snap_info_dict['name'] == snap_name
|
||||||
|
assert snap_info_dict['state'] == RBD_GROUP_SNAP_STATE_COMPLETE
|
||||||
|
for image_snap in snap_info_dict['image_snaps']:
|
||||||
|
assert sorted(image_snap.keys()) == self.img_snap_keys
|
||||||
|
assert image_snap['pool_id'] == pool_id
|
||||||
|
image_names.append(image_snap['image_name'])
|
||||||
|
with Image(ioctx, image_snap['image_name']) as member_image:
|
||||||
|
snaps = [snap for snap in member_image.list_snaps()]
|
||||||
|
assert len(snaps) == 1
|
||||||
|
assert snaps[0]['name'] == snap_info_dict['image_snap_name']
|
||||||
|
assert snaps[0]['id'] == image_snap['snap_id']
|
||||||
|
assert sorted(image_names) == self.image_names
|
||||||
|
|
||||||
|
self.group.remove_snap(snap_name)
|
||||||
|
assert_raises(ObjectNotFound, self.group.get_snap_info, snap_name)
|
||||||
|
|
||||||
def test_group_snap(self):
|
def test_group_snap(self):
|
||||||
global snap_name
|
global snap_name
|
||||||
eq([], list(self.group.list_snaps()))
|
eq([], list(self.group.list_snaps()))
|
||||||
@ -2919,18 +2950,30 @@ class TestGroups(object):
|
|||||||
eq([], list(self.group.list_snaps()))
|
eq([], list(self.group.list_snaps()))
|
||||||
|
|
||||||
def test_group_snap_list_many(self):
|
def test_group_snap_list_many(self):
|
||||||
|
self.image_names.append(create_image())
|
||||||
|
self.image_names.sort()
|
||||||
|
self.group.add_image(ioctx, self.image_names[0])
|
||||||
|
self.group.add_image(ioctx, self.image_names[1])
|
||||||
|
|
||||||
global snap_name
|
global snap_name
|
||||||
eq([], list(self.group.list_snaps()))
|
assert list(self.group.list_snaps()) == []
|
||||||
snap_names = []
|
snap_names = []
|
||||||
for x in range(0, 20):
|
for x in range(0, 20):
|
||||||
snap_names.append(snap_name)
|
snap_names.append(snap_name)
|
||||||
self.group.create_snap(snap_name)
|
self.group.create_snap(snap_name)
|
||||||
snap_name = get_temp_snap_name()
|
snap_name = get_temp_snap_name()
|
||||||
|
|
||||||
snap_names.sort()
|
gp_snaps_list = self.group.list_snaps()
|
||||||
answer = [snap['name'] for snap in self.group.list_snaps()]
|
gp_snap_names = []
|
||||||
answer.sort()
|
for gp_snap in gp_snaps_list:
|
||||||
eq(snap_names, answer)
|
assert sorted(gp_snap.keys()) == self.gp_snap_keys
|
||||||
|
gp_snap_names.append(gp_snap['name'])
|
||||||
|
image_names = []
|
||||||
|
for img_snap in gp_snap['image_snaps']:
|
||||||
|
assert sorted(img_snap.keys()) == self.img_snap_keys
|
||||||
|
image_names.append(img_snap['image_name'])
|
||||||
|
assert sorted(image_names) == self.image_names
|
||||||
|
assert sorted(gp_snap_names) == sorted(snap_names)
|
||||||
|
|
||||||
def test_group_snap_namespace(self):
|
def test_group_snap_namespace(self):
|
||||||
global snap_name
|
global snap_name
|
||||||
|
@ -85,6 +85,18 @@ void add_group_spec_options(po::options_description *pos,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string get_group_snap_state_name(rbd_group_snap_state_t state)
|
||||||
|
{
|
||||||
|
switch (state) {
|
||||||
|
case RBD_GROUP_SNAP_STATE_INCOMPLETE:
|
||||||
|
return "incomplete";
|
||||||
|
case RBD_GROUP_SNAP_STATE_COMPLETE:
|
||||||
|
return "complete";
|
||||||
|
default:
|
||||||
|
return "unknown (" + stringify(state) + ")";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int execute_create(const po::variables_map &vm,
|
int execute_create(const po::variables_map &vm,
|
||||||
const std::vector<std::string> &ceph_global_init_args) {
|
const std::vector<std::string> &ceph_global_init_args) {
|
||||||
size_t arg_index = 0;
|
size_t arg_index = 0;
|
||||||
@ -705,14 +717,8 @@ int execute_group_snap_list(const po::variables_map &vm,
|
|||||||
}
|
}
|
||||||
|
|
||||||
librbd::RBD rbd;
|
librbd::RBD rbd;
|
||||||
std::vector<librbd::group_snap_info_t> snaps;
|
std::vector<librbd::group_snap_info2_t> snaps;
|
||||||
|
r = rbd.group_snap_list2(io_ctx, group_name.c_str(), &snaps);
|
||||||
r = rbd.group_snap_list(io_ctx, group_name.c_str(), &snaps,
|
|
||||||
sizeof(librbd::group_snap_info_t));
|
|
||||||
|
|
||||||
if (r == -ENOENT) {
|
|
||||||
r = 0;
|
|
||||||
}
|
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
@ -721,29 +727,21 @@ int execute_group_snap_list(const po::variables_map &vm,
|
|||||||
if (f) {
|
if (f) {
|
||||||
f->open_array_section("group_snaps");
|
f->open_array_section("group_snaps");
|
||||||
} else {
|
} else {
|
||||||
|
t.define_column("ID", TextTable::LEFT, TextTable::LEFT);
|
||||||
t.define_column("NAME", TextTable::LEFT, TextTable::LEFT);
|
t.define_column("NAME", TextTable::LEFT, TextTable::LEFT);
|
||||||
t.define_column("STATUS", TextTable::LEFT, TextTable::RIGHT);
|
t.define_column("STATE", TextTable::LEFT, TextTable::RIGHT);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto i : snaps) {
|
for (const auto& snap : snaps) {
|
||||||
std::string snap_name = i.name;
|
auto state_string = get_group_snap_state_name(snap.state);
|
||||||
int state = i.state;
|
|
||||||
std::string state_string;
|
|
||||||
if (RBD_GROUP_SNAP_STATE_INCOMPLETE == state) {
|
|
||||||
state_string = "incomplete";
|
|
||||||
} else {
|
|
||||||
state_string = "ok";
|
|
||||||
}
|
|
||||||
if (r < 0) {
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
if (f) {
|
if (f) {
|
||||||
f->open_object_section("group_snap");
|
f->open_object_section("group_snap");
|
||||||
f->dump_string("snapshot", snap_name);
|
f->dump_string("id", snap.id);
|
||||||
|
f->dump_string("snapshot", snap.name);
|
||||||
f->dump_string("state", state_string);
|
f->dump_string("state", state_string);
|
||||||
f->close_section();
|
f->close_section();
|
||||||
} else {
|
} else {
|
||||||
t << snap_name << state_string << TextTable::endrow;
|
t << snap.id << snap.name << state_string << TextTable::endrow;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -756,6 +754,109 @@ int execute_group_snap_list(const po::variables_map &vm,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int execute_group_snap_info(const po::variables_map &vm,
|
||||||
|
const std::vector<std::string> &ceph_global_args) {
|
||||||
|
size_t arg_index = 0;
|
||||||
|
std::string pool_name;
|
||||||
|
std::string namespace_name;
|
||||||
|
std::string group_name;
|
||||||
|
std::string group_snap_name;
|
||||||
|
|
||||||
|
int r = utils::get_pool_generic_snapshot_names(
|
||||||
|
vm, at::ARGUMENT_MODIFIER_NONE, &arg_index, at::POOL_NAME, &pool_name,
|
||||||
|
&namespace_name, GROUP_NAME, "group", &group_name, &group_snap_name, true,
|
||||||
|
utils::SNAPSHOT_PRESENCE_REQUIRED, utils::SPEC_VALIDATION_FULL);
|
||||||
|
if (r < 0) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
at::Format::Formatter formatter;
|
||||||
|
r = utils::get_formatter(vm, &formatter);
|
||||||
|
if (r < 0) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
Formatter *f = formatter.get();
|
||||||
|
|
||||||
|
librados::Rados rados;
|
||||||
|
librados::IoCtx io_ctx;
|
||||||
|
r = utils::init(pool_name, namespace_name, &rados, &io_ctx);
|
||||||
|
if (r < 0) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
librbd::RBD rbd;
|
||||||
|
librbd::group_snap_info2_t group_snap;
|
||||||
|
r = rbd.group_snap_get_info(io_ctx, group_name.c_str(),
|
||||||
|
group_snap_name.c_str(), &group_snap);
|
||||||
|
if (r < 0) {
|
||||||
|
std::cerr << "rbd: failed to show group snapshot: "
|
||||||
|
<< cpp_strerror(r) << std::endl;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto state_string = get_group_snap_state_name(group_snap.state);
|
||||||
|
if (f) {
|
||||||
|
f->open_object_section("group_snapshot");
|
||||||
|
f->dump_string("id", group_snap.id);
|
||||||
|
f->dump_string("name", group_snap.name);
|
||||||
|
f->dump_string("state", state_string);
|
||||||
|
f->dump_string("image_snap_name", group_snap.image_snap_name);
|
||||||
|
f->open_array_section("images");
|
||||||
|
} else {
|
||||||
|
std::cout << "rbd group snapshot '" << group_snap.name << "':\n"
|
||||||
|
<< "\tid: " << group_snap.id << std::endl
|
||||||
|
<< "\tstate: " << state_string << std::endl
|
||||||
|
<< "\timage snap: " << group_snap.image_snap_name << std::endl
|
||||||
|
<< "\timages:" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::sort(group_snap.image_snaps.begin(), group_snap.image_snaps.end(),
|
||||||
|
[](const librbd::group_image_snap_info_t& lhs,
|
||||||
|
const librbd::group_image_snap_info_t& rhs) {
|
||||||
|
if (lhs.pool_id != rhs.pool_id) {
|
||||||
|
return lhs.pool_id < rhs.pool_id;
|
||||||
|
}
|
||||||
|
return lhs.image_name < rhs.image_name;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
for (const auto& image_snap : group_snap.image_snaps) {
|
||||||
|
std::string pool_name;
|
||||||
|
r = rados.pool_reverse_lookup(image_snap.pool_id, &pool_name);
|
||||||
|
if (r == -ENOENT) {
|
||||||
|
pool_name = "<missing image pool " + stringify(image_snap.pool_id) + ">";
|
||||||
|
} else if (r < 0) {
|
||||||
|
std::cerr << "rbd: error looking up pool name for pool_id="
|
||||||
|
<< image_snap.pool_id << ": " << cpp_strerror(r) << std::endl;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (f) {
|
||||||
|
f->open_object_section("image");
|
||||||
|
f->dump_string("pool_name", pool_name);
|
||||||
|
f->dump_string("namespace", io_ctx.get_namespace());
|
||||||
|
f->dump_string("image_name", image_snap.image_name);
|
||||||
|
f->dump_int("snap_id", image_snap.snap_id);
|
||||||
|
f->close_section();
|
||||||
|
} else {
|
||||||
|
std::cout << "\t\t" << pool_name << "/";
|
||||||
|
if (!io_ctx.get_namespace().empty()) {
|
||||||
|
std::cout << io_ctx.get_namespace() << "/";
|
||||||
|
}
|
||||||
|
std::cout << image_snap.image_name << " (snap id: " << image_snap.snap_id
|
||||||
|
<< ")" << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (f) {
|
||||||
|
f->close_section();
|
||||||
|
f->close_section();
|
||||||
|
f->flush(std::cout);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int execute_group_snap_rollback(const po::variables_map &vm,
|
int execute_group_snap_rollback(const po::variables_map &vm,
|
||||||
const std::vector<std::string> &global_args) {
|
const std::vector<std::string> &global_args) {
|
||||||
size_t arg_index = 0;
|
size_t arg_index = 0;
|
||||||
@ -917,6 +1018,13 @@ void get_group_snap_list_arguments(po::options_description *positional,
|
|||||||
false);
|
false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void get_group_snap_info_arguments(po::options_description *positional,
|
||||||
|
po::options_description *options) {
|
||||||
|
add_group_spec_options(positional, options, at::ARGUMENT_MODIFIER_NONE,
|
||||||
|
true);
|
||||||
|
at::add_format_options(options);
|
||||||
|
}
|
||||||
|
|
||||||
void get_group_snap_rollback_arguments(po::options_description *positional,
|
void get_group_snap_rollback_arguments(po::options_description *positional,
|
||||||
po::options_description *options) {
|
po::options_description *options) {
|
||||||
at::add_no_progress_option(options);
|
at::add_no_progress_option(options);
|
||||||
@ -964,6 +1072,10 @@ Shell::Action action_group_snap_list(
|
|||||||
{"group", "snap", "list"}, {"group", "snap", "ls"},
|
{"group", "snap", "list"}, {"group", "snap", "ls"},
|
||||||
"List snapshots of a group.",
|
"List snapshots of a group.",
|
||||||
"", &get_group_snap_list_arguments, &execute_group_snap_list);
|
"", &get_group_snap_list_arguments, &execute_group_snap_list);
|
||||||
|
Shell::Action action_group_snap_info(
|
||||||
|
{"group", "snap", "info"}, {},
|
||||||
|
"Show information about a group snapshot.",
|
||||||
|
"", &get_group_snap_info_arguments, &execute_group_snap_info);
|
||||||
Shell::Action action_group_snap_rollback(
|
Shell::Action action_group_snap_rollback(
|
||||||
{"group", "snap", "rollback"}, {},
|
{"group", "snap", "rollback"}, {},
|
||||||
"Rollback group to snapshot.",
|
"Rollback group to snapshot.",
|
||||||
|
Loading…
Reference in New Issue
Block a user