summaryrefslogtreecommitdiffstats
path: root/src/pybind/mgr/dashboard/frontend/src/app/shared/api/cephfs-snapshot-schedule.service.ts
diff options
context:
space:
mode:
Diffstat (limited to 'src/pybind/mgr/dashboard/frontend/src/app/shared/api/cephfs-snapshot-schedule.service.ts')
-rw-r--r--src/pybind/mgr/dashboard/frontend/src/app/shared/api/cephfs-snapshot-schedule.service.ts177
1 files changed, 177 insertions, 0 deletions
diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/api/cephfs-snapshot-schedule.service.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/api/cephfs-snapshot-schedule.service.ts
new file mode 100644
index 000000000..ade935a92
--- /dev/null
+++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/api/cephfs-snapshot-schedule.service.ts
@@ -0,0 +1,177 @@
+import { HttpClient } from '@angular/common/http';
+import { Injectable } from '@angular/core';
+import { Observable } from 'rxjs/internal/Observable';
+import { catchError, map } from 'rxjs/operators';
+import { intersection, isEqual, uniqWith } from 'lodash';
+import { SnapshotSchedule } from '../models/snapshot-schedule';
+import { of } from 'rxjs';
+import {
+ RepeaFrequencyPlural,
+ RepeaFrequencySingular,
+ RepeatFrequency
+} from '../enum/repeat-frequency.enum';
+import { RetentionFrequencyCopy } from '../enum/retention-frequency.enum';
+
+@Injectable({
+ providedIn: 'root'
+})
+export class CephfsSnapshotScheduleService {
+ baseURL = 'api/cephfs';
+
+ constructor(private http: HttpClient) {}
+
+ create(data: Record<string, any>): Observable<any> {
+ return this.http.post(`${this.baseURL}/snapshot/schedule`, data, { observe: 'response' });
+ }
+
+ update({ fs, path, ...rest }: Record<string, any>): Observable<any> {
+ return this.http.put(
+ `${this.baseURL}/snapshot/schedule/${fs}/${encodeURIComponent(path)}`,
+ rest,
+ { observe: 'response' }
+ );
+ }
+
+ activate({ fs, path, ...rest }: Record<string, any>): Observable<any> {
+ return this.http.post(
+ `${this.baseURL}/snapshot/schedule/${fs}/${encodeURIComponent(path)}/activate`,
+ rest,
+ { observe: 'response' }
+ );
+ }
+
+ deactivate({ fs, path, ...rest }: Record<string, any>): Observable<any> {
+ return this.http.post(
+ `${this.baseURL}/snapshot/schedule/${fs}/${encodeURIComponent(path)}/deactivate`,
+ rest,
+ { observe: 'response' }
+ );
+ }
+
+ delete({
+ fs,
+ path,
+ schedule,
+ start,
+ retentionPolicy,
+ subvol,
+ group
+ }: Record<string, any>): Observable<any> {
+ let deleteUrl = `${this.baseURL}/snapshot/schedule/${fs}/${encodeURIComponent(
+ path
+ )}/delete_snapshot?schedule=${schedule}&start=${encodeURIComponent(start)}`;
+ if (retentionPolicy) {
+ deleteUrl += `&retention_policy=${retentionPolicy}`;
+ }
+ if (subvol && group) {
+ deleteUrl += `&subvol=${encodeURIComponent(subvol)}&group=${encodeURIComponent(group)}`;
+ }
+ return this.http.delete(deleteUrl);
+ }
+
+ checkScheduleExists(
+ path: string,
+ fs: string,
+ interval: number,
+ frequency: RepeatFrequency
+ ): Observable<boolean> {
+ return this.getSnapshotScheduleList(path, fs, false).pipe(
+ map((response) => {
+ const index = response.findIndex(
+ (x) => x.path === path && x.schedule === `${interval}${frequency}`
+ );
+ return index > -1;
+ }),
+ catchError(() => {
+ return of(false);
+ })
+ );
+ }
+
+ checkRetentionPolicyExists(
+ path: string,
+ fs: string,
+ retentionFrequencies: string[],
+ retentionFrequenciesRemoved: string[] = [],
+ isSubvolume = false
+ ): Observable<{ exists: boolean; errorIndex: number }> {
+ return this.getSnapshotSchedule(path, fs, false).pipe(
+ map((response) => {
+ let errorIndex = -1;
+ let exists = false;
+ const index = response.findIndex((x) =>
+ isSubvolume ? x.path.startsWith(path) : x.path === path
+ );
+ const result = retentionFrequencies?.length
+ ? intersection(
+ Object.keys(response?.[index]?.retention).filter(
+ (v) => !retentionFrequenciesRemoved.includes(v)
+ ),
+ retentionFrequencies
+ )
+ : [];
+ exists = !!result?.length;
+ result?.forEach((r) => (errorIndex = retentionFrequencies.indexOf(r)));
+
+ return { exists, errorIndex };
+ }),
+ catchError(() => {
+ return of({ exists: false, errorIndex: -1 });
+ })
+ );
+ }
+
+ getSnapshotSchedule(path: string, fs: string, recursive = true): Observable<SnapshotSchedule[]> {
+ return this.http
+ .get<SnapshotSchedule[]>(
+ `${this.baseURL}/snapshot/schedule/${fs}?path=${path}&recursive=${recursive}`
+ )
+ .pipe(
+ catchError(() => {
+ return of([]);
+ })
+ );
+ }
+
+ getSnapshotScheduleList(
+ path: string,
+ fs: string,
+ recursive = true
+ ): Observable<SnapshotSchedule[]> {
+ return this.getSnapshotSchedule(path, fs, recursive).pipe(
+ map((snapList: SnapshotSchedule[]) =>
+ uniqWith(
+ snapList.map((snapItem: SnapshotSchedule) => ({
+ ...snapItem,
+ scheduleCopy: this.parseScheduleCopy(snapItem.schedule),
+ status: snapItem.active ? 'Active' : 'Inactive',
+ subvol: snapItem?.subvol,
+ retentionCopy: this.parseRetentionCopy(snapItem?.retention),
+ retention: Object.values(snapItem?.retention || [])?.length
+ ? Object.entries(snapItem.retention)
+ ?.map?.(([frequency, interval]) => `${interval}${frequency.toLocaleUpperCase()}`)
+ .join(' ')
+ : '-'
+ })),
+ isEqual
+ )
+ )
+ );
+ }
+
+ parseScheduleCopy(schedule: string): string {
+ const scheduleArr = schedule.split('');
+ const interval = Number(scheduleArr.filter((x) => !isNaN(Number(x))).join(''));
+ const frequencyUnit = scheduleArr[scheduleArr.length - 1];
+ const frequency =
+ interval > 1 ? RepeaFrequencyPlural[frequencyUnit] : RepeaFrequencySingular[frequencyUnit];
+ return $localize`Every ${interval > 1 ? interval + ' ' : ''}${frequency}`;
+ }
+
+ parseRetentionCopy(retention: string | Record<string, number>): string[] {
+ if (!retention) return ['-'];
+ return Object.entries(retention).map(([frequency, interval]) =>
+ $localize`${interval} ${RetentionFrequencyCopy[frequency]}`.toLocaleLowerCase()
+ );
+ }
+}