cloudfoundry/stratos

View on GitHub
src/frontend/packages/kubernetes/src/kubernetes/store/analysis.effects.ts

Summary

Maintainability
A
0 mins
Test Coverage
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Actions, Effect, ofType } from '@ngrx/effects';
import { Store } from '@ngrx/store';
import { catchError, flatMap, mergeMap } from 'rxjs/operators';

import { environment } from '../../../../core/src/environments/environment';
import { AppState, entityCatalog, NormalizedResponse, WrapperRequestActionSuccess } from '../../../../store/src/public-api';
import { ApiRequestTypes } from '../../../../store/src/reducers/api-request-reducer/request-helpers';
import { StartRequestAction, WrapperRequestActionFailed } from '../../../../store/src/types/request.types';
import { KubeScoreReportHelper } from '../services/kubescore-report.helper';
import { PopeyeReportHelper } from '../services/popeye-report.helper';
import {
  DELETE_ANALYSIS_REPORT_TYPES,
  DeleteAnalysisReport,
  GET_ANALYSIS_REPORT_BY_ID_TYPES,
  GET_ANALYSIS_REPORTS_BY_PATH_TYPES,
  GET_ANALYSIS_REPORTS_TYPES,
  GetAnalysisReportById,
  GetAnalysisReports,
  GetAnalysisReportsByPath,
  RUN_ANALYSIS_REPORT_TYPES,
  RunAnalysisReport,
} from './analysis.actions';
import { AnalysisReport } from './kube.types';

@Injectable()
export class AnalysisEffects {
  proxyAPIVersion = environment.proxyAPIVersion;

  constructor(
    private http: HttpClient,
    private actions$: Actions,
    private store: Store<AppState>,
  ) { }

  @Effect()
  fetchAnalysisReports$ = this.actions$.pipe(
    ofType<GetAnalysisReports>(GET_ANALYSIS_REPORTS_TYPES[0]),
    flatMap(action => {
      this.store.dispatch(new StartRequestAction(action));
      const headers = new HttpHeaders({});
      const requestArgs = {
        headers
      };
      const url = `/pp/${this.proxyAPIVersion}/analysis/reports/${action.kubeGuid}`;
      const entityKey = entityCatalog.getEntityKey(action);
      return this.http.get(url, requestArgs).pipe(
        mergeMap(response => {
          const res: NormalizedResponse = {
            entities: { [entityKey]: {} },
            result: []
          };
          const items: any = response as Array<any>;
          items.forEach(item => {
            const id = item.id;
            res.entities[entityKey][id] = item;
            res.result.push(id);
          });
          return [new WrapperRequestActionSuccess(res, action)];
        }),
        catchError(error => [
          new WrapperRequestActionFailed(error.message, action, 'fetch', {
            endpointIds: [action.kubeGuid],
            url: error.url || url,
            eventCode: error.status ? error.status + '' : '500',
            message: 'Kubernetes Analysis Report request error',
            error
          })
        ])
      );
    })
  );

  @Effect()
  fetchAnalysisReportById$ = this.actions$.pipe(
    ofType<GetAnalysisReportById>(GET_ANALYSIS_REPORT_BY_ID_TYPES[0]),
    flatMap(action => {
      this.store.dispatch(new StartRequestAction(action));

      const url = `/pp/${this.proxyAPIVersion}/analysis/reports/${action.kubeGuid}/${action.guid}`;
      const headers = new HttpHeaders({});
      const requestArgs = {
        headers,
      };
      const entityKey = entityCatalog.getEntityKey(action);

      return this.http.get(url, requestArgs).pipe(
        mergeMap(response => {
          this.processReport(response);

          const res: NormalizedResponse = {
            entities: {
              [entityKey]: {
                [action.guid]: response
              }
            },
            result: [action.guid]
          };
          return [new WrapperRequestActionSuccess(res, action)];
        }),
        catchError(error => [
          new WrapperRequestActionFailed(error.message, action, 'fetch', {
            endpointIds: [action.kubeGuid],
            url: error.url || url,
            eventCode: error.status ? error.status + '' : '500',
            message: 'Kubernetes Analysis Report request error',
            error
          })
        ])
      );
    })
  );

  @Effect()
  fetchAnalysisReportByPath$ = this.actions$.pipe(
    ofType<GetAnalysisReportsByPath>(GET_ANALYSIS_REPORTS_BY_PATH_TYPES[0]),
    flatMap(action => {
      this.store.dispatch(new StartRequestAction(action));

      const url = `/pp/${this.proxyAPIVersion}/analysis/completed/${action.kubeGuid}/${action.path}`;
      const headers = new HttpHeaders({});
      const requestArgs = {
        headers,
      };
      const schema = action.entity[0];
      const entityKey = entityCatalog.getEntityKey(action);
      return this.http.get(url, requestArgs).pipe(
        mergeMap((response: AnalysisReport[]) => {
          const res: NormalizedResponse = {
            entities: {
              [entityKey]: {}
            },
            result: []
          };
          response.forEach(report => {
            const guid = schema.getId(report);
            res.entities[entityKey][guid] = report;
            res.result.push(guid);
          });
          return [new WrapperRequestActionSuccess(res, action)];
        }),
        catchError(error => [
          new WrapperRequestActionFailed(error.message, action, 'fetch', {
            endpointIds: [action.kubeGuid],
            url: error.url || url,
            eventCode: error.status ? error.status + '' : '500',
            message: 'Kubernetes Analysis Report request error',
            error
          })
        ])
      );
    })
  );

  @Effect()
  deleteAnalysisReport$ = this.actions$.pipe(
    ofType<DeleteAnalysisReport>(DELETE_ANALYSIS_REPORT_TYPES[0]),
    flatMap(action => {
      const type: ApiRequestTypes = 'delete';

      this.store.dispatch(new StartRequestAction(action, type));

      const url = `/pp/${this.proxyAPIVersion}/analysis/reports`;
      const headers = new HttpHeaders({});
      const requestArgs = {
        headers,
        body: [action.guid]
      };

      return this.http.delete(url, requestArgs).pipe(
        mergeMap(() => {
          const res: NormalizedResponse = {
            entities: { [entityCatalog.getEntityKey(action)]: {} },
            result: []
          };
          return [new WrapperRequestActionSuccess(res, action, type)];
        }),
        catchError(error => [
          new WrapperRequestActionFailed(error.message, action, type, {
            endpointIds: [action.kubeGuid],
            url: error.url || url,
            eventCode: error.status ? error.status + '' : '500',
            message: 'Kubernetes Analysis Report request error',
            error
          })
        ])
      );
    })
  );

  @Effect()
  runAnalysisReport$ = this.actions$.pipe(
    ofType<RunAnalysisReport>(RUN_ANALYSIS_REPORT_TYPES[0]),
    flatMap(action => {
      const type: ApiRequestTypes = 'create';

      this.store.dispatch(new StartRequestAction(action, type));

      const { namespace, app } = action;
      const body = {
        namespace,
        app,
      };

      // Start an Analysis
      const url = `/pp/${this.proxyAPIVersion}/analysis/run/${action.guid}/${action.kubeGuid}`;
      const headers = new HttpHeaders({});
      const requestArgs = {
        headers,
      };

      return this.http.post(url, body, requestArgs).pipe(
        mergeMap((response: AnalysisReport) => {
          const res: NormalizedResponse = {
            entities: { [entityCatalog.getEntityKey(action)]: { [response.id]: response } },
            result: [response.id]
          };
          return [new WrapperRequestActionSuccess(res, action, type)];
        }),
        catchError(error => [
          new WrapperRequestActionFailed(error.message, action, type, {
            endpointIds: [action.kubeGuid],
            url: error.url || url,
            eventCode: error.status ? error.status + '' : '500',
            message: 'Kubernetes Analysis Report request error',
            error
          })
        ])
      );

    })
  );


  private processReport(report: any) {
    // Check the path of the report
    if (report.path.split('/').length !== 2) {
      return;
    }

    switch (report.format) {
      case 'popeye':
        const helper = new PopeyeReportHelper(report);
        helper.map();
        break;
      case 'kubescore':
        const kubeScoreHelper = new KubeScoreReportHelper(report);
        kubeScoreHelper.map();
        break;
      default:
        console.warn('Do not know how to handle this report type: ', report.format);
        break;
    }
  }
}