import logging
import re
from functools import partial
-from typing import no_type_check
+from typing import NamedTuple, Optional, no_type_check
import cherrypy
import rbd
}
+class ReplayingData(NamedTuple):
+ bytes_per_second: Optional[int] = None
+ seconds_until_synced: Optional[int] = None
+ syncing_percent: Optional[float] = None
+ entries_behind_primary: Optional[int] = None
+
+
@ViewCache()
@no_type_check
def _get_pool_datum(pool_name):
rbd.MIRROR_IMAGE_STATUS_STATE_STOPPED: {
'health': 'ok',
'state_color': 'info',
- 'state': 'Primary'
+ 'state': 'Stopped'
}
+
}
rbdctx = rbd.RBD()
return data
+def _update_syncing_image_data(mirror_image, image):
+ if mirror_image['state'] == 'Replaying':
+ p = re.compile("replaying, ({.*})")
+ replaying_data = p.findall(mirror_image['description'])
+ assert len(replaying_data) == 1
+ replaying_data = json.loads(replaying_data[0])
+ if 'replay_state' in replaying_data and replaying_data['replay_state'] == 'idle':
+ image.update({
+ 'state_color': 'info',
+ 'state': 'Idle'
+ })
+ for field in ReplayingData._fields:
+ try:
+ image[field] = replaying_data[field]
+ except KeyError:
+ pass
+ else:
+ p = re.compile("bootstrapping, IMAGE_COPY/COPY_OBJECT (.*)%")
+ image.update({
+ 'progress': (p.findall(mirror_image['description']) or [0])[0]
+ })
+
+
@ViewCache()
def _get_content_data(): # pylint: disable=R0914
pool_names = [pool['pool_name'] for pool in CephService.get_pool_list('rbd')
})
image_ready.append(image)
elif mirror_image['health'] == 'syncing':
- if mirror_image['state'] == 'Replaying':
- p = re.compile("replaying, ({.*})")
- replaying_data = p.findall(mirror_image['description'])
- assert len(replaying_data) == 1
- replaying_data = json.loads(replaying_data[0])
- seconds_until_synced = 0
- if 'seconds_until_synced' in replaying_data:
- seconds_until_synced = replaying_data['seconds_until_synced']
- image.update({
- 'seconds_until_synced': seconds_until_synced
- })
- else:
- p = re.compile("bootstrapping, IMAGE_COPY/COPY_OBJECT (.*)%")
- image.update({
- 'progress': (p.findall(mirror_image['description']) or [0])[0]
- })
+ _update_syncing_image_data(mirror_image, image)
image_syncing.append(image)
else:
image.update({
this.image_error.columns = [
{ prop: 'pool_name', name: $localize`Pool`, flexGrow: 2 },
{ prop: 'name', name: $localize`Image`, flexGrow: 2 },
- { prop: 'description', name: $localize`Issue`, flexGrow: 4 },
{
prop: 'state',
name: $localize`State`,
cellTemplate: this.stateTmpl,
flexGrow: 1
- }
+ },
+ { prop: 'description', name: $localize`Issue`, flexGrow: 4 },
];
this.image_syncing.columns = [
{ prop: 'pool_name', name: $localize`Pool`, flexGrow: 2 },
{ prop: 'name', name: $localize`Image`, flexGrow: 2 },
+ {
+ prop: 'state',
+ name: $localize`State`,
+ cellTemplate: this.stateTmpl,
+ flexGrow: 1
+ },
{
prop: 'progress',
name: $localize`Progress`,
cellTemplate: this.progressTmpl,
flexGrow: 2
},
- {
- prop: 'state',
- name: $localize`State`,
- cellTemplate: this.stateTmpl,
- flexGrow: 1
- }
+ { prop: 'bytes_per_second', name: $localize`Bytes per second`, flexGrow: 2 },
+ { prop: 'entries_behind_primary', name: $localize`Entries behind primary`, flexGrow: 2 },
];
this.image_ready.columns = [
{ prop: 'pool_name', name: $localize`Pool`, flexGrow: 2 },
{ prop: 'name', name: $localize`Image`, flexGrow: 2 },
- { prop: 'description', name: $localize`Description`, flexGrow: 4 },
{
prop: 'state',
name: $localize`State`,
cellTemplate: this.stateTmpl,
flexGrow: 1
- }
+ },
+ { prop: 'description', name: $localize`Description`, flexGrow: 4 },
];
this.subs = this.rbdMirroringService.subscribeSummary((data) => {