Merge pull request #46433 from rhcs-dashboard/rbd-mirroring-replay

mgr/dashboard: move replaying images to Syncing tab

Reviewed-by: Avan Thakkar <athakkar@redhat.com>
Reviewed-by: Ernesto Puerta <epuertat@redhat.com>
Reviewed-by: Ilya Dryomov <idryomov@redhat.com>
Reviewed-by: nSedrickm <NOT@FOUND>
This commit is contained in:
Ernesto Puerta 2022-06-17 17:33:49 +02:00 committed by GitHub
commit bf5c7ff65e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 65 additions and 36 deletions

View File

@ -4,7 +4,7 @@ import json
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
@ -199,6 +199,13 @@ def get_daemons_and_pools(): # pylint: disable=R0915
}
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):
@ -228,15 +235,17 @@ def _get_pool_datum(pool_name):
'state': 'Error'
},
rbd.MIRROR_IMAGE_STATUS_STATE_SYNCING: {
'health': 'syncing'
'health': 'syncing',
'state_color': 'success',
'state': 'Syncing'
},
rbd.MIRROR_IMAGE_STATUS_STATE_STARTING_REPLAY: {
'health': 'ok',
'health': 'syncing',
'state_color': 'success',
'state': 'Starting'
},
rbd.MIRROR_IMAGE_STATUS_STATE_REPLAYING: {
'health': 'ok',
'health': 'syncing',
'state_color': 'success',
'state': 'Replaying'
},
@ -248,8 +257,9 @@ def _get_pool_datum(pool_name):
rbd.MIRROR_IMAGE_STATUS_STATE_STOPPED: {
'health': 'ok',
'state_color': 'info',
'state': 'Primary'
'state': 'Stopped'
}
}
rbdctx = rbd.RBD()
@ -271,6 +281,29 @@ def _get_pool_datum(pool_name):
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')
@ -296,26 +329,21 @@ def _get_content_data(): # pylint: disable=R0914
for mirror_image in mirror_images:
image = {
'pool_name': pool_name,
'name': mirror_image['name']
'name': mirror_image['name'],
'state_color': mirror_image['state_color'],
'state': mirror_image['state']
}
if mirror_image['health'] == 'ok':
image.update({
'state_color': mirror_image['state_color'],
'state': mirror_image['state'],
'description': mirror_image['description']
})
image_ready.append(image)
elif mirror_image['health'] == 'syncing':
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({
'state_color': mirror_image['state_color'],
'state': mirror_image['state'],
'description': mirror_image['description']
})
image_error.append(image)

View File

@ -20,9 +20,9 @@ describe('Mirroring page', () => {
});
it('should show text for all tabs', () => {
mirroring.getTabText(0).should('eq', 'Issues');
mirroring.getTabText(1).should('eq', 'Syncing');
mirroring.getTabText(2).should('eq', 'Ready');
mirroring.getTabText(0).should('eq', 'Issues (0)');
mirroring.getTabText(1).should('eq', 'Syncing (0)');
mirroring.getTabText(2).should('eq', 'Ready (0)');
});
describe('checks that edit mode functionality shows in the pools table', () => {

View File

@ -4,7 +4,7 @@
cdStatefulTab="image-list">
<li ngbNavItem="issues">
<a ngbNavLink
i18n>Issues</a>
i18n>Issues ({{ image_error.data.length }})</a>
<ng-template ngbNavContent>
<cd-table [data]="image_error.data"
columnMode="flex"
@ -17,7 +17,7 @@
</li>
<li ngbNavItem="syncing">
<a ngbNavLink
i18n>Syncing</a>
i18n>Syncing ({{ image_syncing.data.length }})</a>
<ng-template ngbNavContent>
<cd-table [data]="image_syncing.data"
columnMode="flex"
@ -30,7 +30,7 @@
</li>
<li ngbNavItem="ready">
<a ngbNavLink
i18n>Ready</a>
i18n>Ready ({{ image_ready.data.length }})</a>
<ng-template ngbNavContent>
<cd-table [data]="image_ready.data"
columnMode="flex"
@ -51,14 +51,13 @@
<span [ngClass]="row.state_color | mirrorHealthColor">{{ value }}</span>
</ng-template>
<ng-template #syncTmpl>
<span class="badge badge-info"
i18n>Syncing</span>
</ng-template>
<ng-template #progressTmpl
let-row="row"
let-value="value">
<ngb-progressbar type="info"
<div *ngIf="row.state === 'Replaying'">
</div>
<ngb-progressbar *ngIf="row.state === 'Syncing'"
type="info"
[value]="value"
[showValue]="true"></ngb-progressbar>
</ng-template>

View File

@ -41,42 +41,44 @@ export class ImageListComponent implements OnInit, OnDestroy {
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.syncTmpl,
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) => {