Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NAS-131326 / 25.04 / Simplify HA upgrade logic + NAS-131325: system.reboot.info and failover.reboot.info methods and events #10744

Merged
merged 26 commits into from
Nov 15, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
a31ad6e
NAS-131326: Simplify HA upgrade logic
Sep 24, 2024
544ef1c
NAS-131326: Add Reboot Info store
Sep 24, 2024
a7cf359
NAS-131326: Add Reboot Info dialog
Sep 25, 2024
cb566cb
NAS-131326: Add unit tests
Sep 26, 2024
cb9f196
Merge branch 'origin/master' into 131326/NAS-131326
Sep 27, 2024
424ddbe
NAS-131326: Add unit tests
Sep 30, 2024
3918657
NAS-131326: Fix remarks
Oct 3, 2024
80a2d08
NAS-131326: Remove unnecessary filters
Oct 7, 2024
14193eb
NAS-131326: Rename `RebootDialog` to `RebootRequiredDialog`
Oct 7, 2024
dbca167
NAS-131326: Add reboot reason
Oct 9, 2024
21ad32c
Merge branch 'origin/master' into 131326/NAS-131326
Oct 9, 2024
f92048d
Merge branch 'origin/master' into 131326/NAS-131326
Oct 10, 2024
261ae44
NAS-131326: Fix merge errors
Oct 14, 2024
1b0b76f
Merge branch 'origin/master' into 131326/NAS-131326
Oct 15, 2024
e68f634
NAS-131326: Add cancel button
Oct 15, 2024
a590d42
Merge branch 'origin/master' into 131326/NAS-131326
Oct 17, 2024
f914985
Merge branch 'origin/master' into 131326/NAS-131326
Oct 30, 2024
aa95da5
NAS-131326: Fix linter errors
Oct 30, 2024
68d3419
NAS-131326: Remove `HaFipsEffects`
Oct 31, 2024
dff1d06
NAS-131326: Fix remarks
Nov 4, 2024
ef34519
Merge branch 'origin/master' into 131326/NAS-131326
Nov 5, 2024
a84c004
Merge branch 'origin/master' into 131326/NAS-131326
Nov 12, 2024
185f0b0
Merge branch 'origin/master' into 131326/NAS-131326
Nov 14, 2024
7af5895
Merge branch 'origin/master' into 131326/NAS-131326
Nov 14, 2024
65644a4
Merge branch 'master' into NAS-131326
bvasilenko Nov 15, 2024
506bccb
Merge branch 'master' into NAS-131326
bvasilenko Nov 15, 2024
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
2 changes: 1 addition & 1 deletion src/app/helptext/topbar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export const helptextTopbar = {
tc_connect: T('Connecting to TrueCommand'),
tc_status: T('Status of TrueCommand'),
update: T('Update in Progress'),
upgrade_waiting: T('Upgrade Waiting to Finish'),
reboot_info: T('Reboot Info'),
pending_network_changes: T('Pending Network Changes'),
directory_services_monitor: T('Directory Services Monitor'),
resilvering: T('Resilvering'),
Expand Down
4 changes: 3 additions & 1 deletion src/app/interfaces/api/api-call-directory.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ import {
import { Privilege, PrivilegeRole, PrivilegeUpdate } from 'app/interfaces/privilege.interface';
import { Process } from 'app/interfaces/process.interface';
import { QueryParams } from 'app/interfaces/query-api.interface';
import { FailoverRebootInfo, SystemRebootInfo } from 'app/interfaces/reboot-info.interface';
import { ReplicationConfigUpdate } from 'app/interfaces/replication-config-update.interface';
import { ReplicationConfig } from 'app/interfaces/replication-config.interface';
import {
Expand Down Expand Up @@ -460,11 +461,11 @@ export interface ApiCallDirectory {
'failover.get_ips': { params: void; response: string[] };
'failover.licensed': { params: void; response: boolean };
'failover.node': { params: void; response: string };
'failover.reboot.info': { params: void; response: FailoverRebootInfo };
'failover.status': { params: void; response: FailoverStatus };
'failover.sync_from_peer': { params: void; response: void };
'failover.sync_to_peer': { params: [{ reboot?: boolean }]; response: void };
'failover.update': { params: [FailoverUpdate]; response: FailoverConfig };
'failover.upgrade_pending': { params: void; response: boolean };

// Filesystem
'filesystem.acl_is_trivial': {
Expand Down Expand Up @@ -815,6 +816,7 @@ export interface ApiCallDirectory {
'system.security.info.fips_available': { params: void; response: boolean };
'system.set_time': { params: [number]; response: void };
'system.ready': { params: void; response: boolean };
'system.reboot.info': { params: void; response: SystemRebootInfo };
'system.state': { params: void; response: SystemState };
'system.version': { params: void; response: string };
'system.version_short': { params: void; response: string };
Expand Down
3 changes: 3 additions & 0 deletions src/app/interfaces/api/api-event-directory.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { FailoverDisabledReasonEvent } from 'app/interfaces/failover-disabled-re
import { Group } from 'app/interfaces/group.interface';
import { Job } from 'app/interfaces/job.interface';
import { Pool } from 'app/interfaces/pool.interface';
import { FailoverRebootInfo, SystemRebootInfo } from 'app/interfaces/reboot-info.interface';
import { ReportingRealtimeUpdate } from 'app/interfaces/reporting.interface';
import { PoolScan } from 'app/interfaces/resilver-job.interface';
import { Service } from 'app/interfaces/service.interface';
Expand All @@ -28,12 +29,14 @@ export interface ApiEventDirectory {
'disk.query': { response: Disk };
'docker.state': { response: DockerStatusData };
'failover.disabled.reasons': { response: FailoverDisabledReasonEvent };
'failover.reboot.info': { response: FailoverRebootInfo };
'failover.status': { response: { status: FailoverStatus } };
'group.query': { response: Group };
'pool.query': { response: Pool };
'reporting.realtime': { response: ReportingRealtimeUpdate };
'service.query': { response: Service };
'smart.test.progress': { response: SmartTestProgressUpdate };
'system.reboot.info': { response: SystemRebootInfo };
'truecommand.config': { response: TrueCommandConfig };
'user.query': { response: User };
'vm.query': { response: VirtualMachine };
Expand Down
1 change: 0 additions & 1 deletion src/app/interfaces/api/api-job-directory.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,6 @@ export interface ApiJobDirectory {
// Failover
'failover.reboot.other_node': { params: void; response: void };
'failover.upgrade': { params: [FailoverUpgradeParams]; response: boolean };
'failover.upgrade_finish': { params: void; response: boolean };

// Filesystem
'filesystem.put': { params: FilesystemPutParams; response: boolean };
Expand Down
14 changes: 14 additions & 0 deletions src/app/interfaces/reboot-info.interface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
export interface SystemRebootInfo {
boot_id: string;
reboot_required_reasons: RebootRequiredReasons[];
}

export interface FailoverRebootInfo {
this_node: SystemRebootInfo;
other_node: SystemRebootInfo | null;
}

export interface RebootRequiredReasons {
code: string;
reason: string;
}
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,6 @@ describe('AlertsPanelComponent', () => {
reasons: [],
},
isHaLicensed: true,
isUpgradePending: false,
},
},
}),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<div class="dialog-content" mat-dialog-content>
<h3 mat-dialog-title class="dialog-title">
{{ 'Reboot Info' | translate }}
</h3>

<ng-container
*appLet="thisNodeInfo$ | async as nodeInfo"
[ngTemplateOutlet]="reasonsTemplate"
[ngTemplateOutletContext]="{
$implicit: {
reasons: nodeInfo?.reboot_required_reasons,
message: 'The local node must be rebooted because' | translate,
}
}"
></ng-container>

<ng-container
*appLet="otherNodeInfo$ | async as nodeInfo"
[ngTemplateOutlet]="reasonsTemplate"
[ngTemplateOutletContext]="{
$implicit: {
reasons: nodeInfo?.reboot_required_reasons,
message: 'The remote node must be rebooted because' | translate,
}
}"
></ng-container>
</div>

<ng-template #reasonsTemplate let-props>
@if (typeReasons(props.reasons); as reasons) {
<div class="reasons">
<p class="dialog-message">
<span>{{ props.message }}:</span>
</p>
@for (reason of reasons; track reason) {
<li>
{{ reason.reason }}
</li>
}
</div>
}
</ng-template>
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
.dialog-content {
padding-bottom: 5px;
}

.dialog-message,
.dialog-title {
margin-bottom: 5px;
margin-top: 0;
padding: 0;
}

.reasons {
padding: 0 12px 12px;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { createComponentFactory, Spectator } from '@ngneat/spectator/jest';
import { provideMockStore } from '@ngrx/store/testing';
import { SystemRebootInfo } from 'app/interfaces/reboot-info.interface';
import { RebootDialogComponent } from 'app/modules/dialog/components/reboot-dialog/reboot-dialog.component';
import {
selectOtherNodeInfo,
selectThisNodeInfo,
} from 'app/store/reboot-info/reboot-info.selectors';

const fakeThisNodeInfo: SystemRebootInfo = {
boot_id: 'this-boot-id',
reboot_required_reasons: [
{ code: 'FIPS', reason: 'Test Reason 1' },
{ code: 'FIPS', reason: 'Test Reason 2' },
],
};

const fakeOtherNodeInfo: SystemRebootInfo = {
boot_id: 'other-boot-id',
reboot_required_reasons: [
{ code: 'FIPS', reason: 'Test Reason 3' },
{ code: 'FIPS', reason: 'Test Reason 4' },
],
};

describe('RebootDialogComponent', () => {
let spectator: Spectator<RebootDialogComponent>;
const createComponent = createComponentFactory({
component: RebootDialogComponent,
providers: [
provideMockStore({
selectors: [
{
selector: selectThisNodeInfo,
value: fakeThisNodeInfo,
},
{
selector: selectOtherNodeInfo,
value: fakeOtherNodeInfo,
},
],
}),
],
});

beforeEach(() => {
spectator = createComponent();
});

it('shows reasons', () => {
expect(
spectator.queryAll('.reasons li').map((item) => item.textContent.trim()),
).toEqual([
'Test Reason 1',
'Test Reason 2',
'Test Reason 3',
'Test Reason 4',
]);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { CdkScrollable } from '@angular/cdk/scrolling';
import { AsyncPipe, NgTemplateOutlet } from '@angular/common';
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { MatDialogContent, MatDialogTitle } from '@angular/material/dialog';
import { UntilDestroy } from '@ngneat/until-destroy';
import { Store } from '@ngrx/store';
import { TranslateModule } from '@ngx-translate/core';
import { LetDirective } from 'app/directives/app-let.directive';
import { RebootRequiredReasons } from 'app/interfaces/reboot-info.interface';
import { AppsState } from 'app/store';
import { selectOtherNodeInfo, selectThisNodeInfo } from 'app/store/reboot-info/reboot-info.selectors';

@UntilDestroy()
@Component({
selector: 'ix-reboot-dialog',
templateUrl: './reboot-dialog.component.html',
styleUrls: ['./reboot-dialog.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
imports: [
CdkScrollable,
MatDialogContent,
MatDialogTitle,
TranslateModule,
AsyncPipe,
LetDirective,
NgTemplateOutlet,
],
})
export class RebootDialogComponent {
thisNodeInfo$ = this.store$.select(selectThisNodeInfo);
otherNodeInfo$ = this.store$.select(selectOtherNodeInfo);

constructor(private store$: Store<AppsState>) {}

typeReasons(reasons: unknown): RebootRequiredReasons[] {
return reasons as RebootRequiredReasons[];
}
}

This file was deleted.

This file was deleted.

This file was deleted.

13 changes: 12 additions & 1 deletion src/app/modules/layout/topbar/topbar.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,19 @@

<ix-truecommand-button></ix-truecommand-button>

@if (hasRebootRequiredReasons) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can make hasRebootRequiredReasons a signal.

<button
mat-icon-button
class="topbar-button-right"
ixTest="reboot-info"
[matTooltip]="tooltips.reboot_info | translate"
(click)="showRebootInfoDialog()"
>
<ix-icon class="movement" name="update"></ix-icon>
</button>
}

<!-- finish update -->
<ix-failover-upgrade-indicator></ix-failover-upgrade-indicator>
@if (updateIsRunning) {
<button
mat-icon-button
Expand Down
Loading
Loading