if not pool:
raise cherrypy.NotFound('No such pool')
- schedule_info = RbdMirroringService.get_snapshot_schedule_info()
- if schedule_info:
- filtered = [
- info for info in schedule_info
- if info["name"].split("/", 1)[0] == pool_name
- ]
- pool[0]['schedule_info'] = filtered[0] if filtered else {}
+ pool_schedule_spec = f"{pool_name}/"
+ pool_interval = RbdMirroringService.get_schedule_interval(pool_schedule_spec)
+
+ if pool_interval:
+ pool[0]['schedule_info'] = {
+ 'name': pool_schedule_spec,
+ 'schedule_interval': pool_interval,
+ 'schedule_time': None,
+ 'inherited': None
+ }
+ else:
+ cluster_interval = RbdMirroringService.get_schedule_interval('')
+ if cluster_interval:
+ pool[0]['schedule_info'] = {
+ 'name': '',
+ 'schedule_interval': cluster_interval,
+ 'schedule_time': None,
+ 'inherited': 'cluster'
+ }
+ else:
+ pool[0]['schedule_info'] = {}
return pool[0]
def get(self, pool_name: str, attrs: Optional[str] = None, stats: bool = False) -> dict:
stat['mirror_mode'] = 'journal'
elif mirror_mode == rbd.RBD_MIRROR_IMAGE_MODE_SNAPSHOT:
stat['mirror_mode'] = 'snapshot'
- schedule_info = RbdMirroringService.get_snapshot_schedule_info(
- get_image_spec(pool_name, namespace, image_name)
- )
- if schedule_info:
- stat['schedule_info'] = schedule_info[0]
+ image_schedule_spec = get_image_spec(pool_name, namespace, image_name)
+ image_schedule_info = RbdMirroringService.get_snapshot_schedule_info(
+ image_schedule_spec)
+
+ if image_schedule_info and len(image_schedule_info) > 0:
+ schedule = image_schedule_info[0]
+ schedule['inherited'] = None
+ stat['schedule_info'] = schedule
+ else:
+ image_schedule_time = RbdMirroringService.get_schedule_time_for_image(
+ image_schedule_spec)
+
+ pool_schedule_spec = f"{pool_name}/"
+ pool_interval = RbdMirroringService.get_schedule_interval(
+ pool_schedule_spec)
+
+ if pool_interval:
+ stat['schedule_info'] = {
+ 'name': pool_schedule_spec,
+ 'schedule_interval': pool_interval,
+ 'schedule_time': image_schedule_time,
+ 'inherited': 'pool'
+ }
+ else:
+ cluster_interval = RbdMirroringService.get_schedule_interval('')
+ if cluster_interval:
+ stat['schedule_info'] = {
+ 'name': '',
+ 'schedule_interval': cluster_interval,
+ 'schedule_time': image_schedule_time,
+ 'inherited': 'cluster'
+ }
stat['name'] = image_name
return schedule_info if schedule_info else None
+ @classmethod
+ def get_schedule_time_for_image(cls, image_spec: str):
+ """Get the scheduled time for a specific image from schedule status."""
+ schedule_status_raw = cls.snapshot_schedule_status('')
+ try:
+ schedule_status = json.loads(
+ schedule_status_raw[1]) if schedule_status_raw and schedule_status_raw[1] else {}
+ except (json.JSONDecodeError, TypeError):
+ return None
+
+ scheduled_images = schedule_status.get("scheduled_images", [])
+ for img in scheduled_images:
+ if img.get("image") == image_spec:
+ return img.get("schedule_time")
+ return None
+
+ @classmethod
+ def get_schedule_interval(cls, schedule_spec: str):
+ """Get just the schedule interval for a given spec (pool or cluster)."""
+ schedule_list_raw = cls.snapshot_schedule_list('')
+ try:
+ schedule_list = json.loads(
+ schedule_list_raw[1]) if schedule_list_raw and schedule_list_raw[1] else {}
+ except (json.JSONDecodeError, TypeError):
+ return None
+
+ if not schedule_list:
+ return None
+
+ for _, schedule in schedule_list.items():
+ name = schedule.get("name")
+ if name and name == schedule_spec:
+ return schedule.get("schedule", [])
+ return None
+
+ @classmethod
+ def get_cluster_schedule(cls):
+ """Get cluster-level schedule with inherited flag set."""
+ cluster_schedule_info = cls.get_snapshot_schedule_info('')
+ if cluster_schedule_info and len(cluster_schedule_info) > 0:
+ schedule = cluster_schedule_info[0]
+ schedule['inherited'] = 'cluster'
+ return schedule
+ return None
+
class RbdImageMetadataService(object):
def __init__(self, image):