Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
86 commits
Select commit Hold shift + click to select a range
5e2ce25
wip
Hamdy-khader Oct 3, 2025
68486bf
wip 2
Hamdy-khader Oct 7, 2025
9339721
implement snapshot replication
Hamdy-khader Oct 13, 2025
0e046ec
implement snapshot replication 2
Hamdy-khader Oct 15, 2025
efe11b6
Fix env_var
Hamdy-khader Oct 17, 2025
f5456e9
Fix service
Hamdy-khader Oct 18, 2025
de95003
Fix service
Hamdy-khader Oct 18, 2025
02077a1
Fix service
Hamdy-khader Oct 18, 2025
d0db64f
Fix service
Hamdy-khader Oct 18, 2025
b1561bb
Fix service 2
Hamdy-khader Oct 18, 2025
2fde451
Fix service 3
Hamdy-khader Oct 18, 2025
d084c06
Fix service 4
Hamdy-khader Oct 18, 2025
3199c39
Merge branch 'refs/heads/main' into main-sfam-2359
Hamdy-khader Oct 18, 2025
d7e7c20
Fix service 6
Hamdy-khader Oct 18, 2025
6770f32
Fix service 5
Hamdy-khader Oct 18, 2025
08d7edc
Fix service 7
Hamdy-khader Oct 18, 2025
0806489
Fix service 8
Hamdy-khader Oct 18, 2025
a6eb900
Fix service 8
Hamdy-khader Oct 18, 2025
2f6cad3
Merge branch 'main' into main-sfam-2359
Hamdy-khader Nov 5, 2025
d02beba
wip
Hamdy-khader Nov 5, 2025
4267f1c
wip 2
Hamdy-khader Nov 5, 2025
ef130f2
wip 3
Hamdy-khader Nov 5, 2025
d68ebf6
wip 3
Hamdy-khader Nov 5, 2025
54cc929
wip 4
Hamdy-khader Nov 6, 2025
4e59c73
wip 4
Hamdy-khader Nov 6, 2025
296a246
wip 5
Hamdy-khader Nov 6, 2025
80035ed
wip 7
Hamdy-khader Nov 6, 2025
9b49217
Fix lvol poller cpu mask
Hamdy-khader Nov 6, 2025
149fcd5
Fix target snap name
Hamdy-khader Nov 6, 2025
c0b869f
fix poller mask
Hamdy-khader Nov 6, 2025
c6d7d1a
fix poller mask
Hamdy-khader Nov 7, 2025
9900a6a
fix poller mask
Hamdy-khader Nov 7, 2025
fa4bfb7
fix chain
Hamdy-khader Nov 7, 2025
4781a77
fix chain
Hamdy-khader Nov 7, 2025
cd6cab7
fix chain
Hamdy-khader Nov 7, 2025
3c9dd46
fix chain
Hamdy-khader Nov 7, 2025
f460479
fix chain
Hamdy-khader Nov 7, 2025
659857d
fix chain
Hamdy-khader Nov 7, 2025
5f352d9
Merge branch 'main' into main-sfam-2359
Hamdy-khader Nov 24, 2025
7655dbd
Set cluster_id optional on SNodeAPI docker version
Hamdy-khader Nov 24, 2025
880630f
fix type checker
Hamdy-khader Nov 25, 2025
91443ed
fix type checker
Hamdy-khader Nov 25, 2025
6ff60fd
Fix snapshot replications tickets
Hamdy-khader Nov 27, 2025
98ff764
Fix sfam-2496
Hamdy-khader Nov 27, 2025
05b6cd1
Follow up 1
Hamdy-khader Nov 27, 2025
32d6ad4
fix lvol replication_start
Hamdy-khader Nov 27, 2025
580a519
fix rep service
Hamdy-khader Nov 27, 2025
254035d
fix snapshot clone return value
Hamdy-khader Nov 27, 2025
cd2b261
replicate snapshot back to src _1 (#790)
Hamdy-khader Dec 3, 2025
a620255
Merge branch 'main' into main-sfam-2359
Hamdy-khader Dec 3, 2025
c09ad75
Merge branch 'main' into main-sfam-2359
Hamdy-khader Dec 4, 2025
7a3cf03
Merge branch 'main' into main-sfam-2359
Hamdy-khader Dec 5, 2025
df90efe
Fix sn list apiv2 response _2
Hamdy-khader Dec 5, 2025
98b6384
Fix sn list apiv2 response _3
Hamdy-khader Dec 5, 2025
7a52b77
Add stats to spdk_http_proxy_server.py
Hamdy-khader Dec 8, 2025
9526f8c
Add stats to spdk_http_proxy_server.py _2
Hamdy-khader Dec 8, 2025
3a3e7b5
Fix 2
Hamdy-khader Dec 8, 2025
93f7c8c
Fix 2
Hamdy-khader Dec 8, 2025
db31b6e
Fix 3
Hamdy-khader Dec 8, 2025
82600ba
Fix sfam-2524
Hamdy-khader Dec 9, 2025
70d3864
Fix sfam-2523
Hamdy-khader Dec 9, 2025
3b40dc1
Fix sfam-2527
Hamdy-khader Dec 11, 2025
196b93c
Increase snapshot replication task retry on node not online
Hamdy-khader Dec 12, 2025
d81835a
fix sfam-2516 _1
Hamdy-khader Dec 12, 2025
5c1dd94
fix sfam-2516 _2
Hamdy-khader Dec 12, 2025
0b920c3
fix sfam-2516 _3
Hamdy-khader Dec 12, 2025
a485224
fix linter
Hamdy-khader Dec 10, 2025
9d145e2
fix sfam-2516 _4
Hamdy-khader Dec 13, 2025
0db9022
wip
Hamdy-khader Dec 13, 2025
4016222
Merge branch 'main' into main-sfam-2359
Hamdy-khader Dec 13, 2025
ff05ec6
wip
Hamdy-khader Dec 13, 2025
8786169
wip 2
Hamdy-khader Dec 13, 2025
4734c2d
wip 2
Hamdy-khader Dec 13, 2025
15e0af3
Exclude src snap node id when starting replication on cloned lvol
Hamdy-khader Dec 16, 2025
da0c057
fix snapshot replication source and target in case of replicate_to_so…
Hamdy-khader Dec 24, 2025
4fbf425
Main sfam 2359 api (#844)
geoffrey1330 Jan 19, 2026
575816b
added replication_start and stop to api v2 (#845)
geoffrey1330 Jan 19, 2026
c1e9ce1
Merge branch 'main' into main-sfam-2359
geoffrey1330 Jan 20, 2026
1b08d82
Merge branch 'main' into main-sfam-2359
Hamdy-khader Jan 27, 2026
5f96694
Enhance snapshot replication logic to support snapshot instances and …
Hamdy-khader Jan 27, 2026
105a14f
Add replication-trigger command to start replication for logical volumes
Hamdy-khader Jan 28, 2026
0ac5bce
Merge branch 'main' into main-sfam-2359
Hamdy-khader Feb 5, 2026
37f46af
fix 1
Hamdy-khader Feb 5, 2026
920034e
fix 1
Hamdy-khader Feb 5, 2026
d78223d
Merge branch 'main' into main-sfam-2359
Hamdy-khader Feb 5, 2026
ff20e2e
Fix 1
Hamdy-khader Feb 6, 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
109 changes: 109 additions & 0 deletions simplyblock_cli/cli-reference.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1339,6 +1339,28 @@ commands:
help: "Name"
dest: name
type: str
- name: add-replication
help: Assigns the snapshot replication target cluster
arguments:
- name: "cluster_id"
help: "Cluster id"
dest: cluster_id
type: str
completer: _completer_get_cluster_list
- name: "target_cluster_id"
help: "Target Cluster id"
dest: target_cluster_id
type: str
completer: _completer_get_cluster_list
- name: "--timeout"
help: "Snapshot replication network timeout"
dest: timeout
type: int
default: "3600"
- name: "--target-pool"
help: "Target cluster pool ID or name"
dest: target_pool
type: str
- name: "volume"
help: "Logical volume commands"
aliases:
Expand Down Expand Up @@ -1469,6 +1491,11 @@ commands:
dest: npcs
type: int
default: 0
- name: "--replicate"
help: "Replicate LVol snapshot"
dest: replicate
type: bool
action: store_true
- name: qos-set
help: "Changes QoS settings for an active logical volume"
arguments:
Expand Down Expand Up @@ -1670,6 +1697,34 @@ commands:
help: "Logical volume id"
dest: volume_id
type: str
- name: replication-start
help: "Start snapshot replication taken from lvol"
arguments:
- name: "lvol_id"
help: "Logical volume id"
dest: lvol_id
type: str
- name: replication-stop
help: "Stop snapshot replication taken from lvol"
arguments:
- name: "lvol_id"
help: "Logical volume id"
dest: lvol_id
type: str
- name: replication-status
help: "Lists replication status"
arguments:
- name: "cluster_id"
help: "Cluster UUID"
dest: cluster_id
type: str
- name: replication-trigger
help: "Start replication for lvol"
arguments:
- name: "lvol_id"
help: "Logical volume id"
dest: lvol_id
type: str
- name: "control-plane"
help: "Control plane commands"
aliases:
Expand Down Expand Up @@ -1894,6 +1949,16 @@ commands:
dest: all
type: bool
action: store_true
- name: "--cluster-id"
help: "Filter snapshots by cluster UUID"
dest: cluster_id
type: str
required: false
- name: "--with-details"
help: "List snapshots with replicate and chaining details"
dest: with_details
type: bool
action: store_true
- name: delete
help: "Deletes a snapshot"
arguments:
Expand All @@ -1906,6 +1971,13 @@ commands:
dest: force
type: bool
action: store_true
- name: check
help: "Check a snapshot health"
arguments:
- name: "snapshot_id"
help: "Snapshot id"
dest: snapshot_id
type: str
- name: clone
help: "Provisions a new logical volume from an existing snapshot"
arguments:
Expand All @@ -1922,6 +1994,43 @@ commands:
dest: resize
type: size
default: "0"
- name: replication-status
help: "Lists snapshots replication status"
arguments:
- name: "cluster_id"
help: "Cluster UUID"
dest: cluster_id
type: str
- name: delete-replication-only
help: "Delete replicated version of a snapshot"
arguments:
- name: "snapshot_id"
help: "Snapshot UUID"
dest: snapshot_id
type: str
- name: get
help: "Gets a snapshot information"
arguments:
- name: "snapshot_id"
help: "Snapshot UUID"
dest: snapshot_id
type: str
- name: set
help: "set snapshot db value"
private: true
arguments:
- name: "snapshot_id"
help: "snapshot id"
dest: snapshot_id
type: str
- name: "attr_name"
help: "attr_name"
dest: attr_name
type: str
- name: "attr_value"
help: "attr_value"
dest: attr_value
type: str
- name: "qos"
help: "qos commands"
weight: 700
Expand Down
83 changes: 83 additions & 0 deletions simplyblock_cli/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,7 @@ def init_cluster(self):
if self.developer_mode:
self.init_cluster__set(subparser)
self.init_cluster__change_name(subparser)
self.init_cluster__add_replication(subparser)


def init_cluster__create(self, subparser):
Expand Down Expand Up @@ -526,6 +527,13 @@ def init_cluster__change_name(self, subparser):
subcommand.add_argument('cluster_id', help='Cluster id', type=str).completer = self._completer_get_cluster_list
subcommand.add_argument('name', help='Name', type=str)

def init_cluster__add_replication(self, subparser):
subcommand = self.add_sub_command(subparser, 'add-replication', 'Assigns the snapshot replication target cluster')
subcommand.add_argument('cluster_id', help='Cluster id', type=str).completer = self._completer_get_cluster_list
subcommand.add_argument('target_cluster_id', help='Target Cluster id', type=str).completer = self._completer_get_cluster_list
argument = subcommand.add_argument('--timeout', help='Snapshot replication network timeout', type=int, default=3600, dest='timeout')
argument = subcommand.add_argument('--target-pool', help='Target cluster pool ID or name', type=str, dest='target_pool')


def init_volume(self):
subparser = self.add_command('volume', 'Logical volume commands', aliases=['lvol',])
Expand All @@ -546,6 +554,10 @@ def init_volume(self):
self.init_volume__get_io_stats(subparser)
self.init_volume__check(subparser)
self.init_volume__inflate(subparser)
self.init_volume__replication_start(subparser)
self.init_volume__replication_stop(subparser)
self.init_volume__replication_status(subparser)
self.init_volume__replication_trigger(subparser)


def init_volume__add(self, subparser):
Expand Down Expand Up @@ -575,6 +587,7 @@ def init_volume__add(self, subparser):
argument = subcommand.add_argument('--pvc-name', '--pvc_name', help='Set logical volume PVC name for k8s clients', type=str, dest='pvc_name')
argument = subcommand.add_argument('--data-chunks-per-stripe', help='Erasure coding schema parameter k (distributed raid), default: 1', type=int, default=0, dest='ndcs')
argument = subcommand.add_argument('--parity-chunks-per-stripe', help='Erasure coding schema parameter n (distributed raid), default: 1', type=int, default=0, dest='npcs')
argument = subcommand.add_argument('--replicate', help='Replicate LVol snapshot', dest='replicate', action='store_true')

def init_volume__qos_set(self, subparser):
subcommand = self.add_sub_command(subparser, 'qos-set', 'Changes QoS settings for an active logical volume')
Expand Down Expand Up @@ -652,6 +665,22 @@ def init_volume__inflate(self, subparser):
subcommand = self.add_sub_command(subparser, 'inflate', 'Inflate a logical volume')
subcommand.add_argument('volume_id', help='Logical volume id', type=str)

def init_volume__replication_start(self, subparser):
subcommand = self.add_sub_command(subparser, 'replication-start', 'Start snapshot replication taken from lvol')
subcommand.add_argument('lvol_id', help='Logical volume id', type=str)

def init_volume__replication_stop(self, subparser):
subcommand = self.add_sub_command(subparser, 'replication-stop', 'Stop snapshot replication taken from lvol')
subcommand.add_argument('lvol_id', help='Logical volume id', type=str)

def init_volume__replication_status(self, subparser):
subcommand = self.add_sub_command(subparser, 'replication-status', 'Lists replication status')
subcommand.add_argument('cluster_id', help='Cluster UUID', type=str)

def init_volume__replication_trigger(self, subparser):
subcommand = self.add_sub_command(subparser, 'replication-trigger', 'Start replication for lvol')
subcommand.add_argument('lvol_id', help='Logical volume id', type=str)


def init_control_plane(self):
subparser = self.add_command('control-plane', 'Control plane commands', aliases=['cp','mgmt',])
Expand Down Expand Up @@ -751,7 +780,13 @@ def init_snapshot(self):
self.init_snapshot__add(subparser)
self.init_snapshot__list(subparser)
self.init_snapshot__delete(subparser)
self.init_snapshot__check(subparser)
self.init_snapshot__clone(subparser)
self.init_snapshot__replication_status(subparser)
self.init_snapshot__delete_replication_only(subparser)
self.init_snapshot__get(subparser)
if self.developer_mode:
self.init_snapshot__set(subparser)


def init_snapshot__add(self, subparser):
Expand All @@ -762,18 +797,42 @@ def init_snapshot__add(self, subparser):
def init_snapshot__list(self, subparser):
subcommand = self.add_sub_command(subparser, 'list', 'Lists all snapshots')
argument = subcommand.add_argument('--all', help='List soft deleted snapshots', dest='all', action='store_true')
argument = subcommand.add_argument('--cluster-id', help='Filter snapshots by cluster UUID', type=str, dest='cluster_id', required=False)
argument = subcommand.add_argument('--with-details', help='List snapshots with replicate and chaining details', dest='with_details', action='store_true')

def init_snapshot__delete(self, subparser):
subcommand = self.add_sub_command(subparser, 'delete', 'Deletes a snapshot')
subcommand.add_argument('snapshot_id', help='Snapshot id', type=str)
argument = subcommand.add_argument('--force', help='Force remove', dest='force', action='store_true')

def init_snapshot__check(self, subparser):
subcommand = self.add_sub_command(subparser, 'check', 'Check a snapshot health')
subcommand.add_argument('snapshot_id', help='Snapshot id', type=str)

def init_snapshot__clone(self, subparser):
subcommand = self.add_sub_command(subparser, 'clone', 'Provisions a new logical volume from an existing snapshot')
subcommand.add_argument('snapshot_id', help='Snapshot id', type=str)
subcommand.add_argument('lvol_name', help='Logical volume name', type=str)
argument = subcommand.add_argument('--resize', help='New logical volume size: 10M, 10G, 10(bytes). Can only increase.', type=size_type(), default='0', dest='resize')

def init_snapshot__replication_status(self, subparser):
subcommand = self.add_sub_command(subparser, 'replication-status', 'Lists snapshots replication status')
subcommand.add_argument('cluster_id', help='Cluster UUID', type=str)

def init_snapshot__delete_replication_only(self, subparser):
subcommand = self.add_sub_command(subparser, 'delete-replication-only', 'Delete replicated version of a snapshot')
subcommand.add_argument('snapshot_id', help='Snapshot UUID', type=str)

def init_snapshot__get(self, subparser):
subcommand = self.add_sub_command(subparser, 'get', 'Gets a snapshot information')
subcommand.add_argument('snapshot_id', help='Snapshot UUID', type=str)

def init_snapshot__set(self, subparser):
subcommand = self.add_sub_command(subparser, 'set', 'set snapshot db value')
subcommand.add_argument('snapshot_id', help='snapshot id', type=str)
subcommand.add_argument('attr_name', help='attr_name', type=str)
subcommand.add_argument('attr_value', help='attr_value', type=str)


def init_qos(self):
subparser = self.add_command('qos', 'qos commands')
Expand Down Expand Up @@ -1024,6 +1083,8 @@ def run(self):
ret = self.cluster__set(sub_command, args)
elif sub_command in ['change-name']:
ret = self.cluster__change_name(sub_command, args)
elif sub_command in ['add-replication']:
ret = self.cluster__add_replication(sub_command, args)
else:
self.parser.print_help()

Expand Down Expand Up @@ -1070,6 +1131,14 @@ def run(self):
ret = self.volume__check(sub_command, args)
elif sub_command in ['inflate']:
ret = self.volume__inflate(sub_command, args)
elif sub_command in ['replication-start']:
ret = self.volume__replication_start(sub_command, args)
elif sub_command in ['replication-stop']:
ret = self.volume__replication_stop(sub_command, args)
elif sub_command in ['replication-status']:
ret = self.volume__replication_status(sub_command, args)
elif sub_command in ['replication-trigger']:
ret = self.volume__replication_trigger(sub_command, args)
else:
self.parser.print_help()

Expand Down Expand Up @@ -1115,8 +1184,22 @@ def run(self):
ret = self.snapshot__list(sub_command, args)
elif sub_command in ['delete']:
ret = self.snapshot__delete(sub_command, args)
elif sub_command in ['check']:
ret = self.snapshot__check(sub_command, args)
elif sub_command in ['clone']:
ret = self.snapshot__clone(sub_command, args)
elif sub_command in ['replication-status']:
ret = self.snapshot__replication_status(sub_command, args)
elif sub_command in ['delete-replication-only']:
ret = self.snapshot__delete_replication_only(sub_command, args)
elif sub_command in ['get']:
ret = self.snapshot__get(sub_command, args)
elif sub_command in ['set']:
if not self.developer_mode:
print("This command is private.")
ret = False
else:
ret = self.snapshot__set(sub_command, args)
else:
self.parser.print_help()

Expand Down
39 changes: 35 additions & 4 deletions simplyblock_cli/clibase.py
Original file line number Diff line number Diff line change
Expand Up @@ -478,6 +478,9 @@ def cluster__complete_expand(self, sub_command, args):
cluster_ops.cluster_expand(args.cluster_id)
return True

def cluster__add_replication(self, sub_command, args):
return cluster_ops.add_replication(args.cluster_id, args.target_cluster_id, args.timeout, args.target_pool)

def volume__add(self, sub_command, args):
name = args.name
size = args.size
Expand Down Expand Up @@ -505,7 +508,8 @@ def volume__add(self, sub_command, args):
crypto_key2=args.crypto_key2,
lvol_priority_class=lvol_priority_class,
uid=args.uid, pvc_name=args.pvc_name, namespace=args.namespace,
max_namespace_per_subsys=args.max_namespace_per_subsys, ndcs=ndcs, npcs=npcs, fabric=args.fabric)
max_namespace_per_subsys=args.max_namespace_per_subsys, ndcs=ndcs, npcs=npcs, fabric=args.fabric,
do_replicate=args.replicate)
if results:
return results
else:
Expand Down Expand Up @@ -586,6 +590,18 @@ def volume__check(self, sub_command, args):
def volume__inflate(self, sub_command, args):
return lvol_controller.inflate_lvol(args.volume_id)

def volume__replication_start(self, sub_command, args):
return lvol_controller.replication_start(args.lvol_id)

def volume__replication_stop(self, sub_command, args):
return lvol_controller.replication_stop(args.lvol_id)

def volume__replication_status(self, sub_command, args):
return snapshot_controller.list_replication_tasks(args.cluster_id)

def volume__replication_trigger(self, sub_command, args):
return lvol_controller.replication_trigger(args.lvol_id)

def control_plane__add(self, sub_command, args):
cluster_id = args.cluster_id
cluster_ip = args.cluster_ip
Expand Down Expand Up @@ -654,16 +670,31 @@ def snapshot__add(self, sub_command, args):
return snapshot_id if not error else error

def snapshot__list(self, sub_command, args):
return snapshot_controller.list(args.all)
return snapshot_controller.list(args.all, args.cluster_id, args.with_details)

def snapshot__delete(self, sub_command, args):
return snapshot_controller.delete(args.snapshot_id, args.force)

def snapshot__check(self, sub_command, args):
return health_controller.check_snap(args.snapshot_id)

def snapshot__clone(self, sub_command, args):
new_size = args.resize

success, details = snapshot_controller.clone(args.snapshot_id, args.lvol_name, new_size)
return details
clone_id, error = snapshot_controller.clone(args.snapshot_id, args.lvol_name, new_size)
return clone_id if not error else error

def snapshot__replication_status(self, sub_command, args):
return snapshot_controller.list_replication_tasks(args.cluster_id)

def snapshot__delete_replication_only(self, sub_command, args):
return snapshot_controller.delete_replicated(args.snapshot_id)

def snapshot__get(self, sub_command, args):
return snapshot_controller.get(args.snapshot_id)

def snapshot__set(self, sub_command, args):
return snapshot_controller.set(args.snapshot_id, args.attr_name, args.attr_value)

def qos__add(self, sub_command, args):
return qos_controller.add_class(args.name, args.weight, args.cluster_id)
Expand Down
Loading
Loading