]> git.proxmox.com Git - ceph.git/blob - ceph/src/pybind/mgr/dashboard/frontend/src/app/shared/services/module-status-guard.service.ts
import ceph 16.2.7
[ceph.git] / ceph / src / pybind / mgr / dashboard / frontend / src / app / shared / services / module-status-guard.service.ts
1 import { HttpClient } from '@angular/common/http';
2 import { Injectable } from '@angular/core';
3 import { ActivatedRouteSnapshot, CanActivate, CanActivateChild, Router } from '@angular/router';
4
5 import { of as observableOf } from 'rxjs';
6 import { catchError, map } from 'rxjs/operators';
7
8 import { MgrModuleService } from '~/app/shared/api/mgr-module.service';
9 import { Icons } from '~/app/shared/enum/icons.enum';
10
11 /**
12 * This service checks if a route can be activated by executing a
13 * REST API call to '/api/<apiPath>/status'. If the returned response
14 * states that the module is not available, then the user is redirected
15 * to the specified <redirectTo> URL path.
16 *
17 * A controller implementing this endpoint should return an object of
18 * the following form:
19 * {'available': true|false, 'message': null|string}.
20 *
21 * The configuration of this guard should look like this:
22 * const routes: Routes = [
23 * {
24 * path: 'rgw/bucket',
25 * component: RgwBucketListComponent,
26 * canActivate: [AuthGuardService, ModuleStatusGuardService],
27 * data: {
28 * moduleStatusGuardConfig: {
29 * apiPath: 'rgw',
30 * redirectTo: 'rgw/501'
31 * }
32 * }
33 * },
34 * ...
35 */
36 @Injectable({
37 providedIn: 'root'
38 })
39 export class ModuleStatusGuardService implements CanActivate, CanActivateChild {
40 // TODO: Hotfix - remove ALLOWLIST'ing when a generic ErrorComponent is implemented
41 static readonly ALLOWLIST: string[] = ['501'];
42
43 constructor(
44 private http: HttpClient,
45 private router: Router,
46 private mgrModuleService: MgrModuleService
47 ) {}
48
49 canActivate(route: ActivatedRouteSnapshot) {
50 return this.doCheck(route);
51 }
52
53 canActivateChild(childRoute: ActivatedRouteSnapshot) {
54 return this.doCheck(childRoute);
55 }
56
57 private doCheck(route: ActivatedRouteSnapshot) {
58 if (route.url.length > 0 && ModuleStatusGuardService.ALLOWLIST.includes(route.url[0].path)) {
59 return observableOf(true);
60 }
61 const config = route.data['moduleStatusGuardConfig'];
62 let backendCheck = false;
63 if (config.backend) {
64 this.mgrModuleService.getConfig('orchestrator').subscribe(
65 (resp) => {
66 backendCheck = config.backend === resp['orchestrator'];
67 },
68 () => {
69 this.router.navigate([config.redirectTo]);
70 return observableOf(false);
71 }
72 );
73 }
74 return this.http.get(`api/${config.apiPath}/status`).pipe(
75 map((resp: any) => {
76 if (!resp.available && !backendCheck) {
77 this.router.navigate([config.redirectTo || ''], {
78 state: {
79 header: config.header,
80 message: resp.message,
81 section: config.section,
82 section_info: config.section_info,
83 icon: Icons.wrench
84 }
85 });
86 }
87 return resp.available;
88 }),
89 catchError(() => {
90 this.router.navigate([config.redirectTo]);
91 return observableOf(false);
92 })
93 );
94 }
95 }