diff --git a/custom-src/frontend/app/custom/helm/create-release/create-release.component.ts b/custom-src/frontend/app/custom/helm/create-release/create-release.component.ts index 709dfdc928..45793d2149 100644 --- a/custom-src/frontend/app/custom/helm/create-release/create-release.component.ts +++ b/custom-src/frontend/app/custom/helm/create-release/create-release.component.ts @@ -3,23 +3,19 @@ import { Component, ElementRef, OnDestroy, OnInit, ViewChild } from '@angular/co import { FormControl, FormGroup, Validators } from '@angular/forms'; import { MatTextareaAutosize } from '@angular/material/input'; import { ActivatedRoute } from '@angular/router'; -import { Store } from '@ngrx/store'; -import { PaginationMonitorFactory } from 'frontend/packages/store/src/monitors/pagination-monitor.factory'; -import { getPaginationObservables } from 'frontend/packages/store/src/reducers/pagination-reducer/pagination-reducer.helper'; import { BehaviorSubject, combineLatest, Observable, of, Subscription } from 'rxjs'; import { distinctUntilChanged, filter, first, map, pairwise, startWith, switchMap } from 'rxjs/operators'; -import { AppState } from '../../../../../store/src/app-state'; -import { EntityMonitorFactory } from '../../../../../store/src/monitors/entity-monitor.factory.service'; +import { RequestInfoState } from '../../../../../store/src/reducers/api-request-reducer/types'; import { EndpointsService } from '../../../core/endpoints.service'; import { safeUnsubscribe } from '../../../core/utils.service'; import { ConfirmationDialogConfig } from '../../../shared/components/confirmation-dialog.config'; import { ConfirmationDialogService } from '../../../shared/components/confirmation-dialog.service'; import { StepOnNextFunction, StepOnNextResult } from '../../../shared/components/stepper/step/step.component'; +import { kubeEntityCatalog } from '../../kubernetes/kubernetes-entity-catalog'; import { KUBERNETES_ENDPOINT_TYPE } from '../../kubernetes/kubernetes-entity-factory'; import { KubernetesNamespace } from '../../kubernetes/store/kube.types'; -import { CreateKubernetesNamespace, GetKubernetesNamespaces } from '../../kubernetes/store/kubernetes.actions'; -import { HelmInstall } from '../store/helm.actions'; +import { helmEntityCatalog } from '../helm-entity-catalog'; import { HelmInstallValues } from '../store/helm.types'; @Component({ @@ -61,11 +57,8 @@ export class CreateReleaseComponent implements OnInit, OnDestroy { constructor( private route: ActivatedRoute, public endpointsService: EndpointsService, - private store: Store, private httpClient: HttpClient, private confirmDialog: ConfirmationDialogService, - private pmf: PaginationMonitorFactory, - private emf: EntityMonitorFactory ) { const chart = this.route.snapshot.params; this.cancelUrl = `/monocular/charts/${chart.repo}/${chart.chartName}/${chart.version}`; @@ -98,12 +91,7 @@ export class CreateReleaseComponent implements OnInit, OnDestroy { this.kubeEndpoints$ = this.endpointsService.connectedEndpointsOfTypes(KUBERNETES_ENDPOINT_TYPE); - const action = new GetKubernetesNamespaces(null); - const allNamespaces$ = getPaginationObservables({ - store: this.store, - action, - paginationMonitor: this.pmf.create(action.paginationKey, action, true) - }).entities$.pipe( + const allNamespaces$ = kubeEntityCatalog.namespace.store.getPaginationService(null).entities$.pipe( filter(namespaces => !!namespaces), first() ); @@ -234,12 +222,10 @@ export class CreateReleaseComponent implements OnInit, OnDestroy { }); } - const action = new CreateKubernetesNamespace( + return kubeEntityCatalog.namespace.api.create( this.details.controls.releaseNamespace.value, - this.details.controls.endpoint.value); - this.store.dispatch(action); - - return this.emf.create(action.guid, action).entityRequest$.pipe( + this.details.controls.endpoint.value + ).pipe( pairwise(), filter(([oldVal, newVal]) => oldVal.creating && !newVal.creating), map(([, newVal]) => newVal), @@ -267,11 +253,8 @@ export class CreateReleaseComponent implements OnInit, OnDestroy { }; // Make the request - const action = new HelmInstall(values); - this.store.dispatch(action); - - // Wait for result of request - return this.emf.create(action.guid, action).entityRequest$.pipe( + return helmEntityCatalog.chart.api.install(values).pipe( + // Wait for result of request filter(state => !!state), pairwise(), filter(([oldVal, newVal]) => (oldVal.creating && !newVal.creating)), diff --git a/custom-src/frontend/app/custom/helm/helm-entity-catalog.ts b/custom-src/frontend/app/custom/helm/helm-entity-catalog.ts new file mode 100644 index 0000000000..288b527982 --- /dev/null +++ b/custom-src/frontend/app/custom/helm/helm-entity-catalog.ts @@ -0,0 +1,17 @@ +import { StratosCatalogEndpointEntity, StratosCatalogEntity } from '../../../../store/src/entity-catalog/entity-catalog-entity/entity-catalog-entity'; import { IFavoriteMetadata } from '../../../../store/src/types/user-favorites.types'; import { MonocularChart, HelmVersion } from './store/helm.types'; import { HelmChartActionBuilders, HelmVersionActionBuilders } from './store/helm.action-builders'; + +/** + * A strongly typed collection of Helm Catalog Entities. + * This can be used to access functionality exposed by each specific type, such as get, update, delete, etc + */ +export class HelmEntityCatalog { + endpoint: StratosCatalogEndpointEntity; + chart: StratosCatalogEntity + version: StratosCatalogEntity +} + +/** + * A strongly typed collection of Helm Catalog Entities. + * This can be used to access functionality exposed by each specific type, such as get, update, delete, etc + */ +export const helmEntityCatalog: HelmEntityCatalog = new HelmEntityCatalog(); diff --git a/custom-src/frontend/app/custom/helm/helm-entity-generator.ts b/custom-src/frontend/app/custom/helm/helm-entity-generator.ts index 0fb65457a6..380b225a40 100644 --- a/custom-src/frontend/app/custom/helm/helm-entity-generator.ts +++ b/custom-src/frontend/app/custom/helm/helm-entity-generator.ts @@ -5,12 +5,19 @@ import { } from '../../../../store/src/entity-catalog/entity-catalog-entity/entity-catalog-entity'; import { StratosEndpointExtensionDefinition } from '../../../../store/src/entity-catalog/entity-catalog.types'; import { IFavoriteMetadata } from '../../../../store/src/types/user-favorites.types'; +import { helmEntityCatalog } from './helm-entity-catalog'; import { HELM_ENDPOINT_TYPE, helmEntityFactory, helmVersionsEntityType, monocularChartsEntityType, } from './helm-entity-factory'; +import { + HelmChartActionBuilders, + helmChartActionBuilders, + HelmVersionActionBuilders, + helmVersionActionBuilders, +} from './store/helm.action-builders'; import { HelmVersion, MonocularChart } from './store/helm.types'; @@ -36,10 +43,11 @@ export function generateHelmEntities(): StratosBaseCatalogEntity[] { } function generateEndpointEntity(endpointDefinition: StratosEndpointExtensionDefinition) { - return new StratosCatalogEndpointEntity( + helmEntityCatalog.endpoint = new StratosCatalogEndpointEntity( endpointDefinition, metadata => `/monocular/repos/${metadata.guid}`, ); + return helmEntityCatalog.endpoint; } function generateChartEntity(endpointDefinition: StratosEndpointExtensionDefinition) { @@ -48,7 +56,13 @@ function generateChartEntity(endpointDefinition: StratosEndpointExtensionDefinit schema: helmEntityFactory(monocularChartsEntityType), endpoint: endpointDefinition }; - return new StratosCatalogEntity(definition); + helmEntityCatalog.chart = new StratosCatalogEntity( + definition, + { + actionBuilders: helmChartActionBuilders + } + ); + return helmEntityCatalog.chart; } function generateVersionEntity(endpointDefinition: StratosEndpointExtensionDefinition) { @@ -57,7 +71,13 @@ function generateVersionEntity(endpointDefinition: StratosEndpointExtensionDefin schema: helmEntityFactory(helmVersionsEntityType), endpoint: endpointDefinition }; - return new StratosCatalogEntity(definition); + helmEntityCatalog.version = new StratosCatalogEntity( + definition, + { + actionBuilders: helmVersionActionBuilders + } + ); + return helmEntityCatalog.version; } diff --git a/custom-src/frontend/app/custom/helm/helm-testing.module.ts b/custom-src/frontend/app/custom/helm/helm-testing.module.ts index 9ee747eaf0..2bace2cf52 100644 --- a/custom-src/frontend/app/custom/helm/helm-testing.module.ts +++ b/custom-src/frontend/app/custom/helm/helm-testing.module.ts @@ -7,12 +7,14 @@ import { RouterTestingModule } from '@angular/router/testing'; import { CATALOGUE_ENTITIES, EntityCatalogFeatureModule } from '../../../../store/src/entity-catalog.module'; import { entityCatalog, TestEntityCatalog } from '../../../../store/src/entity-catalog/entity-catalog'; import { createBasicStoreModule } from '../../../../store/testing/public-api'; +import { AppTestModule } from '../../../test-framework/core-test.helper'; import { generateStratosEntities } from '../../base-entity-types'; import { CoreModule } from '../../core/core.module'; import { SharedModule } from '../../shared/shared.module'; import { HelmReleaseGuid } from '../kubernetes/workloads/workload.types'; import { generateHelmEntities } from './helm-entity-generator'; + @NgModule({ imports: [{ ngModule: EntityCatalogFeatureModule, @@ -53,6 +55,7 @@ export const HelmReleaseGuidMock = { }; export const HelmBaseTestModules = [ + AppTestModule, HelmTestingModule, RouterTestingModule, CoreModule, diff --git a/custom-src/frontend/app/custom/helm/list-types/monocular-charts-data-source.ts b/custom-src/frontend/app/custom/helm/list-types/monocular-charts-data-source.ts index 2a1c005854..afefeae64e 100644 --- a/custom-src/frontend/app/custom/helm/list-types/monocular-charts-data-source.ts +++ b/custom-src/frontend/app/custom/helm/list-types/monocular-charts-data-source.ts @@ -4,8 +4,7 @@ import { PaginationEntityState } from '../../../../../store/src//types/paginatio import { AppState } from '../../../../../store/src/app-state'; import { ListDataSource } from '../../../shared/components/list/data-sources-controllers/list-data-source'; import { IListConfig } from '../../../shared/components/list/list.component.types'; -import { getMonocularChartId, helmEntityFactory, monocularChartsEntityType } from '../helm-entity-factory'; -import { GetMonocularCharts } from '../store/helm.actions'; +import { helmEntityCatalog } from '../helm-entity-catalog'; import { MonocularChart } from '../store/helm.types'; export class MonocularChartsDataSource extends ListDataSource { @@ -14,12 +13,12 @@ export class MonocularChartsDataSource extends ListDataSource { store: Store, listConfig: IListConfig ) { - const action = new GetMonocularCharts(); + const action = helmEntityCatalog.chart.actions.getMultiple(); super({ store, action, - schema: helmEntityFactory(monocularChartsEntityType), - getRowUniqueId: getMonocularChartId, + schema: action.entity[0], + getRowUniqueId: (row) => action.entity[0].getId(row), paginationKey: action.paginationKey, isLocal: true, listConfig, diff --git a/custom-src/frontend/app/custom/helm/store/helm.action-builders.ts b/custom-src/frontend/app/custom/helm/store/helm.action-builders.ts new file mode 100644 index 0000000000..53c20f4de9 --- /dev/null +++ b/custom-src/frontend/app/custom/helm/store/helm.action-builders.ts @@ -0,0 +1,23 @@ +import { OrchestratedActionBuilders } from '../../../../../store/src/entity-catalog/action-orchestrator/action-orchestrator'; +import { GetHelmVersions, GetMonocularCharts, HelmInstall } from './helm.actions'; +import { HelmInstallValues } from './helm.types'; + +export interface HelmChartActionBuilders extends OrchestratedActionBuilders { + getMultiple: () => GetMonocularCharts, + // Helm install added to chart action builder and not helm release/workload to ensure action & effect are available in this module + // (others may not have loaded) + install: (values: HelmInstallValues) => HelmInstall +} + +export const helmChartActionBuilders: HelmChartActionBuilders = { + getMultiple: () => new GetMonocularCharts(), + install: (values: HelmInstallValues) => new HelmInstall(values) +} + +export interface HelmVersionActionBuilders extends OrchestratedActionBuilders { + getMultiple: () => GetHelmVersions +} + +export const helmVersionActionBuilders: HelmVersionActionBuilders = { + getMultiple: () => new GetHelmVersions() +} \ No newline at end of file diff --git a/custom-src/frontend/app/custom/helm/store/helm.actions.ts b/custom-src/frontend/app/custom/helm/store/helm.actions.ts index ce114a1245..d0c0db844e 100644 --- a/custom-src/frontend/app/custom/helm/store/helm.actions.ts +++ b/custom-src/frontend/app/custom/helm/store/helm.actions.ts @@ -1,6 +1,4 @@ import { EntityRequestAction } from '../../../../../store/src/types/request.types'; -import { KUBERNETES_ENDPOINT_TYPE } from '../../kubernetes/kubernetes-entity-factory'; -import { helmReleaseEntityKey } from '../../kubernetes/workloads/store/workloads-entity-factory'; import { HELM_ENDPOINT_TYPE, helmEntityFactory, @@ -42,8 +40,18 @@ export class GetMonocularCharts implements MonocularPaginationAction { 'order-direction': 'desc', 'order-direction-field': 'name', }; + flattenPagination = true; } +export class HelmInstall implements EntityRequestAction { + type = HELM_INSTALL; + endpointType = HELM_ENDPOINT_TYPE; + entityType = monocularChartsEntityType; + guid: string; + constructor(public values: HelmInstallValues) { + this.guid = '' + this.values.releaseName; + } +} export class GetHelmVersions implements MonocularPaginationAction { constructor() { @@ -63,15 +71,5 @@ export class GetHelmVersions implements MonocularPaginationAction { 'order-direction': 'asc', 'order-direction-field': 'version', }; + flattenPagination = true; } - -export class HelmInstall implements EntityRequestAction { - type = HELM_INSTALL; - endpointType = KUBERNETES_ENDPOINT_TYPE; - entityType = helmReleaseEntityKey; - guid: string; - constructor(public values: HelmInstallValues) { - this.guid = '' + this.values.releaseName; - } -} - diff --git a/custom-src/frontend/app/custom/helm/store/helm.effects.ts b/custom-src/frontend/app/custom/helm/store/helm.effects.ts index e79232c5d9..5ec555ade5 100644 --- a/custom-src/frontend/app/custom/helm/store/helm.effects.ts +++ b/custom-src/frontend/app/custom/helm/store/helm.effects.ts @@ -2,24 +2,25 @@ import { HttpClient } from '@angular/common/http'; import { Injectable } from '@angular/core'; import { Actions, Effect, ofType } from '@ngrx/effects'; import { Action, Store } from '@ngrx/store'; -import { GET_ENDPOINTS_SUCCESS, GetAllEndpointsSuccess } from 'frontend/packages/store/src/actions/endpoint.actions'; -import { ClearPaginationOfType } from 'frontend/packages/store/src/actions/pagination.actions'; -import { AppState } from 'frontend/packages/store/src/app-state'; -import { entityCatalog } from 'frontend/packages/store/src/entity-catalog/entity-catalog'; -import { ApiRequestTypes } from 'frontend/packages/store/src/reducers/api-request-reducer/request-helpers'; -import { NormalizedResponse } from 'frontend/packages/store/src/types/api.types'; +import { Observable } from 'rxjs'; +import { catchError, flatMap, mergeMap } from 'rxjs/operators'; + +import { GET_ENDPOINTS_SUCCESS, GetAllEndpointsSuccess } from '../../../../../store/src/actions/endpoint.actions'; +import { ClearPaginationOfType } from '../../../../../store/src/actions/pagination.actions'; +import { AppState } from '../../../../../store/src/app-state'; +import { entityCatalog } from '../../../../../store/src/entity-catalog/entity-catalog'; +import { ApiRequestTypes } from '../../../../../store/src/reducers/api-request-reducer/request-helpers'; +import { NormalizedResponse } from '../../../../../store/src/types/api.types'; import { EntityRequestAction, StartRequestAction, WrapperRequestActionFailed, WrapperRequestActionSuccess, -} from 'frontend/packages/store/src/types/request.types'; -import { Observable } from 'rxjs'; -import { catchError, flatMap, mergeMap } from 'rxjs/operators'; - +} from '../../../../../store/src/types/request.types'; import { environment } from '../../../environments/environment'; import { isJetstreamError } from '../../../jetstream.helpers'; -import { HELM_ENDPOINT_TYPE } from '../helm-entity-factory'; +import { helmEntityCatalog } from '../helm-entity-catalog'; +import { getHelmVersionId, getMonocularChartId, HELM_ENDPOINT_TYPE } from '../helm-entity-factory'; import { GET_HELM_VERSIONS, GET_MONOCULAR_CHARTS, @@ -85,7 +86,7 @@ export class HelmEffects { const items = response.data as Array; const processedData = items.reduce((res, data) => { - const id = data.id; + const id = getMonocularChartId(data); res.entities[entityKey][id] = data; // Promote the name to the top-level object for simplicity data.name = data.attributes.name; @@ -119,7 +120,7 @@ export class HelmEffects { endpointId: endpoint, ...endpointData }; - processedData.entities[entityKey][endpoint] = version; + processedData.entities[entityKey][getHelmVersionId(version)] = version; processedData.result.push(endpoint); }); return processedData; @@ -142,7 +143,7 @@ export class HelmEffects { ]; }), catchError(error => { - const { status, message } = this.createHelmError(error); + const { status, message } = HelmEffects.createHelmError(error); const errorMessage = `Failed to install helm chart: ${message}`; return [ new WrapperRequestActionFailed(errorMessage, action, requestType, { @@ -172,7 +173,7 @@ export class HelmEffects { return this.httpClient.get(url, requestArgs).pipe( mergeMap((response: any) => [new WrapperRequestActionSuccess(mapResult(response), action)]), catchError(error => { - const { status, message } = this.createHelmError(error); + const { status, message } = HelmEffects.createHelmError(error); return [ new WrapperRequestActionFailed(message, action, 'fetch', { endpointIds, @@ -186,7 +187,7 @@ export class HelmEffects { ); } - private createHelmErrorMessage(err: any): string { + static createHelmErrorMessage(err: any): string { if (err) { if (err.error && err.error.message) { // Kube error @@ -202,7 +203,7 @@ export class HelmEffects { return 'Helm API request error'; } - private createHelmError(err: any): { status: string, message: string } { + static createHelmError(err: any): { status: string, message: string } { let unwrapped = err; if (err.error) { unwrapped = err.error; @@ -212,7 +213,7 @@ export class HelmEffects { // Wrapped error return { status: jetstreamError.error.statusCode.toString(), - message: this.createHelmErrorMessage(jetstreamError) + message: HelmEffects.createHelmErrorMessage(jetstreamError) }; } return { @@ -242,7 +243,7 @@ export class HelmEffects { this.syncing = syncing; if (remaining !== existing) { // Dispatch action to refresh charts - this.store.dispatch(new GetMonocularCharts()); + helmEntityCatalog.chart.api.getMultiple(); } if (remaining > 0) { this.scheduleSyncStatusCheck(); diff --git a/custom-src/frontend/app/custom/kubernetes/auth-forms/kubernetes-certs-auth-form/kubernetes-certs-auth-form.component.scss b/custom-src/frontend/app/custom/kubernetes/auth-forms/kubernetes-certs-auth-form/kubernetes-certs-auth-form.component.scss index 23498e9eca..5385ee9711 100644 --- a/custom-src/frontend/app/custom/kubernetes/auth-forms/kubernetes-certs-auth-form/kubernetes-certs-auth-form.component.scss +++ b/custom-src/frontend/app/custom/kubernetes/auth-forms/kubernetes-certs-auth-form/kubernetes-certs-auth-form.component.scss @@ -14,7 +14,7 @@ &__content { & > * { - padding-bottom: 10px; + margin-bottom: 10px; } textarea { max-height: 75px; diff --git a/custom-src/frontend/app/custom/kubernetes/kubernetes-entity-catalog.ts b/custom-src/frontend/app/custom/kubernetes/kubernetes-entity-catalog.ts new file mode 100644 index 0000000000..816ab0bd47 --- /dev/null +++ b/custom-src/frontend/app/custom/kubernetes/kubernetes-entity-catalog.ts @@ -0,0 +1,43 @@ +import { + StratosCatalogEndpointEntity, + StratosCatalogEntity, +} from '../../../../store/src/entity-catalog/entity-catalog-entity/entity-catalog-entity'; +import { IFavoriteMetadata } from '../../../../store/src/types/user-favorites.types'; +import { + KubeDashboardActionBuilders, + KubeDeploymentActionBuilders, + KubeNamespaceActionBuilders, + KubeNodeActionBuilders, + KubePodActionBuilders, + KubeServiceActionBuilders, + KubeStatefulSetsActionBuilders, +} from './store/action-builders/kube.action-builders'; +import { + KubernetesDeployment, + KubernetesNamespace, + KubernetesNode, + KubernetesPod, + KubernetesStatefulSet, + KubeService, +} from './store/kube.types'; + +/** + * A strongly typed collection of Kube Catalog Entities. + * This can be used to access functionality exposed by each specific type, such as get, update, delete, etc + */ +export class KubeEntityCatalog { + public endpoint: StratosCatalogEndpointEntity; + public statefulSet: StratosCatalogEntity; + public pod: StratosCatalogEntity; + public deployment: StratosCatalogEntity; + public node: StratosCatalogEntity; + public namespace: StratosCatalogEntity; + public service: StratosCatalogEntity + public dashboard: StratosCatalogEntity; +} + +/** + * A strongly typed collection of Kube Catalog Entities. + * This can be used to access functionality exposed by each specific type, such as get, update, delete, etc + */ +export const kubeEntityCatalog: KubeEntityCatalog = new KubeEntityCatalog(); diff --git a/custom-src/frontend/app/custom/kubernetes/kubernetes-entity-factory.ts b/custom-src/frontend/app/custom/kubernetes/kubernetes-entity-factory.ts index 1e0aed9df9..a30402dfaa 100644 --- a/custom-src/frontend/app/custom/kubernetes/kubernetes-entity-factory.ts +++ b/custom-src/frontend/app/custom/kubernetes/kubernetes-entity-factory.ts @@ -3,7 +3,15 @@ import { Schema, schema } from 'normalizr'; import { getAPIResourceGuid } from '../../../../cloud-foundry/src/store/selectors/api.selectors'; import { EntitySchema } from '../../../../store/src/helpers/entity-schema'; import { metricEntityType } from '../../base-entity-schemas'; -import { getKubeAPIResourceGuid } from './store/kube.selectors'; +import { + getGuidFromKubeDashboardObj, + getGuidFromKubeDeploymentObj, + getGuidFromKubeNamespaceObj, + getGuidFromKubeNodeObj, + getGuidFromKubePodObj, + getGuidFromKubeServiceObj, + getGuidFromKubeStatefulSetObj, +} from './store/kube.getIds'; import { KubernetesApp } from './store/kube.types'; export const kubernetesEntityType = 'kubernetesInfo'; @@ -13,7 +21,6 @@ export const kubernetesNamespacesEntityType = 'kubernetesNamespace'; export const kubernetesServicesEntityType = 'kubernetesService'; export const kubernetesStatefulSetsEntityType = 'kubernetesStatefulSet'; export const kubernetesDeploymentsEntityType = 'kubernetesDeployment'; -export const kubernetesAppsEntityType = 'kubernetesApp'; export const kubernetesDashboardEntityType = 'kubernetesDashboard'; export const getKubeAppId = (object: KubernetesApp) => object.name; @@ -49,52 +56,52 @@ entityCache[kubernetesEntityType] = new KubernetesEntitySchema( { idAttribute: getAPIResourceGuid } ); -entityCache[kubernetesAppsEntityType] = new KubernetesEntitySchema( - kubernetesAppsEntityType, - {}, - { idAttribute: getKubeAppId } -); - entityCache[kubernetesStatefulSetsEntityType] = new KubernetesEntitySchema( kubernetesStatefulSetsEntityType, {}, - { idAttribute: getKubeAPIResourceGuid } + { + idAttribute: getGuidFromKubeStatefulSetObj + } ); entityCache[kubernetesPodsEntityType] = new KubernetesEntitySchema( kubernetesPodsEntityType, {}, - { idAttribute: getKubeAPIResourceGuid } + { + idAttribute: getGuidFromKubePodObj + } ); entityCache[kubernetesDeploymentsEntityType] = new KubernetesEntitySchema( kubernetesDeploymentsEntityType, {}, - { idAttribute: getKubeAPIResourceGuid } + { + idAttribute: getGuidFromKubeDeploymentObj + } ); entityCache[kubernetesNodesEntityType] = new KubernetesEntitySchema( kubernetesNodesEntityType, {}, - { idAttribute: getKubeAPIResourceGuid } + { idAttribute: getGuidFromKubeNodeObj } ); entityCache[kubernetesNamespacesEntityType] = new KubernetesEntitySchema( kubernetesNamespacesEntityType, {}, - { idAttribute: getKubeAPIResourceGuid } + { idAttribute: getGuidFromKubeNamespaceObj } ); entityCache[kubernetesServicesEntityType] = new KubernetesEntitySchema( kubernetesServicesEntityType, {}, - { idAttribute: getKubeAPIResourceGuid } + { idAttribute: getGuidFromKubeServiceObj } ); entityCache[kubernetesDashboardEntityType] = new KubernetesEntitySchema( kubernetesDashboardEntityType, {}, - { idAttribute: getKubeAPIResourceGuid } + { idAttribute: getGuidFromKubeDashboardObj } ); entityCache[metricEntityType] = new KubernetesEntitySchema(metricEntityType); diff --git a/custom-src/frontend/app/custom/kubernetes/kubernetes-entity-generator.ts b/custom-src/frontend/app/custom/kubernetes/kubernetes-entity-generator.ts index 8155fd83ce..eac9f993c0 100644 --- a/custom-src/frontend/app/custom/kubernetes/kubernetes-entity-generator.ts +++ b/custom-src/frontend/app/custom/kubernetes/kubernetes-entity-generator.ts @@ -5,7 +5,10 @@ import { StratosCatalogEndpointEntity, StratosCatalogEntity, } from '../../../../store/src/entity-catalog/entity-catalog-entity/entity-catalog-entity'; -import { StratosEndpointExtensionDefinition } from '../../../../store/src/entity-catalog/entity-catalog.types'; +import { + IStratosEntityDefinition, + StratosEndpointExtensionDefinition, +} from '../../../../store/src/entity-catalog/entity-catalog.types'; import { IFavoriteMetadata } from '../../../../store/src/types/user-favorites.types'; import { metricEntityType } from '../../base-entity-schemas'; import { EndpointAuthTypeConfig, EndpointType } from '../../core/extension/extension-types'; @@ -17,9 +20,9 @@ import { KubernetesConfigAuthFormComponent, } from './auth-forms/kubernetes-config-auth-form/kubernetes-config-auth-form.component'; import { KubernetesGKEAuthFormComponent } from './auth-forms/kubernetes-gke-auth-form/kubernetes-gke-auth-form.component'; +import { kubeEntityCatalog } from './kubernetes-entity-catalog'; import { KUBERNETES_ENDPOINT_TYPE, - kubernetesAppsEntityType, kubernetesDashboardEntityType, kubernetesDeploymentsEntityType, kubernetesEntityFactory, @@ -30,7 +33,22 @@ import { kubernetesStatefulSetsEntityType, } from './kubernetes-entity-factory'; import { - KubernetesApp, + KubeDashboardActionBuilders, + kubeDashboardActionBuilders, + KubeDeploymentActionBuilders, + kubeDeploymentActionBuilders, + KubeNamespaceActionBuilders, + kubeNamespaceActionBuilders, + KubeNodeActionBuilders, + kubeNodeActionBuilders, + KubePodActionBuilders, + kubePodActionBuilders, + KubeServiceActionBuilders, + kubeServiceActionBuilders, + KubeStatefulSetsActionBuilders, + kubeStatefulSetsActionBuilders, +} from './store/action-builders/kube.action-builders'; +import { KubernetesDeployment, KubernetesNamespace, KubernetesNode, @@ -139,7 +157,6 @@ export function generateKubernetesEntities(): StratosBaseCatalogEntity[] { }; return [ generateEndpointEntity(endpointDefinition), - generateAppEntity(endpointDefinition), generateStatefulSetsEntity(endpointDefinition), generatePodsEntity(endpointDefinition), generateDeploymentsEntity(endpointDefinition), @@ -153,86 +170,99 @@ export function generateKubernetesEntities(): StratosBaseCatalogEntity[] { } function generateEndpointEntity(endpointDefinition: StratosEndpointExtensionDefinition) { - return new StratosCatalogEndpointEntity( + kubeEntityCatalog.endpoint = new StratosCatalogEndpointEntity( endpointDefinition, metadata => `/kubernetes/${metadata.guid}` ); -} - -function generateAppEntity(endpointDefinition: StratosEndpointExtensionDefinition) { - const definition = { - type: kubernetesAppsEntityType, - schema: kubernetesEntityFactory(kubernetesAppsEntityType), - endpoint: endpointDefinition - }; - return new StratosCatalogEntity(definition); + return kubeEntityCatalog.endpoint; } function generateStatefulSetsEntity(endpointDefinition: StratosEndpointExtensionDefinition) { - const definition = { + const definition: IStratosEntityDefinition = { type: kubernetesStatefulSetsEntityType, schema: kubernetesEntityFactory(kubernetesStatefulSetsEntityType), endpoint: endpointDefinition }; - return new StratosCatalogEntity(definition); + kubeEntityCatalog.statefulSet = new StratosCatalogEntity(definition, { + actionBuilders: kubeStatefulSetsActionBuilders + }); + return kubeEntityCatalog.statefulSet; } function generatePodsEntity(endpointDefinition: StratosEndpointExtensionDefinition) { - const definition = { + const definition: IStratosEntityDefinition = { type: kubernetesPodsEntityType, schema: kubernetesEntityFactory(kubernetesPodsEntityType), endpoint: endpointDefinition }; - return new StratosCatalogEntity(definition); + kubeEntityCatalog.pod = new StratosCatalogEntity(definition, { + actionBuilders: kubePodActionBuilders + }); + return kubeEntityCatalog.pod; } function generateDeploymentsEntity(endpointDefinition: StratosEndpointExtensionDefinition) { - const definition = { + const definition: IStratosEntityDefinition = { type: kubernetesDeploymentsEntityType, schema: kubernetesEntityFactory(kubernetesDeploymentsEntityType), endpoint: endpointDefinition }; - return new StratosCatalogEntity(definition); + kubeEntityCatalog.deployment = new StratosCatalogEntity(definition, { + actionBuilders: kubeDeploymentActionBuilders + }); + return kubeEntityCatalog.deployment; } function generateNodesEntity(endpointDefinition: StratosEndpointExtensionDefinition) { - const definition = { + const definition: IStratosEntityDefinition = { type: kubernetesNodesEntityType, schema: kubernetesEntityFactory(kubernetesNodesEntityType), endpoint: endpointDefinition }; - return new StratosCatalogEntity(definition); + kubeEntityCatalog.node = new StratosCatalogEntity(definition, { + actionBuilders: kubeNodeActionBuilders + }); + return kubeEntityCatalog.node; } function generateNamespacesEntity(endpointDefinition: StratosEndpointExtensionDefinition) { - const definition = { + const definition: IStratosEntityDefinition = { type: kubernetesNamespacesEntityType, schema: kubernetesEntityFactory(kubernetesNamespacesEntityType), endpoint: endpointDefinition }; - return new StratosCatalogEntity(definition); + kubeEntityCatalog.namespace = new StratosCatalogEntity(definition, { + actionBuilders: kubeNamespaceActionBuilders + }); + return kubeEntityCatalog.namespace; } function generateServicesEntity(endpointDefinition: StratosEndpointExtensionDefinition) { - const definition = { + const definition: IStratosEntityDefinition = { type: kubernetesServicesEntityType, schema: kubernetesEntityFactory(kubernetesServicesEntityType), endpoint: endpointDefinition }; - return new StratosCatalogEntity(definition); + kubeEntityCatalog.service = new StratosCatalogEntity(definition, { + actionBuilders: kubeServiceActionBuilders + }); + return kubeEntityCatalog.service; } function generateDashboardEntity(endpointDefinition: StratosEndpointExtensionDefinition) { - const definition = { + const definition: IStratosEntityDefinition = { type: kubernetesDashboardEntityType, schema: kubernetesEntityFactory(kubernetesDashboardEntityType), endpoint: endpointDefinition }; - return new StratosCatalogEntity(definition); + kubeEntityCatalog.dashboard = new StratosCatalogEntity(definition, { + actionBuilders: kubeDashboardActionBuilders + }); + return kubeEntityCatalog.dashboard; } function generateMetricEntity(endpointDefinition: StratosEndpointExtensionDefinition) { - const definition = { + const definition: IStratosEntityDefinition = { type: metricEntityType, schema: kubernetesEntityFactory(metricEntityType), label: 'Kubernetes Metric', diff --git a/custom-src/frontend/app/custom/kubernetes/kubernetes.setup.module.ts b/custom-src/frontend/app/custom/kubernetes/kubernetes.setup.module.ts index 305457f572..45f33e0292 100644 --- a/custom-src/frontend/app/custom/kubernetes/kubernetes.setup.module.ts +++ b/custom-src/frontend/app/custom/kubernetes/kubernetes.setup.module.ts @@ -1,8 +1,6 @@ import { CommonModule } from '@angular/common'; import { NgModule, Optional, SkipSelf } from '@angular/core'; -import { Store } from '@ngrx/store'; -import { AppState } from '../../../../store/src/app-state'; import { EntityCatalogModule } from '../../../../store/src/entity-catalog.module'; import { EndpointHealthCheck } from '../../../endpoints-health-checks'; import { CoreModule } from '../../core/core.module'; @@ -16,12 +14,12 @@ import { KubernetesConfigAuthFormComponent, } from './auth-forms/kubernetes-config-auth-form/kubernetes-config-auth-form.component'; import { KubernetesGKEAuthFormComponent } from './auth-forms/kubernetes-gke-auth-form/kubernetes-gke-auth-form.component'; +import { kubeEntityCatalog } from './kubernetes-entity-catalog'; import { KUBERNETES_ENDPOINT_TYPE } from './kubernetes-entity-factory'; import { generateKubernetesEntities } from './kubernetes-entity-generator'; import { BaseKubeGuid } from './kubernetes-page.types'; import { KubernetesStoreModule } from './kubernetes.store.module'; import { KubernetesEndpointService } from './services/kubernetes-endpoint.service'; -import { KubeHealthCheck } from './store/kubernetes.actions'; @NgModule({ @@ -52,14 +50,13 @@ import { KubeHealthCheck } from './store/kubernetes.actions'; export class KubernetesSetupModule { constructor( endpointService: EndpointsService, - store: Store, @Optional() @SkipSelf() parentModule: KubernetesSetupModule ) { if (parentModule) { // Module has already been imported } else { endpointService.registerHealthCheck( - new EndpointHealthCheck(KUBERNETES_ENDPOINT_TYPE, (endpoint) => store.dispatch(new KubeHealthCheck(endpoint.guid))) + new EndpointHealthCheck(KUBERNETES_ENDPOINT_TYPE, (endpoint) => kubeEntityCatalog.node.api.healthCheck(endpoint.guid)) ); } } diff --git a/custom-src/frontend/app/custom/kubernetes/kubernetes.testing.module.ts b/custom-src/frontend/app/custom/kubernetes/kubernetes.testing.module.ts index c87f6368fc..9185564ccb 100644 --- a/custom-src/frontend/app/custom/kubernetes/kubernetes.testing.module.ts +++ b/custom-src/frontend/app/custom/kubernetes/kubernetes.testing.module.ts @@ -6,6 +6,7 @@ import { RouterTestingModule } from '@angular/router/testing'; import { CATALOGUE_ENTITIES, EntityCatalogFeatureModule } from '../../../../store/src/entity-catalog.module'; import { entityCatalog, TestEntityCatalog } from '../../../../store/src/entity-catalog/entity-catalog'; import { createBasicStoreModule } from '../../../../store/testing/public-api'; +import { AppTestModule } from '../../../test-framework/core-test.helper'; import { generateStratosEntities } from '../../base-entity-types'; import { CoreModule } from '../../core/core.module'; import { SharedModule } from '../../shared/shared.module'; @@ -34,6 +35,7 @@ import { HelmReleaseHelperService } from './workloads/release/tabs/helm-release- export class KubernetesTestingModule { } export const KubernetesBaseTestModules = [ + AppTestModule, KubernetesTestingModule, RouterTestingModule, CoreModule, diff --git a/custom-src/frontend/app/custom/kubernetes/list-types/kubernetes-namespace-pods/kubernetes-namespace-pods-data-source.ts b/custom-src/frontend/app/custom/kubernetes/list-types/kubernetes-namespace-pods/kubernetes-namespace-pods-data-source.ts index aef7b05503..b5c6dbc2aa 100644 --- a/custom-src/frontend/app/custom/kubernetes/list-types/kubernetes-namespace-pods/kubernetes-namespace-pods-data-source.ts +++ b/custom-src/frontend/app/custom/kubernetes/list-types/kubernetes-namespace-pods/kubernetes-namespace-pods-data-source.ts @@ -3,11 +3,11 @@ import { Store } from '@ngrx/store'; import { AppState } from '../../../../../../store/src/app-state'; import { ListDataSource } from '../../../../shared/components/list/data-sources-controllers/list-data-source'; import { IListConfig } from '../../../../shared/components/list/list.component.types'; +import { kubeEntityCatalog } from '../../kubernetes-entity-catalog'; import { kubernetesEntityFactory, kubernetesPodsEntityType } from '../../kubernetes-entity-factory'; import { BaseKubeGuid } from '../../kubernetes-page.types'; import { KubernetesNamespaceService } from '../../services/kubernetes-namespace.service'; import { KubernetesPod } from '../../store/kube.types'; -import { GetKubernetesPodsInNamespace } from '../../store/kubernetes.actions'; export class KubernetesNamespacePodsDataSource extends ListDataSource { @@ -17,7 +17,7 @@ export class KubernetesNamespacePodsDataSource extends ListDataSource, kubeNamespaceService: KubernetesNamespaceService, ) { - const action = new GetKubernetesPodsInNamespace(kubeGuid.guid, kubeNamespaceService.namespaceName); + const action = kubeEntityCatalog.pod.actions.getInNamespace(kubeGuid.guid, kubeNamespaceService.namespaceName); super({ store, action, diff --git a/custom-src/frontend/app/custom/kubernetes/list-types/kubernetes-namespace-services/kubernetes-namespace-services-data-source.ts b/custom-src/frontend/app/custom/kubernetes/list-types/kubernetes-namespace-services/kubernetes-namespace-services-data-source.ts index 063318f97f..beb0626c7e 100644 --- a/custom-src/frontend/app/custom/kubernetes/list-types/kubernetes-namespace-services/kubernetes-namespace-services-data-source.ts +++ b/custom-src/frontend/app/custom/kubernetes/list-types/kubernetes-namespace-services/kubernetes-namespace-services-data-source.ts @@ -2,9 +2,9 @@ import { Store } from '@ngrx/store'; import { AppState } from '../../../../../../store/src/app-state'; import { IListConfig } from '../../../../shared/components/list/list.component.types'; +import { kubeEntityCatalog } from '../../kubernetes-entity-catalog'; import { BaseKubeGuid } from '../../kubernetes-page.types'; import { KubeService } from '../../store/kube.types'; -import { GetKubernetesServicesInNamespace } from '../../store/kubernetes.actions'; import { BaseKubernetesServicesDataSource } from '../kubernetes-services/kubernetes-services-data-source'; @@ -16,10 +16,9 @@ export class KubernetesNamespaceServicesDataSource extends BaseKubernetesService listConfig: IListConfig, namespace: string, ) { - const action = new GetKubernetesServicesInNamespace(kubeGuid.guid, namespace); super( store, - action, + kubeEntityCatalog.service.actions.getInNamespace(namespace, kubeGuid.guid), listConfig ); } diff --git a/custom-src/frontend/app/custom/kubernetes/list-types/kubernetes-namespaces/kubernetes-namespaces-data-source.ts b/custom-src/frontend/app/custom/kubernetes/list-types/kubernetes-namespaces/kubernetes-namespaces-data-source.ts index d1fd2cc6e3..2c3a375252 100644 --- a/custom-src/frontend/app/custom/kubernetes/list-types/kubernetes-namespaces/kubernetes-namespaces-data-source.ts +++ b/custom-src/frontend/app/custom/kubernetes/list-types/kubernetes-namespaces/kubernetes-namespaces-data-source.ts @@ -4,11 +4,10 @@ import { getPaginationKey } from '../../../../../../store/src/actions/pagination import { AppState } from '../../../../../../store/src/app-state'; import { ListDataSource } from '../../../../shared/components/list/data-sources-controllers/list-data-source'; import { IListConfig } from '../../../../shared/components/list/list.component.types'; -import { kubernetesEntityFactory, kubernetesNamespacesEntityType } from '../../kubernetes-entity-factory'; +import { kubeEntityCatalog } from '../../kubernetes-entity-catalog'; +import { kubernetesNamespacesEntityType } from '../../kubernetes-entity-factory'; import { BaseKubeGuid } from '../../kubernetes-page.types'; -import { getKubeAPIResourceGuid } from '../../store/kube.selectors'; import { KubernetesNamespace } from '../../store/kube.types'; -import { GetKubernetesNamespaces } from '../../store/kubernetes.actions'; export class KubernetesNamespacesDataSource extends ListDataSource { @@ -18,11 +17,12 @@ export class KubernetesNamespacesDataSource extends ListDataSource ) { + const action = kubeEntityCatalog.namespace.actions.getMultiple(kubeGuid.guid); super({ store, - action: new GetKubernetesNamespaces(kubeGuid.guid), - schema: kubernetesEntityFactory(kubernetesNamespacesEntityType), - getRowUniqueId: getKubeAPIResourceGuid, + action, + schema: action.entity[0], + getRowUniqueId: (row) => action.entity[0].getId(row), paginationKey: getPaginationKey(kubernetesNamespacesEntityType, kubeGuid.guid), isLocal: true, listConfig, diff --git a/custom-src/frontend/app/custom/kubernetes/list-types/kubernetes-node-pods/kubernetes-node-pods-data-source.ts b/custom-src/frontend/app/custom/kubernetes/list-types/kubernetes-node-pods/kubernetes-node-pods-data-source.ts index a2c59454dd..f89ae7ae9f 100644 --- a/custom-src/frontend/app/custom/kubernetes/list-types/kubernetes-node-pods/kubernetes-node-pods-data-source.ts +++ b/custom-src/frontend/app/custom/kubernetes/list-types/kubernetes-node-pods/kubernetes-node-pods-data-source.ts @@ -3,12 +3,10 @@ import { Store } from '@ngrx/store'; import { AppState } from '../../../../../../store/src/app-state'; import { ListDataSource } from '../../../../shared/components/list/data-sources-controllers/list-data-source'; import { IListConfig } from '../../../../shared/components/list/list.component.types'; -import { kubernetesEntityFactory, kubernetesPodsEntityType } from '../../kubernetes-entity-factory'; +import { kubeEntityCatalog } from '../../kubernetes-entity-catalog'; import { BaseKubeGuid } from '../../kubernetes-page.types'; import { KubernetesNodeService } from '../../services/kubernetes-node.service'; -import { getKubeAPIResourceGuid } from '../../store/kube.selectors'; import { KubernetesPod } from '../../store/kube.types'; -import { GetKubernetesPodsOnNode } from '../../store/kubernetes.actions'; export class KubernetesNodePodsDataSource extends ListDataSource { @@ -18,12 +16,12 @@ export class KubernetesNodePodsDataSource extends ListDataSource listConfig: IListConfig, kubeNodeService: KubernetesNodeService, ) { - const action = new GetKubernetesPodsOnNode(kubeGuid.guid, kubeNodeService.nodeName); + const action = kubeEntityCatalog.pod.actions.getOnNode(kubeGuid.guid, kubeNodeService.nodeName); super({ store, action, - schema: kubernetesEntityFactory(kubernetesPodsEntityType), - getRowUniqueId: getKubeAPIResourceGuid, + schema: action.entity[0], + getRowUniqueId: (row) => action.entity[0].getId(row), paginationKey: action.paginationKey, isLocal: true, listConfig, diff --git a/custom-src/frontend/app/custom/kubernetes/list-types/kubernetes-nodes/kubernetes-nodes-data-source.ts b/custom-src/frontend/app/custom/kubernetes/list-types/kubernetes-nodes/kubernetes-nodes-data-source.ts index 797cd9a5fd..30678de266 100644 --- a/custom-src/frontend/app/custom/kubernetes/list-types/kubernetes-nodes/kubernetes-nodes-data-source.ts +++ b/custom-src/frontend/app/custom/kubernetes/list-types/kubernetes-nodes/kubernetes-nodes-data-source.ts @@ -8,11 +8,10 @@ import { ListDataSource, } from '../../../../shared/components/list/data-sources-controllers/list-data-source'; import { IListConfig } from '../../../../shared/components/list/list.component.types'; -import { kubernetesEntityFactory, kubernetesNodesEntityType } from '../../kubernetes-entity-factory'; +import { kubeEntityCatalog } from '../../kubernetes-entity-catalog'; +import { kubernetesNodesEntityType } from '../../kubernetes-entity-factory'; import { BaseKubeGuid } from '../../kubernetes-page.types'; -import { getKubeAPIResourceGuid } from '../../store/kube.selectors'; import { KubernetesNode } from '../../store/kube.types'; -import { GetKubernetesNodes } from '../../store/kubernetes.actions'; export class KubernetesNodesDataSource extends ListDataSource { @@ -22,11 +21,12 @@ export class KubernetesNodesDataSource extends ListDataSource { listConfig: IListConfig, transformEntities: (DataFunction | DataFunctionDefinition)[] ) { + const action = kubeEntityCatalog.node.actions.getMultiple(kubeGuid.guid); super({ store, - action: new GetKubernetesNodes(kubeGuid.guid), - schema: kubernetesEntityFactory(kubernetesNodesEntityType), - getRowUniqueId: getKubeAPIResourceGuid, + action, + schema: action.entity[0], + getRowUniqueId: (row) => action.entity[0].getId(row), paginationKey: getPaginationKey(kubernetesNodesEntityType, kubeGuid.guid), isLocal: true, listConfig, diff --git a/custom-src/frontend/app/custom/kubernetes/list-types/kubernetes-pods/kubernetes-pod-containers/kubernetes-pod-containers.component.ts b/custom-src/frontend/app/custom/kubernetes/list-types/kubernetes-pods/kubernetes-pod-containers/kubernetes-pod-containers.component.ts index f83718f337..d838567a71 100644 --- a/custom-src/frontend/app/custom/kubernetes/list-types/kubernetes-pods/kubernetes-pod-containers/kubernetes-pod-containers.component.ts +++ b/custom-src/frontend/app/custom/kubernetes/list-types/kubernetes-pods/kubernetes-pod-containers/kubernetes-pod-containers.component.ts @@ -1,13 +1,9 @@ import { TitleCasePipe } from '@angular/common'; import { Component, Input } from '@angular/core'; -import { Store } from '@ngrx/store'; import * as moment from 'moment'; import { of } from 'rxjs'; import { filter, map } from 'rxjs/operators'; -import { AppState } from '../../../../../../../store/src/app-state'; -import { entityCatalog } from '../../../../../../../store/src/entity-catalog/entity-catalog'; -import { selectEntity } from '../../../../../../../store/src/selectors/api.selectors'; import { BooleanIndicatorType } from '../../../../../shared/components/boolean-indicator/boolean-indicator.component'; import { ITableListDataSource } from '../../../../../shared/components/list/data-sources-controllers/list-data-source-types'; import { @@ -20,7 +16,7 @@ import { } from '../../../../../shared/components/list/list-table/table-cell-icon/table-cell-icon.component'; import { ITableColumn } from '../../../../../shared/components/list/list-table/table.types'; import { CardCell } from '../../../../../shared/components/list/list.types'; -import { KUBERNETES_ENDPOINT_TYPE, kubernetesPodsEntityType } from '../../../kubernetes-entity-factory'; +import { kubeEntityCatalog } from '../../../kubernetes-entity-catalog'; import { Container, ContainerState, ContainerStatus, InitContainer, KubernetesPod } from '../../../store/kube.types'; export interface ContainerForTable { @@ -39,16 +35,15 @@ export interface ContainerForTable { }) export class KubernetesPodContainersComponent extends CardCell { - private entityConfig = entityCatalog.getEntity(KUBERNETES_ENDPOINT_TYPE, kubernetesPodsEntityType); - @Input() set row(row: KubernetesPod) { if (!row || !!this.containerDataSource) { return; } + const id = kubeEntityCatalog.pod.getSchema().getId(row); this.containerDataSource = { isTableLoading$: of(false), - connect: () => this.store.select(selectEntity(this.entityConfig.entityKey, row.metadata.uid)).pipe( + connect: () => kubeEntityCatalog.pod.store.getEntityMonitor(id).entity$.pipe( filter(pod => !!pod), map(pod => this.map(pod)), ), @@ -58,7 +53,6 @@ export class KubernetesPodContainersComponent extends CardCell { } constructor( - private store: Store, private titleCase: TitleCasePipe, ) { super(); diff --git a/custom-src/frontend/app/custom/kubernetes/list-types/kubernetes-pods/kubernetes-pods-data-source.ts b/custom-src/frontend/app/custom/kubernetes/list-types/kubernetes-pods/kubernetes-pods-data-source.ts index cd608a2569..57d56cf38a 100644 --- a/custom-src/frontend/app/custom/kubernetes/list-types/kubernetes-pods/kubernetes-pods-data-source.ts +++ b/custom-src/frontend/app/custom/kubernetes/list-types/kubernetes-pods/kubernetes-pods-data-source.ts @@ -3,11 +3,9 @@ import { Store } from '@ngrx/store'; import { AppState } from '../../../../../../store/src/app-state'; import { ListDataSource } from '../../../../shared/components/list/data-sources-controllers/list-data-source'; import { IListConfig } from '../../../../shared/components/list/list.component.types'; -import { kubernetesEntityFactory, kubernetesPodsEntityType } from '../../kubernetes-entity-factory'; +import { kubeEntityCatalog } from '../../kubernetes-entity-catalog'; import { BaseKubeGuid } from '../../kubernetes-page.types'; -import { getKubeAPIResourceGuid } from '../../store/kube.selectors'; import { KubernetesPod } from '../../store/kube.types'; -import { GetKubernetesPods } from '../../store/kubernetes.actions'; export class KubernetesPodsDataSource extends ListDataSource { @@ -16,12 +14,12 @@ export class KubernetesPodsDataSource extends ListDataSource { kubeGuid: BaseKubeGuid, listConfig: IListConfig ) { - const action = new GetKubernetesPods(kubeGuid.guid); + const action = kubeEntityCatalog.pod.actions.getMultiple(kubeGuid.guid); super({ store, action, - schema: kubernetesEntityFactory(kubernetesPodsEntityType), - getRowUniqueId: getKubeAPIResourceGuid, + schema: action.entity[0], + getRowUniqueId: (row) => action.entity[0].getId(row), paginationKey: action.paginationKey, isLocal: true, listConfig, diff --git a/custom-src/frontend/app/custom/kubernetes/list-types/kubernetes-services/kubernetes-services-data-source.ts b/custom-src/frontend/app/custom/kubernetes/list-types/kubernetes-services/kubernetes-services-data-source.ts index 6aed4a43f6..6b02912c88 100644 --- a/custom-src/frontend/app/custom/kubernetes/list-types/kubernetes-services/kubernetes-services-data-source.ts +++ b/custom-src/frontend/app/custom/kubernetes/list-types/kubernetes-services/kubernetes-services-data-source.ts @@ -5,8 +5,6 @@ import { AppState } from '../../../../../../store/src/app-state'; import { PaginatedAction } from '../../../../../../store/src/types/pagination.types'; import { ListDataSource } from '../../../../shared/components/list/data-sources-controllers/list-data-source'; import { IListConfig } from '../../../../shared/components/list/list.component.types'; -import { kubernetesEntityFactory, kubernetesServicesEntityType } from '../../kubernetes-entity-factory'; -import { getKubeAPIResourceGuid } from '../../store/kube.selectors'; import { KubeService } from '../../store/kube.types'; export class BaseKubernetesServicesDataSource extends ListDataSource { @@ -20,8 +18,8 @@ export class BaseKubernetesServicesDataSource extends ListDataSource action.entity[0].getId(row), paginationKey: action.paginationKey, transformEntity, isLocal: true, diff --git a/custom-src/frontend/app/custom/kubernetes/pod-metrics/pod-metrics.component.ts b/custom-src/frontend/app/custom/kubernetes/pod-metrics/pod-metrics.component.ts index 8f144d0768..0da0a94369 100644 --- a/custom-src/frontend/app/custom/kubernetes/pod-metrics/pod-metrics.component.ts +++ b/custom-src/frontend/app/custom/kubernetes/pod-metrics/pod-metrics.component.ts @@ -1,12 +1,8 @@ import { Component } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; -import { Store } from '@ngrx/store'; -import * as moment from 'moment'; import { Observable } from 'rxjs'; import { map } from 'rxjs/operators'; -import { AppState } from '../../../../../store/src/app-state'; -import { EntityServiceFactory } from '../../../../../store/src/entity-service-factory.service'; import { EntityInfo } from '../../../../../store/src/types/api.types'; import { ChartSeries, IMetricMatrixResult } from '../../../../../store/src/types/base-metric.types'; import { IMetricApplication } from '../../../../../store/src/types/metric.types'; @@ -18,12 +14,13 @@ import { getMetricsChartConfigBuilder, } from '../../../shared/components/metrics-chart/metrics.component.helpers'; import { IHeaderBreadcrumb } from '../../../shared/components/page-header/page-header.types'; +import { kubeEntityCatalog } from '../kubernetes-entity-catalog'; +import { formatAxisCPUTime, formatCPUTime } from '../kubernetes-metrics.helpers'; import { BaseKubeGuid } from '../kubernetes-page.types'; import { KubernetesEndpointService } from '../services/kubernetes-endpoint.service'; import { KubernetesService } from '../services/kubernetes.service'; import { KubernetesPod } from '../store/kube.types'; -import { FetchKubernetesMetricsAction, GetKubernetesPod } from '../store/kubernetes.actions'; -import { formatCPUTime, formatAxisCPUTime } from '../kubernetes-metrics.helpers'; +import { FetchKubernetesMetricsAction } from '../store/kubernetes.actions'; @Component({ selector: 'app-pod-metrics', @@ -58,8 +55,6 @@ export class PodMetricsComponent { constructor( public activatedRoute: ActivatedRoute, - public store: Store, - public entityServiceFactory: EntityServiceFactory, public kubeEndpointService: KubernetesEndpointService ) { this.podName = activatedRoute.snapshot.params.podName; @@ -166,9 +161,8 @@ export class PodMetricsComponent { }]; }) ); - this.podEntity$ = this.entityServiceFactory.create( - this.podName, - new GetKubernetesPod(this.podName, this.namespaceName, this.kubeEndpointService.kubeGuid), - ).entityObs$; + this.podEntity$ = kubeEntityCatalog.pod.store.getEntityService(this.podName, this.kubeEndpointService.kubeGuid, { + namespace: this.namespaceName + }).entityObs$; } } diff --git a/custom-src/frontend/app/custom/kubernetes/services/kubernetes-endpoint.service.ts b/custom-src/frontend/app/custom/kubernetes/services/kubernetes-endpoint.service.ts index 612e762654..7bafc4d2ca 100644 --- a/custom-src/frontend/app/custom/kubernetes/services/kubernetes-endpoint.service.ts +++ b/custom-src/frontend/app/custom/kubernetes/services/kubernetes-endpoint.service.ts @@ -7,17 +7,10 @@ import { GetAllEndpoints } from '../../../../../store/src/actions/endpoint.actio import { AppState } from '../../../../../store/src/app-state'; import { EntityService } from '../../../../../store/src/entity-service'; import { EntityServiceFactory } from '../../../../../store/src/entity-service-factory.service'; -import { PaginationMonitorFactory } from '../../../../../store/src/monitors/pagination-monitor.factory'; -import { getPaginationObservables } from '../../../../../store/src/reducers/pagination-reducer/pagination-reducer.helper'; +import { PaginationObservables } from '../../../../../store/src/reducers/pagination-reducer/pagination-reducer.types'; import { EntityInfo } from '../../../../../store/src/types/api.types'; import { EndpointModel, EndpointUser } from '../../../../../store/src/types/endpoint.types'; -import { - kubernetesDeploymentsEntityType, - kubernetesNodesEntityType, - kubernetesPodsEntityType, - kubernetesServicesEntityType, - kubernetesStatefulSetsEntityType, -} from '../kubernetes-entity-factory'; +import { kubeEntityCatalog } from '../kubernetes-entity-catalog'; import { BaseKubeGuid } from '../kubernetes-page.types'; import { KubernetesDeployment, @@ -26,15 +19,6 @@ import { KubernetesStatefulSet, KubeService, } from '../store/kube.types'; -import { - GeKubernetesDeployments, - GetKubernetesDashboard, - GetKubernetesNodes, - GetKubernetesPods, - GetKubernetesServices, - GetKubernetesStatefulSets, - KubePaginationAction, -} from '../store/kubernetes.actions'; import { KubeDashboardStatus } from '../store/kubernetes.effects'; @Injectable() @@ -61,7 +45,6 @@ export class KubernetesEndpointService { public baseKube: BaseKubeGuid, private store: Store, private entityServiceFactory: EntityServiceFactory, - private paginationMonitorFactory: PaginationMonitorFactory ) { const kubeGuid = baseKube.guid; @@ -160,40 +143,22 @@ export class KubernetesEndpointService { this.currentUser$ = this.endpoint$.pipe(map(e => e.entity.user), shareReplay(1)); - this.deployments$ = this.getObservable( - new GeKubernetesDeployments(this.kubeGuid), - kubernetesDeploymentsEntityType - ); + this.deployments$ = this.getObservable(kubeEntityCatalog.deployment.store.getPaginationService(this.kubeGuid)); - this.pods$ = this.getObservable( - new GetKubernetesPods(this.kubeGuid), - kubernetesPodsEntityType - ); + this.pods$ = this.getObservable(kubeEntityCatalog.pod.store.getPaginationService(this.kubeGuid)); - this.nodes$ = this.getObservable( - new GetKubernetesNodes(this.kubeGuid), - kubernetesNodesEntityType - ); + this.nodes$ = this.getObservable(kubeEntityCatalog.node.store.getPaginationService(this.kubeGuid)) - this.statefulSets$ = this.getObservable( - new GetKubernetesStatefulSets(this.kubeGuid), - kubernetesStatefulSetsEntityType - ); + this.statefulSets$ = this.getObservable(kubeEntityCatalog.statefulSet.store.getPaginationService(this.kubeGuid)); - this.services$ = this.getObservable( - new GetKubernetesServices(this.kubeGuid), - kubernetesServicesEntityType - ); + this.services$ = this.getObservable(kubeEntityCatalog.service.store.getPaginationService(this.kubeGuid)); this.kubeDashboardEnabled$ = this.store.select('auth').pipe( filter(auth => !!auth.sessionData['plugin-config']), map(auth => auth.sessionData['plugin-config'].kubeDashboardEnabled === 'true') ); - const kubeDashboardStatus$ = this.entityServiceFactory.create( - this.kubeGuid, - new GetKubernetesDashboard(this.kubeGuid), - ).waitForEntity$.pipe( + const kubeDashboardStatus$ = kubeEntityCatalog.dashboard.store.getEntityService(this.kubeGuid).waitForEntity$.pipe( map(status => status.entity), filter(status => !!status) ); @@ -223,14 +188,11 @@ export class KubernetesEndpointService { } public refreshKubernetesDashboardStatus() { - this.store.dispatch(new GetKubernetesDashboard(this.kubeGuid)); + kubeEntityCatalog.dashboard.api.get(this.kubeGuid); } - private getObservable(paginationAction: KubePaginationAction, schemaKey: string): Observable { - return getPaginationObservables({ - store: this.store, - action: paginationAction, - paginationMonitor: this.paginationMonitorFactory.create(paginationAction.paginationKey, paginationAction, true) - }, true).entities$.pipe(filter(p => !!p), first()); + private getObservable(obs: PaginationObservables): Observable { + return obs.entities$.pipe(filter(p => !!p), first()); } + } diff --git a/custom-src/frontend/app/custom/kubernetes/services/kubernetes-namespace.service.ts b/custom-src/frontend/app/custom/kubernetes/services/kubernetes-namespace.service.ts index 0d58870122..c4686cf28b 100644 --- a/custom-src/frontend/app/custom/kubernetes/services/kubernetes-namespace.service.ts +++ b/custom-src/frontend/app/custom/kubernetes/services/kubernetes-namespace.service.ts @@ -1,15 +1,11 @@ import { Injectable } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; -import { Store } from '@ngrx/store'; import { Observable } from 'rxjs'; import { filter, first, map, publishReplay } from 'rxjs/operators'; -import { AppState } from '../../../../../store/src/app-state'; -import { EntityServiceFactory } from '../../../../../store/src/entity-service-factory.service'; -import { PaginationMonitorFactory } from '../../../../../store/src/monitors/pagination-monitor.factory'; import { getIdFromRoute } from '../../../core/utils.service'; +import { kubeEntityCatalog } from '../kubernetes-entity-catalog'; import { KubernetesNamespace } from '../store/kube.types'; -import { GetKubernetesNamespace } from '../store/kubernetes.actions'; import { KubernetesEndpointService } from './kubernetes-endpoint.service'; @Injectable() @@ -21,18 +17,12 @@ export class KubernetesNamespaceService { constructor( public kubeEndpointService: KubernetesEndpointService, public activatedRoute: ActivatedRoute, - public store: Store, - public paginationMonitorFactory: PaginationMonitorFactory, - public entityServiceFactory: EntityServiceFactory, ) { this.namespaceName = getIdFromRoute(activatedRoute, 'namespaceName'); this.kubeGuid = kubeEndpointService.kubeGuid; - const namespaceEntity = this.entityServiceFactory.create( - this.namespaceName, - new GetKubernetesNamespace(this.namespaceName, this.kubeGuid), - ); + const namespaceEntity = kubeEntityCatalog.namespace.store.getEntityService(this.namespaceName, this.kubeGuid); this.namespace$ = namespaceEntity.entityObs$.pipe( filter(p => !!p), diff --git a/custom-src/frontend/app/custom/kubernetes/services/kubernetes-node.service.ts b/custom-src/frontend/app/custom/kubernetes/services/kubernetes-node.service.ts index 74cc1f75d9..096eb86efa 100644 --- a/custom-src/frontend/app/custom/kubernetes/services/kubernetes-node.service.ts +++ b/custom-src/frontend/app/custom/kubernetes/services/kubernetes-node.service.ts @@ -6,14 +6,13 @@ import { filter, first, map, shareReplay } from 'rxjs/operators'; import { MetricQueryConfig, MetricsAction } from '../../../../../store/src/actions/metrics.actions'; import { AppState } from '../../../../../store/src/app-state'; -import { EntityServiceFactory } from '../../../../../store/src/entity-service-factory.service'; import { EntityMonitorFactory } from '../../../../../store/src/monitors/entity-monitor.factory.service'; -import { PaginationMonitorFactory } from '../../../../../store/src/monitors/pagination-monitor.factory'; import { EntityInfo } from '../../../../../store/src/types/api.types'; import { getIdFromRoute } from '../../../core/utils.service'; import { MetricQueryType } from '../../../shared/services/metrics-range-selector.types'; +import { kubeEntityCatalog } from '../kubernetes-entity-catalog'; import { KubernetesNode, MetricStatistic } from '../store/kube.types'; -import { FetchKubernetesMetricsAction, GetKubernetesNode } from '../store/kubernetes.actions'; +import { FetchKubernetesMetricsAction } from '../store/kubernetes.actions'; import { KubernetesEndpointService } from './kubernetes-endpoint.service'; @@ -33,17 +32,12 @@ export class KubernetesNodeService { public kubeEndpointService: KubernetesEndpointService, public activatedRoute: ActivatedRoute, public store: Store, - public paginationMonitorFactory: PaginationMonitorFactory, - public entityServiceFactory: EntityServiceFactory, public entityMonitorFactory: EntityMonitorFactory ) { this.nodeName = getIdFromRoute(activatedRoute, 'nodeName'); this.kubeGuid = kubeEndpointService.kubeGuid; - const nodeEntityService = this.entityServiceFactory.create( - this.nodeName, - new GetKubernetesNode(this.nodeName, this.kubeGuid), - ); + const nodeEntityService = kubeEntityCatalog.node.store.getEntityService(this.nodeName, this.kubeGuid); this.node$ = nodeEntityService.entityObs$.pipe( filter(p => !!p && !!p.entity), diff --git a/custom-src/frontend/app/custom/kubernetes/store/action-builders/kube.action-builders.ts b/custom-src/frontend/app/custom/kubernetes/store/action-builders/kube.action-builders.ts new file mode 100644 index 0000000000..58ad75827c --- /dev/null +++ b/custom-src/frontend/app/custom/kubernetes/store/action-builders/kube.action-builders.ts @@ -0,0 +1,147 @@ +import { + OrchestratedActionBuilders, +} from '../../../../../../store/src/entity-catalog/action-orchestrator/action-orchestrator'; +import { GetHelmReleasePods, GetHelmReleaseServices } from '../../workloads/store/workloads.actions'; +import { + CreateKubernetesNamespace, + GeKubernetesDeployments, + GetKubernetesDashboard, + GetKubernetesNamespace, + GetKubernetesNamespaces, + GetKubernetesNode, + GetKubernetesNodes, + GetKubernetesPod, + GetKubernetesPods, + GetKubernetesPodsInNamespace, + GetKubernetesPodsOnNode, + GetKubernetesServices, + GetKubernetesServicesInNamespace, + GetKubernetesStatefulSets, + KubeHealthCheck, +} from '../kubernetes.actions'; + +export interface KubeStatefulSetsActionBuilders extends OrchestratedActionBuilders { + getMultiple: ( + kubeGuid: string, + paginationKey?: string, + ) => GetKubernetesStatefulSets +} + +export const kubeStatefulSetsActionBuilders: KubeStatefulSetsActionBuilders = { + getMultiple: (kubeGuid: string, paginationKey?: string) => new GetKubernetesStatefulSets(kubeGuid) +} + +export interface KubePodActionBuilders extends OrchestratedActionBuilders { + get: ( + podName: string, + kubeGuid: string, + extraArgs: { namespace: string } + ) => GetKubernetesPod, + getMultiple: ( + kubeGuid: string, + paginationKey?: string, + ) => GetKubernetesPods + getOnNode: ( + kubeGuid: string, + nodeName: string + ) => GetKubernetesPodsOnNode + getInNamespace: ( + kubeGuid: string, + namespace: string + ) => GetKubernetesPodsInNamespace + getInWorkload: ( + kubeGuid: string, + releaseTitle: string + ) => GetHelmReleasePods +} + +export const kubePodActionBuilders: KubePodActionBuilders = { + get: (podName: string, kubeGuid: string, { namespace }) => new GetKubernetesPod(podName, namespace, kubeGuid), + getMultiple: (kubeGuid: string, paginationKey?: string) => new GetKubernetesPods(kubeGuid), + getOnNode: (kubeGuid: string, nodeName: string) => new GetKubernetesPodsOnNode(kubeGuid, nodeName), + getInNamespace: (kubeGuid: string, namespace: string) => new GetKubernetesPodsInNamespace(kubeGuid, namespace), + getInWorkload: (kubeGuid: string, releaseTitle: string) => new GetHelmReleasePods(kubeGuid, releaseTitle) +} + +export interface KubeDeploymentActionBuilders extends OrchestratedActionBuilders { + getMultiple: ( + kubeGuid: string, + paginationKey?: string, + ) => GeKubernetesDeployments +} + +export const kubeDeploymentActionBuilders: KubeDeploymentActionBuilders = { + getMultiple: (kubeGuid: string, paginationKey?: string) => new GeKubernetesDeployments(kubeGuid) +} + +export interface KubeNodeActionBuilders extends OrchestratedActionBuilders { + get: ( + nodeName: string, + kubeGuid: string + ) => GetKubernetesNode + getMultiple: ( + kubeGuid: string, + paginationKey?: string, + ) => GetKubernetesNodes + healthCheck: ( + kubeGuid: string, + ) => KubeHealthCheck; +} + +export const kubeNodeActionBuilders: KubeNodeActionBuilders = { + get: (nodeName: string, endpointGuid: string) => new GetKubernetesNode(nodeName, endpointGuid), + getMultiple: (kubeGuid: string, paginationKey?: string) => new GetKubernetesNodes(kubeGuid), + healthCheck: (kubeGuid: string) => new KubeHealthCheck(kubeGuid) +} + +export interface KubeNamespaceActionBuilders extends OrchestratedActionBuilders { + get: ( + namespace: string, + kubeGuid: string + ) => GetKubernetesNamespace; + create: ( + namespace: string, + kubeGuid: string + ) => CreateKubernetesNamespace; + getMultiple: ( + kubeGuid: string, + paginationKey?: string, + ) => GetKubernetesNamespaces +} + +export const kubeNamespaceActionBuilders: KubeNamespaceActionBuilders = { + get: (namespace: string, kubeGuid: string) => new GetKubernetesNamespace(namespace, kubeGuid), + create: (namespace: string, kubeGuid: string) => new CreateKubernetesNamespace(namespace, kubeGuid), + getMultiple: (kubeGuid: string, paginationKey?: string) => new GetKubernetesNamespaces(kubeGuid) +} + +export interface KubeServiceActionBuilders extends OrchestratedActionBuilders { + getMultiple: ( + kubeGuid: string, + paginationKey?: string + ) => GetKubernetesServices + getInNamespace: ( + namespace: string, + kubeGuid: string + ) => GetKubernetesServicesInNamespace + getInWorkload: ( + releaseTitle: string, + kubeGuid: string + ) => GetHelmReleaseServices +} + +export const kubeServiceActionBuilders: KubeServiceActionBuilders = { + getMultiple: (kubeGuid: string, paginationKey?: string) => new GetKubernetesServices(kubeGuid), + getInNamespace: (namespace: string, kubeGuid: string) => new GetKubernetesServicesInNamespace(kubeGuid, namespace), + getInWorkload: (releaseTitle: string, kubeGuid: string) => new GetHelmReleaseServices(kubeGuid, releaseTitle) +} + +export interface KubeDashboardActionBuilders extends OrchestratedActionBuilders { + get: ( + kubeGuid: string + ) => GetKubernetesDashboard; +} + +export const kubeDashboardActionBuilders: KubeDashboardActionBuilders = { + get: (kubeGuid: string) => new GetKubernetesDashboard(kubeGuid) +} diff --git a/custom-src/frontend/app/custom/kubernetes/store/kube.getIds.ts b/custom-src/frontend/app/custom/kubernetes/store/kube.getIds.ts new file mode 100644 index 0000000000..ef66c673df --- /dev/null +++ b/custom-src/frontend/app/custom/kubernetes/store/kube.getIds.ts @@ -0,0 +1,49 @@ +import { environment } from '../../../environments/environment'; +import { + BasicKubeAPIResource, + KubernetesDeployment, + KubernetesNamespace, + KubernetesNode, + KubernetesPod, + KubernetesStatefulSet, + KubeService, +} from './kube.types'; +import { KubeDashboardStatus } from './kubernetes.effects'; + +const deliminate = (...args: string[]) => args.join('_:_'); + +const debugMissingKubeId = (entity: BasicKubeAPIResource, func: (...args: string[]) => string, ...args: string[]) => { + if (!environment.production && (!entity.metadata || !entity.metadata.kubeId)) { + console.log(`Kube entity does not have a kubeId, this is probably a bug: `, entity); + } + return func(...args); +} + +export const getGuidFromKubeNode = (kubeGuid: string, name: string): string => deliminate(name, kubeGuid) +export const getGuidFromKubeNodeObj = (entity: KubernetesNode): string => + debugMissingKubeId(entity, getGuidFromKubeNode, entity.metadata.kubeId, entity.metadata.name); + +export const getGuidFromKubeNamespace = (kubeGuid: string, name: string): string => deliminate(name, kubeGuid) +export const getGuidFromKubeNamespaceObj = (entity: KubernetesNamespace): string => + debugMissingKubeId(entity, getGuidFromKubeNamespace, entity.metadata.kubeId, entity.metadata.name); + +export const getGuidFromKubeService = (kubeGuid: string, namespace: string, name: string): string => deliminate(name, namespace, kubeGuid); +export const getGuidFromKubeServiceObj = (entity: KubeService): string => + debugMissingKubeId(entity, getGuidFromKubeService, entity.metadata.kubeId, entity.metadata.namespace, entity.metadata.name); + +export const getGuidFromKubeStatefulSet = (kubeGuid: string, namespace: string, name: string): string => + deliminate(name, namespace, kubeGuid); +export const getGuidFromKubeStatefulSetObj = (entity: KubernetesStatefulSet): string => + debugMissingKubeId(entity, getGuidFromKubeStatefulSet, entity.metadata.kubeId, entity.metadata.namespace, entity.metadata.name); + +export const getGuidFromKubeDeployment = (kubeGuid: string, namespace: string, name: string): string => + deliminate(name, namespace, kubeGuid); +export const getGuidFromKubeDeploymentObj = (entity: KubernetesDeployment): string => + debugMissingKubeId(entity, getGuidFromKubeDeployment, entity.metadata.kubeId, entity.metadata.namespace, entity.metadata.name); + +export const getGuidFromKubePod = (kubeGuid: string, namespace: string, name: string): string => deliminate(name, namespace, kubeGuid); +export const getGuidFromKubePodObj = (entity: KubernetesPod): string => + debugMissingKubeId(entity, getGuidFromKubePod, entity.metadata.kubeId, entity.metadata.namespace, entity.metadata.name); + +export const getGuidFromKubeDashboard = (kubeGuid: string): string => kubeGuid +export const getGuidFromKubeDashboardObj = (entity: KubeDashboardStatus): string => getGuidFromKubeDashboard(entity.kubeGuid); diff --git a/custom-src/frontend/app/custom/kubernetes/store/kube.selectors.ts b/custom-src/frontend/app/custom/kubernetes/store/kube.selectors.ts deleted file mode 100644 index dd88469ca2..0000000000 --- a/custom-src/frontend/app/custom/kubernetes/store/kube.selectors.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { compose } from '@ngrx/store'; - -import { BasicKubeAPIResource, Metadata } from './kube.types'; - - -const getValueOrNull = (object, key) => - object ? (object[key] ? object[key] : null) : null; -export const getMetadataGuid = (metadata: Metadata): string => - getValueOrNull(metadata, 'uid'); - -export const getKubeAPIMetadata = ( - resource: BasicKubeAPIResource -): Metadata => getValueOrNull(resource, 'metadata'); - -export const getKubeAPIResourceGuid = compose( - getMetadataGuid, - getKubeAPIMetadata -); - - diff --git a/custom-src/frontend/app/custom/kubernetes/store/kubernetes.actions.ts b/custom-src/frontend/app/custom/kubernetes/store/kubernetes.actions.ts index e678c983b8..cec88d6f34 100644 --- a/custom-src/frontend/app/custom/kubernetes/store/kubernetes.actions.ts +++ b/custom-src/frontend/app/custom/kubernetes/store/kubernetes.actions.ts @@ -17,6 +17,7 @@ import { kubernetesServicesEntityType, kubernetesStatefulSetsEntityType, } from '../kubernetes-entity-factory'; +import { getGuidFromKubeDashboard, getGuidFromKubeNamespace, getGuidFromKubeNode, getGuidFromKubePod } from './kube.getIds'; export const GET_RELEASE_POD_INFO = '[KUBERNETES Endpoint] Get Release Pods Info'; export const GET_RELEASE_POD_INFO_SUCCESS = '[KUBERNETES Endpoint] Get Release Pods Info Success'; @@ -81,33 +82,36 @@ export const GET_KUBE_DASHBOARD_SUCCESS = '[KUBERNETES Endpoint] Get Dashboard S export const GET_KUBE_DASHBOARD_FAILURE = '[KUBERNETES Endpoint] Get Dashboard Failure'; -const sortPodsByName = { +const defaultSortParams = { 'order-direction': 'desc' as SortDirection, 'order-direction-field': 'name' }; + export interface KubeAction extends EntityRequestAction { kubeGuid: string; } -export interface KubePaginationAction extends PaginatedAction, KubeAction { } +export interface KubePaginationAction extends PaginatedAction, KubeAction { + flattenPagination: boolean; +} +export interface KubeSingleEntityAction extends KubeAction { + guid: string; +} -export class KubeHealthCheck implements KubePaginationAction { - constructor(public kubeGuid) { - this.paginationKey = kubeGuid + '-health-check'; +export class GetKubernetesNode implements KubeSingleEntityAction { + constructor(public nodeName: string, public kubeGuid: string) { + this.guid = getGuidFromKubeNode(kubeGuid, nodeName); } - initialParams = { - limit: 1 - }; - type = GET_NODES_INFO; + type = GET_NODE_INFO; entityType = kubernetesNodesEntityType; endpointType = KUBERNETES_ENDPOINT_TYPE; entity = [kubernetesEntityFactory(kubernetesNodesEntityType)]; actions = [ - GET_NODES_INFO, - GET_NODES_INFO_SUCCESS, - GET_NODES_INFO_FAILURE + GET_NODE_INFO, + GET_NODE_INFO_SUCCESS, + GET_NODE_INFO_FAILURE ]; - paginationKey: string; + guid: string; } export class GetKubernetesNodes implements KubePaginationAction { @@ -124,54 +128,85 @@ export class GetKubernetesNodes implements KubePaginationAction { GET_NODES_INFO_FAILURE ]; paginationKey: string; - initialParams = { - 'order-direction': 'desc' as SortDirection, - 'order-direction-field': 'name' + initialParams: PaginationParam = { + ...defaultSortParams }; + flattenPagination = true; } -export class GetKubernetesNode implements KubeAction { - constructor(public nodeName: string, public kubeGuid: string) { +export class KubeHealthCheck extends GetKubernetesNodes { + constructor(kubeGuid) { + super(kubeGuid); + this.paginationKey = kubeGuid + '-health-check'; + this.initialParams.limit = 1; } - type = GET_NODE_INFO; - entityType = kubernetesNodesEntityType; - endpointType = KUBERNETES_ENDPOINT_TYPE; - entity = [kubernetesEntityFactory(kubernetesNodesEntityType)]; +} - actions = [ - GET_NODE_INFO, - GET_NODE_INFO_SUCCESS, - GET_NODE_INFO_FAILURE - ]; +export class CreateKubernetesNamespace implements KubeSingleEntityAction { + + constructor(public namespaceName: string, public kubeGuid: string) { + this.guid = getGuidFromKubeNamespace(kubeGuid, namespaceName); + } + + type = CREATE_NAMESPACE; + entityType = kubernetesNamespacesEntityType; + endpointType = KUBERNETES_ENDPOINT_TYPE; + entity = [kubernetesEntityFactory(kubernetesNamespacesEntityType)]; + actions = getActions('Namespace', 'Create'); + requestType: ApiRequestTypes = 'create'; + guid: string; } -export class GetKubernetesNamespace implements KubeAction { +export class GetKubernetesNamespace implements KubeSingleEntityAction { constructor(public namespaceName: string, public kubeGuid: string) { + this.guid = getGuidFromKubeNamespace(kubeGuid, namespaceName); } type = GET_NAMESPACE_INFO; entityType = kubernetesNamespacesEntityType; endpointType = KUBERNETES_ENDPOINT_TYPE; entity = [kubernetesEntityFactory(kubernetesNamespacesEntityType)]; - actions = [ GET_NAMESPACE_INFO, GET_NAMESPACE_INFO_SUCCESS, GET_NAMESPACE_INFO_FAILURE ]; + guid: string; } -export class CreateKubernetesNamespace implements KubeAction { - public guid: string; - constructor(public namespaceName: string, public kubeGuid: string) { - this.guid = `Creating-${namespaceName}-${kubeGuid}`; +export class GetKubernetesNamespaces implements KubePaginationAction { + constructor(public kubeGuid: string) { + this.paginationKey = getPaginationKey(kubernetesNamespacesEntityType, kubeGuid || 'all'); } - - type = CREATE_NAMESPACE; + type = GET_NAMESPACES_INFO; entityType = kubernetesNamespacesEntityType; endpointType = KUBERNETES_ENDPOINT_TYPE; entity = [kubernetesEntityFactory(kubernetesNamespacesEntityType)]; - actions = getActions('Namespace', 'Create'); - requestType: ApiRequestTypes = 'create'; + actions = [ + GET_NAMESPACES_INFO, + GET_NAMESPACES_INFO_SUCCESS, + GET_NAMESPACES_INFO_FAILURE + ]; + paginationKey: string; + initialParams = { + ...defaultSortParams + }; + flattenPagination = true; +} + +export class GetKubernetesPod implements KubeSingleEntityAction { + constructor(public podName, public namespaceName, public kubeGuid) { + this.guid = getGuidFromKubePod(kubeGuid, namespaceName, podName); + } + type = GET_KUBE_POD; + entityType = kubernetesPodsEntityType; + endpointType = KUBERNETES_ENDPOINT_TYPE; + entity = [kubernetesEntityFactory(kubernetesPodsEntityType)]; + actions = [ + GET_KUBE_POD, + GET_KUBE_POD_SUCCESS, + GET_KUBE_POD_FAILURE + ]; + guid: string; } export class GetKubernetesPods implements KubePaginationAction { @@ -188,88 +223,37 @@ export class GetKubernetesPods implements KubePaginationAction { GET_POD_INFO_FAILURE ]; paginationKey: string; - initialParams = { - ...sortPodsByName + initialParams: PaginationParam = { + ...defaultSortParams }; + flattenPagination = true; } -export class GetKubernetesPodsOnNode implements PaginatedAction, KubeAction { - constructor(public kubeGuid: string, public nodeName: string) { +export class GetKubernetesPodsOnNode extends GetKubernetesPods { + constructor(kubeGuid: string, public nodeName: string) { + super(kubeGuid) this.paginationKey = getPaginationKey(kubernetesPodsEntityType, `node-${nodeName}`, kubeGuid); - this.initialParams = { - fieldSelector: `spec.nodeName=${nodeName}`, - ...sortPodsByName - }; + this.initialParams.fieldSelector = `spec.nodeName=${nodeName}`; } type = GET_PODS_ON_NODE_INFO; - entityType = kubernetesPodsEntityType; - endpointType = KUBERNETES_ENDPOINT_TYPE; - entity = [kubernetesEntityFactory(kubernetesPodsEntityType)]; actions = [ GET_PODS_ON_NODE_INFO, GET_PODS_ON_NODE_INFO_SUCCESS, GET_PODS_ON_NODE_INFO_FAILURE ]; - paginationKey: string; - initialParams: PaginationParam; } -export class GetKubernetesServicesInNamespace implements PaginatedAction, KubeAction { - constructor(public kubeGuid: string, public namespaceName: string) { - this.paginationKey = getPaginationKey(kubernetesPodsEntityType, `ns-${namespaceName}`, kubeGuid); - } - type = GET_SERVICES_IN_NAMESPACE_INFO; - entityType = kubernetesServicesEntityType; - endpointType = KUBERNETES_ENDPOINT_TYPE; - entity = [kubernetesEntityFactory(kubernetesServicesEntityType)]; - actions = [ - GET_SERVICES_IN_NAMESPACE_INFO, - GET_SERVICES_IN_NAMESPACE_INFO_SUCCESS, - GET_SERVICES_IN_NAMESPACE_INFO_FAILURE - ]; - paginationKey: string; - initialParams = { - ...sortPodsByName - }; -} - -export class GetKubernetesPodsInNamespace implements PaginatedAction, KubeAction { - constructor(public kubeGuid: string, public namespaceName: string) { +export class GetKubernetesPodsInNamespace extends GetKubernetesPods { + constructor(kubeGuid: string, public namespaceName: string) { + super(kubeGuid); this.paginationKey = getPaginationKey(kubernetesPodsEntityType, `ns-${namespaceName}`, kubeGuid); } type = GET_PODS_IN_NAMESPACE_INFO; - entityType = kubernetesPodsEntityType; - endpointType = KUBERNETES_ENDPOINT_TYPE; - entity = [kubernetesEntityFactory(kubernetesPodsEntityType)]; actions = [ GET_PODS_IN_NAMESPACE_INFO, GET_PODS_IN_NAMEPSACE_INFO_SUCCESS, GET_PODS_IN_NAMEPSACE_INFO_FAILURE ]; - paginationKey: string; - initialParams = { - ...sortPodsByName - }; -} - -export class GetKubernetesNamespaces implements KubePaginationAction { - constructor(public kubeGuid: string) { - this.paginationKey = getPaginationKey(kubernetesNamespacesEntityType, kubeGuid || 'all'); - } - type = GET_NAMESPACES_INFO; - entityType = kubernetesNamespacesEntityType; - endpointType = KUBERNETES_ENDPOINT_TYPE; - entity = [kubernetesEntityFactory(kubernetesNamespacesEntityType)]; - actions = [ - GET_NAMESPACES_INFO, - GET_NAMESPACES_INFO_SUCCESS, - GET_NAMESPACES_INFO_FAILURE - ]; - paginationKey: string; - initialParams = { - 'order-direction': 'desc' as SortDirection, - 'order-direction-field': 'name' - }; } export class GetKubernetesServices implements KubePaginationAction { @@ -286,26 +270,26 @@ export class GetKubernetesServices implements KubePaginationAction { GET_SERVICE_INFO_FAILURE ]; paginationKey: string; - initialParams = { - 'order-direction': 'desc' as SortDirection, - 'order-direction-field': 'name' + initialParams: PaginationParam = { + ...defaultSortParams }; + flattenPagination = true; } -export class GetKubernetesPod implements KubeAction { - constructor(public podName, public namespaceName, public kubeGuid) { +export class GetKubernetesServicesInNamespace extends GetKubernetesServices { + constructor(kubeGuid: string, public namespaceName: string) { + super(kubeGuid); + this.paginationKey = getPaginationKey(kubernetesPodsEntityType, namespaceName, kubeGuid); } - type = GET_KUBE_POD; - entityType = kubernetesPodsEntityType; - endpointType = KUBERNETES_ENDPOINT_TYPE; - entity = [kubernetesEntityFactory(kubernetesPodsEntityType)]; + type = GET_SERVICES_IN_NAMESPACE_INFO; actions = [ - GET_KUBE_POD, - GET_KUBE_POD_SUCCESS, - GET_KUBE_POD_FAILURE + GET_SERVICES_IN_NAMESPACE_INFO, + GET_SERVICES_IN_NAMESPACE_INFO_SUCCESS, + GET_SERVICES_IN_NAMESPACE_INFO_FAILURE ]; } + export class GetKubernetesStatefulSets implements KubePaginationAction { constructor(public kubeGuid) { this.paginationKey = getPaginationKey(kubernetesStatefulSetsEntityType, kubeGuid); @@ -320,6 +304,7 @@ export class GetKubernetesStatefulSets implements KubePaginationAction { GET_KUBE_STATEFULSETS_FAILURE ]; paginationKey: string; + flattenPagination = true; } export class GeKubernetesDeployments implements KubePaginationAction { @@ -336,10 +321,12 @@ export class GeKubernetesDeployments implements KubePaginationAction { GET_KUBE_DEPLOYMENT_FAILURE ]; paginationKey: string; + flattenPagination = true; } -export class GetKubernetesDashboard implements KubeAction { +export class GetKubernetesDashboard implements KubeSingleEntityAction { constructor(public kubeGuid: string) { + this.guid = getGuidFromKubeDashboard(kubeGuid); } type = GET_KUBE_DASHBOARD; entityType = kubernetesDashboardEntityType; @@ -351,6 +338,7 @@ export class GetKubernetesDashboard implements KubeAction { GET_KUBE_DASHBOARD_SUCCESS, GET_KUBE_DASHBOARD_FAILURE ]; + guid: string; } function getKubeMetricsAction(guid: string) { diff --git a/custom-src/frontend/app/custom/kubernetes/store/kubernetes.effects.ts b/custom-src/frontend/app/custom/kubernetes/store/kubernetes.effects.ts index c55b3cca8a..645dc5b91e 100644 --- a/custom-src/frontend/app/custom/kubernetes/store/kubernetes.effects.ts +++ b/custom-src/frontend/app/custom/kubernetes/store/kubernetes.effects.ts @@ -21,15 +21,9 @@ import { isJetstreamError } from '../../../jetstream.helpers'; import { KUBERNETES_ENDPOINT_TYPE, kubernetesDashboardEntityType, - kubernetesDeploymentsEntityType, - kubernetesNamespacesEntityType, - kubernetesNodesEntityType, kubernetesPodsEntityType, - kubernetesServicesEntityType, - kubernetesStatefulSetsEntityType, } from '../kubernetes-entity-factory'; import { KubernetesPodExpandedStatusHelper } from '../services/kubernetes-expanded-state'; -import { getKubeAPIResourceGuid } from './kube.selectors'; import { BasicKubeAPIResource, KubernetesDeployment, @@ -79,6 +73,7 @@ export interface KubeDashboardContainer { export interface KubeDashboardStatus { guid: string; + kubeGuid: string; installed: boolean; stratosInstalled: boolean; running: boolean; @@ -96,9 +91,6 @@ export interface KubeDashboardStatus { serviceAccount: any; } -type GetID = (p: T) => string; -type Filter = (p: T) => boolean; - @Injectable() export class KubernetesEffects { proxyAPIVersion = environment.proxyAPIVersion; @@ -124,9 +116,9 @@ export class KubernetesEffects { result: [] } as NormalizedResponse; const status = response as KubeDashboardStatus; - const id = status.guid; - result.entities[dashboardEntityConfig.entityKey][id] = status; - result.result.push(id); + status.kubeGuid = action.kubeGuid; + result.entities[dashboardEntityConfig.entityKey][action.guid] = status; + result.result.push(action.guid); return [ new WrapperRequestActionSuccess(result, action) ]; @@ -151,174 +143,133 @@ export class KubernetesEffects { @Effect() fetchNodeInfo$ = this.actions$.pipe( ofType(GET_NODE_INFO), - flatMap(action => { - const nodeEntityConfig = entityCatalog.getEntity(KUBERNETES_ENDPOINT_TYPE, kubernetesNodesEntityType); - return this.processSingleItemAction(action, - `/pp/${this.proxyAPIVersion}/proxy/api/v1/nodes/${action.nodeName}`, - nodeEntityConfig.entityKey, - (node) => node.metadata.name); - }) + flatMap(action => this.processSingleItemAction( + action, + `/pp/${this.proxyAPIVersion}/proxy/api/v1/nodes/${action.nodeName}` + )) ); @Effect() fetchNamespaceInfo$ = this.actions$.pipe( ofType(GET_NAMESPACE_INFO), - flatMap(action => { - const namespaceEntityConfig = entityCatalog.getEntity(KUBERNETES_ENDPOINT_TYPE, kubernetesNamespacesEntityType); - return this.processSingleItemAction(action, - `/pp/${this.proxyAPIVersion}/proxy/api/v1/namespaces/${action.namespaceName}`, - namespaceEntityConfig.entityKey, - getKubeAPIResourceGuid); - }) + flatMap(action => this.processSingleItemAction( + action, + `/pp/${this.proxyAPIVersion}/proxy/api/v1/namespaces/${action.namespaceName}`) + ) ); @Effect() fetchPodsInfo$ = this.actions$.pipe( ofType(GET_POD_INFO), - flatMap(action => { - const podsEntityConfig = entityCatalog.getEntity(KUBERNETES_ENDPOINT_TYPE, kubernetesPodsEntityType); - return this.processListAction(action, - `/pp/${this.proxyAPIVersion}/proxy/api/v1/pods`, - podsEntityConfig.entityKey, - getKubeAPIResourceGuid - ); - }) + flatMap(action => this.processListAction( + action, + `/pp/${this.proxyAPIVersion}/proxy/api/v1/pods` + )) ); @Effect() fetchPodsOnNodeInfo$ = this.actions$.pipe( ofType(GET_PODS_ON_NODE_INFO), - flatMap(action => { - const podsEntityConfig = entityCatalog.getEntity(KUBERNETES_ENDPOINT_TYPE, kubernetesPodsEntityType); - return this.processListAction(action, + flatMap(action => + this.processListAction( + action, `/pp/${this.proxyAPIVersion}/proxy/api/v1/pods`, - podsEntityConfig.entityKey, - getKubeAPIResourceGuid - ); - }) + // Note - filtering done via param in action + ) + ) ); @Effect() fetchPodsInNamespaceInfo$ = this.actions$.pipe( ofType(GET_PODS_IN_NAMESPACE_INFO), - flatMap(action => { - const podsEntityConfig = entityCatalog.getEntity(KUBERNETES_ENDPOINT_TYPE, kubernetesPodsEntityType); - return this.processListAction(action, - `/pp/${this.proxyAPIVersion}/proxy/api/v1/namespaces/${action.namespaceName}/pods`, - podsEntityConfig.entityKey, - getKubeAPIResourceGuid - ); - }) + flatMap(action => this.processListAction( + action, + `/pp/${this.proxyAPIVersion}/proxy/api/v1/namespaces/${action.namespaceName}/pods`, + )) ); @Effect() fetchServicesInNamespaceInfo$ = this.actions$.pipe( ofType(GET_SERVICES_IN_NAMESPACE_INFO), - flatMap(action => { - const servicesEntityConfig = entityCatalog.getEntity(KUBERNETES_ENDPOINT_TYPE, kubernetesServicesEntityType); - return this.processListAction(action, - `/pp/${this.proxyAPIVersion}/proxy/api/v1/namespaces/${action.namespaceName}/services`, - servicesEntityConfig.entityKey, - getKubeAPIResourceGuid - ); - }) + flatMap(action => this.processListAction( + action, + `/pp/${this.proxyAPIVersion}/proxy/api/v1/namespaces/${action.namespaceName}/services`, + )) ); @Effect() fetchPodInfo$ = this.actions$.pipe( ofType(GET_KUBE_POD), - flatMap(action => { - const podsEntityConfig = entityCatalog.getEntity(KUBERNETES_ENDPOINT_TYPE, kubernetesPodsEntityType); - return this.processListAction(action, - `/pp/${this.proxyAPIVersion}/proxy/api/v1/namespaces/${action.namespaceName}/pods/${action.podName}`, - podsEntityConfig.entityKey, - getKubeAPIResourceGuid - ); - }) + flatMap(action => this.processSingleItemAction( + action, + `/pp/${this.proxyAPIVersion}/proxy/api/v1/namespaces/${action.namespaceName}/pods/${action.podName}`, + )) ); @Effect() fetchServicesInfo$ = this.actions$.pipe( ofType(GET_SERVICE_INFO), - flatMap(action => { - const servicesEntityConfig = entityCatalog.getEntity(KUBERNETES_ENDPOINT_TYPE, kubernetesServicesEntityType); - return this.processListAction(action, - `/pp/${this.proxyAPIVersion}/proxy/api/v1/services`, - servicesEntityConfig.entityKey, - getKubeAPIResourceGuid); - }) + flatMap(action => this.processListAction( + action, + `/pp/${this.proxyAPIVersion}/proxy/api/v1/services`, + )) ); @Effect() fetchNamespacesInfo$ = this.actions$.pipe( ofType(GET_NAMESPACES_INFO), - flatMap(action => { - const namespaceEntityConfig = entityCatalog.getEntity(KUBERNETES_ENDPOINT_TYPE, kubernetesNamespacesEntityType); - return this.processListAction(action, - `/pp/${this.proxyAPIVersion}/proxy/api/v1/namespaces`, - namespaceEntityConfig.entityKey, - getKubeAPIResourceGuid); - }) + flatMap(action => this.processListAction( + action, + `/pp/${this.proxyAPIVersion}/proxy/api/v1/namespaces`, + )) ); @Effect() createNamespace$ = this.actions$.pipe( ofType(CREATE_NAMESPACE), - flatMap(action => { - const namespaceEntityConfig = entityCatalog.getEntity(action); - return this.processSingleItemAction(action, - `/pp/${this.proxyAPIVersion}/proxy/api/v1/namespaces`, - namespaceEntityConfig.entityKey, - getKubeAPIResourceGuid, - { - kind: 'Namespace', - apiVersion: 'v1', - metadata: { - name: action.namespaceName, - }, - }); - }) + flatMap(action => this.processSingleItemAction( + action, + `/pp/${this.proxyAPIVersion}/proxy/api/v1/namespaces`, + { + kind: 'Namespace', + apiVersion: 'v1', + metadata: { + name: action.namespaceName, + }, + } + ) + ) ); @Effect() fetchStatefulSets$ = this.actions$.pipe( ofType(GET_KUBE_STATEFULSETS), - flatMap(action => { - const statefulSetsEntityConfig = entityCatalog.getEntity(KUBERNETES_ENDPOINT_TYPE, kubernetesStatefulSetsEntityType); - return this.processListAction(action, - `/pp/${this.proxyAPIVersion}/proxy/apis/apps/v1/statefulsets`, - statefulSetsEntityConfig.entityKey, - getKubeAPIResourceGuid); - }) + flatMap(action => this.processListAction( + action, + `/pp/${this.proxyAPIVersion}/proxy/apis/apps/v1/statefulsets`, + )) ); @Effect() fetchDeployments$ = this.actions$.pipe( ofType(GET_KUBE_DEPLOYMENT), - flatMap(action => { - const deploymentsEntityConfig = entityCatalog.getEntity(KUBERNETES_ENDPOINT_TYPE, kubernetesDeploymentsEntityType); - return this.processListAction(action, - `/pp/${this.proxyAPIVersion}/proxy/apis/apps/v1/deployments`, - deploymentsEntityConfig.entityKey, - getKubeAPIResourceGuid); - }) + flatMap(action => this.processListAction( + action, + `/pp/${this.proxyAPIVersion}/proxy/apis/apps/v1/deployments`, + )) ); private processNodeAction(action: GetKubernetesNodes) { - const nodeEntityConfig = entityCatalog.getEntity(KUBERNETES_ENDPOINT_TYPE, kubernetesNodesEntityType); - return this.processListAction(action, - `/pp/${this.proxyAPIVersion}/proxy/api/v1/nodes`, - nodeEntityConfig.entityKey, - getKubeAPIResourceGuid); + return this.processListAction( + action, + `/pp/${this.proxyAPIVersion}/proxy/api/v1/nodes` + ); } - private processListAction( - action: KubePaginationAction | KubeAction, - url: string, - entityKey: string, - getId: GetID, - filterResults?: Filter) { + private processListAction( + action: KubePaginationAction, + url: string) { this.store.dispatch(new StartRequestAction(action)); const getKubeIds = action.kubeGuid ? @@ -329,6 +280,7 @@ export class KubernetesEffects { ); let pKubeIds: string[]; + const entityKey = entityCatalog.getEntityKey(action); return getKubeIds.pipe( switchMap(kubeIds => { pKubeIds = kubeIds; @@ -363,10 +315,9 @@ export class KubernetesEffects { }); return combinedRes; }, []); - const filteredItems = filterResults ? items.filter(res => filterResults(res)) : items; - const processesData = filteredItems + const processesData = items .reduce((res, data) => { - const id = getId(data); + const id = action.entity[0].getId(data); const updatedData = action.entityType === kubernetesPodsEntityType ? KubernetesPodExpandedStatusHelper.updatePodWithExpandedStatus(data as unknown as KubernetesPod) : data; @@ -396,8 +347,6 @@ export class KubernetesEffects { private processSingleItemAction( action: KubeAction, url: string, - schemaKey: string, - getId: GetID, body?: any) { const requestType: ApiRequestTypes = body ? 'create' : 'fetch'; this.store.dispatch(new StartRequestAction(action, requestType)); @@ -410,20 +359,19 @@ export class KubernetesEffects { headers }; const request = body ? this.http.post(url, body, requestArgs) : this.http.get(url, requestArgs); - + const entityKey = entityCatalog.getEntityKey(action); return request .pipe( mergeMap((response: T) => { const res = { - entities: { [schemaKey]: {} }, + entities: { [entityKey]: {} }, result: [] } as NormalizedResponse; - const id = getId(response); const data = action.entityType === kubernetesPodsEntityType ? KubernetesPodExpandedStatusHelper.updatePodWithExpandedStatus(response as unknown as KubernetesPod) : response; - res.entities[schemaKey][id] = data; - res.result.push(id); + res.entities[entityKey][action.guid] = data; + res.result.push(action.guid); const actions: Action[] = [ new WrapperRequestActionSuccess(res, action) ]; diff --git a/custom-src/frontend/app/custom/kubernetes/tabs/kubernetes-summary-tab/kubernetes-summary.component.ts b/custom-src/frontend/app/custom/kubernetes/tabs/kubernetes-summary-tab/kubernetes-summary.component.ts index 5f7d4cdd5d..fc4b0a9ce5 100644 --- a/custom-src/frontend/app/custom/kubernetes/tabs/kubernetes-summary-tab/kubernetes-summary.component.ts +++ b/custom-src/frontend/app/custom/kubernetes/tabs/kubernetes-summary-tab/kubernetes-summary.component.ts @@ -4,20 +4,20 @@ import { SafeResourceUrl } from '@angular/platform-browser'; import { Router } from '@angular/router'; import { Store } from '@ngrx/store'; import { combineLatest, interval, Observable, Subscription } from 'rxjs'; -import { map, startWith } from 'rxjs/operators'; +import { first, map, startWith } from 'rxjs/operators'; import { AppState } from '../../../../../../store/src/app-state'; import { entityCatalog } from '../../../../../../store/src/entity-catalog/entity-catalog'; import { PaginationMonitorFactory } from '../../../../../../store/src/monitors/pagination-monitor.factory'; -import { getPaginationObservables } from '../../../../../../store/src/reducers/pagination-reducer/pagination-reducer.helper'; -import { PaginatedAction } from '../../../../../../store/src/types/pagination.types'; +import { getCurrentPageRequestInfo } from '../../../../../../store/src/reducers/pagination-reducer/pagination-reducer.types'; +import { PaginatedAction, PaginationEntityState } from '../../../../../../store/src/types/pagination.types'; import { safeUnsubscribe } from '../../../../core/utils.service'; import { IChartThresholds, ISimpleUsageChartData, } from '../../../../shared/components/simple-usage-chart/simple-usage-chart.types'; +import { kubeEntityCatalog } from '../../kubernetes-entity-catalog'; import { KubernetesEndpointService } from '../../services/kubernetes-endpoint.service'; -import { GetKubernetesNamespaces, GetKubernetesNodes, GetKubernetesPods } from '../../store/kubernetes.actions'; interface IValueLabels { usedLabel?: string; @@ -113,12 +113,15 @@ export class KubernetesSummaryTabComponent implements OnInit, OnDestroy { ngOnInit() { const guid = this.kubeEndpointService.baseKube.guid; - const podCountAction = new GetKubernetesPods(guid); - const nodeCountAction = new GetKubernetesNodes(guid); - const namespacesCountAction = new GetKubernetesNamespaces(guid); - const pods$ = this.getPaginationObservable(podCountAction); - const nodes$ = this.getPaginationObservable(nodeCountAction); - const namespaces$ = this.getPaginationObservable(namespacesCountAction); + const podsObs = kubeEntityCatalog.pod.store.getPaginationService(guid); + const pods$ = podsObs.entities$; + this.poll(kubeEntityCatalog.pod.actions.getMultiple(guid), podsObs.pagination$) + const nodesObs = kubeEntityCatalog.node.store.getPaginationService(guid); + const nodes$ = nodesObs.entities$; + this.poll(kubeEntityCatalog.node.actions.getMultiple(guid), nodesObs.pagination$) + const namespacesObs = kubeEntityCatalog.namespace.store.getPaginationService(guid); + const namespaces$ = namespacesObs.entities$; + this.poll(kubeEntityCatalog.namespace.actions.getMultiple(guid), namespacesObs.pagination$) this.podCount$ = this.kubeEndpointService.getCountObservable(pods$); this.nodeCount$ = this.kubeEndpointService.getCountObservable(nodes$); @@ -175,28 +178,22 @@ export class KubernetesSummaryTabComponent implements OnInit, OnDestroy { ); } - private getPaginationObservable(action: PaginatedAction) { - const paginationMonitor = this.paginationMonitorFactory.create( - action.paginationKey, - action, - true - ); - - this.ngZone.runOutsideAngular(() => { + private poll(action: PaginatedAction, pagination$: Observable) { + this.ngZone.runOutsideAngular(() => this.polls.push( interval(10000).subscribe(() => { - this.ngZone.run(() => { - this.store.dispatch(action); - }); + this.ngZone.run(() => this.updateList(action, pagination$)); }) - ); - }); + ) + ); + } - return getPaginationObservables({ - store: this.store, - action, - paginationMonitor - }).entities$; + private updateList(action: PaginatedAction, pagination$: Observable) { + pagination$.pipe(first()).subscribe(pag => { + if (!getCurrentPageRequestInfo(pag, { busy: true, error: false, message: '' }).busy) { + this.store.dispatch(action); + } + }) } ngOnDestroy() { diff --git a/custom-src/frontend/app/custom/kubernetes/workloads/list-types/helm-release-pods-list-source.ts b/custom-src/frontend/app/custom/kubernetes/workloads/list-types/helm-release-pods-list-source.ts index d3cb3f80c4..6726c3ef26 100644 --- a/custom-src/frontend/app/custom/kubernetes/workloads/list-types/helm-release-pods-list-source.ts +++ b/custom-src/frontend/app/custom/kubernetes/workloads/list-types/helm-release-pods-list-source.ts @@ -3,9 +3,8 @@ import { ListDataSource } from 'frontend/packages/core/src/shared/components/lis import { IListConfig } from 'frontend/packages/core/src/shared/components/list/list.component.types'; import { AppState } from 'frontend/packages/store/src/app-state'; -import { getKubeAPIResourceGuid } from '../../store/kube.selectors'; +import { kubeEntityCatalog } from '../../kubernetes-entity-catalog'; import { KubernetesPod } from '../../store/kube.types'; -import { GetHelmReleasePods } from '../store/workloads.actions'; export class HelmReleasePodsDataSource extends ListDataSource { @@ -16,13 +15,12 @@ export class HelmReleasePodsDataSource extends ListDataSource { endpointGuid: string, releaseTitle: string ) { - const action = new GetHelmReleasePods(endpointGuid, releaseTitle); - + const action = kubeEntityCatalog.pod.actions.getInWorkload(endpointGuid, releaseTitle); super({ store, action, schema: action.entity[0], - getRowUniqueId: getKubeAPIResourceGuid, + getRowUniqueId: (row: KubernetesPod) => action.entity[0].getId(row), paginationKey: action.paginationKey, isLocal: true, listConfig, diff --git a/custom-src/frontend/app/custom/kubernetes/workloads/list-types/helm-release-services-list-source.ts b/custom-src/frontend/app/custom/kubernetes/workloads/list-types/helm-release-services-list-source.ts index ff70a8a77e..24186f23f9 100644 --- a/custom-src/frontend/app/custom/kubernetes/workloads/list-types/helm-release-services-list-source.ts +++ b/custom-src/frontend/app/custom/kubernetes/workloads/list-types/helm-release-services-list-source.ts @@ -2,41 +2,9 @@ import { Store } from '@ngrx/store'; import { ListDataSource } from 'frontend/packages/core/src/shared/components/list/data-sources-controllers/list-data-source'; import { IListConfig } from 'frontend/packages/core/src/shared/components/list/list.component.types'; import { AppState } from 'frontend/packages/store/src/app-state'; -import { PaginationMonitor } from 'frontend/packages/store/src/monitors/pagination-monitor'; -import { getPaginationObservables } from 'frontend/packages/store/src/reducers/pagination-reducer/pagination-reducer.helper'; -import { Observable } from 'rxjs'; -import { filter, map, publishReplay, refCount, switchMap } from 'rxjs/operators'; -import { kubernetesEntityFactory } from '../../kubernetes-entity-factory'; import { KubeService } from '../../store/kube.types'; -import { GetKubernetesServicesInNamespace } from '../../store/kubernetes.actions'; -import { getHelmReleaseServiceId } from '../store/workloads-entity-factory'; -import { GetHelmReleases, GetHelmReleaseServices } from '../store/workloads.actions'; -import { HelmRelease, HelmReleaseService } from '../workload.types'; - - -export const fetchHelmReleaseServiceFromKubernetes = (store: Store, helmService: HelmReleaseService): Observable => { - return fetchRelease(store, helmService.endpointId, helmService.releaseTitle).pipe( - switchMap(release => { - const action = new GetKubernetesServicesInNamespace(helmService.endpointId, release.namespace); - const paginationMonitor = new PaginationMonitor(store, action.paginationKey, kubernetesEntityFactory(action.entityType)); - return getPaginationObservables({ store, action, paginationMonitor }).entities$; - }), - filter(entities => !!entities), - map(services => services.find(service => service.metadata.name === helmService.name)), - publishReplay(1), - refCount() - ); -}; - -function fetchRelease(store: Store, endpointGuid: string, releaseTitle: string) { - const action = new GetHelmReleases(); - const paginationMonitor = new PaginationMonitor(store, action.paginationKey, action); - const svc = getPaginationObservables({ store, action, paginationMonitor }); - return svc.entities$.pipe( - map((items: HelmRelease[]) => items.find(item => item.guid === `${endpointGuid}:${releaseTitle}`)) - ); -} +import { GetHelmReleaseServices } from '../store/workloads.actions'; export class HelmReleaseServicesDataSource extends ListDataSource { @@ -51,23 +19,10 @@ export class HelmReleaseServicesDataSource extends ListDataSource { store, action, schema: action.entity[0], - getRowUniqueId: getHelmReleaseServiceId, + getRowUniqueId: (row: KubeService) => action.entity[0].getId(row), paginationKey: action.paginationKey, isLocal: true, listConfig, }); - // transformEntity: map((helmServices: HelmReleaseService[]) => { - // return helmServices.map(helmService => { - // if (!helmService.kubeService$) { - // helmService.kubeService$ = fetchHelmReleaseServiceFromKubernetes(store, helmService); - // } - // return helmService; - // }); - // }), - // refresh: () => { - // store.dispatch(action); - // store.dispatch(new ClearPaginationOfType(action)); - // } - // }); } } diff --git a/custom-src/frontend/app/custom/kubernetes/workloads/list-types/helm-releases-list-source.ts b/custom-src/frontend/app/custom/kubernetes/workloads/list-types/helm-releases-list-source.ts index 35bf800960..d6fe2020f1 100644 --- a/custom-src/frontend/app/custom/kubernetes/workloads/list-types/helm-releases-list-source.ts +++ b/custom-src/frontend/app/custom/kubernetes/workloads/list-types/helm-releases-list-source.ts @@ -10,10 +10,8 @@ import { IListConfig } from 'frontend/packages/core/src/shared/components/list/l import { AppState } from 'frontend/packages/store/src/app-state'; import { PaginationEntityState } from 'frontend/packages/store/src/types/pagination.types'; -import { kubernetesEntityFactory } from '../../kubernetes-entity-factory'; -import { getHelmReleaseId, helmReleaseEntityKey } from '../store/workloads-entity-factory'; -import { GetHelmReleases } from '../store/workloads.actions'; import { HelmRelease } from '../workload.types'; +import { workloadsEntityCatalog } from '../workloads-entity-catalog'; const kubeEndpointFilter = (entities: HelmRelease[], paginationState: PaginationEntityState) => { // Filter by Kube Endpoint and Namespace @@ -33,13 +31,14 @@ export class HelmReleasesDataSource extends ListDataSource { store: Store, listConfig: IListConfig ) { - const action = new GetHelmReleases(); + + const action = workloadsEntityCatalog.release.actions.getMultiple(); const transformEntities = [{ type: 'filter' as DataFunctionDefinitionType, field: 'name' }, kubeEndpointFilter]; super({ store, action, - schema: kubernetesEntityFactory(helmReleaseEntityKey), - getRowUniqueId: getHelmReleaseId, + schema: action.entity[0], + getRowUniqueId: row => action.entity[0].getId(row), paginationKey: action.paginationKey, isLocal: true, transformEntities, diff --git a/custom-src/frontend/app/custom/kubernetes/workloads/list-types/kube-namespaces-filter-config.service.ts b/custom-src/frontend/app/custom/kubernetes/workloads/list-types/kube-namespaces-filter-config.service.ts index 6132e3fc47..846848fc7a 100644 --- a/custom-src/frontend/app/custom/kubernetes/workloads/list-types/kube-namespaces-filter-config.service.ts +++ b/custom-src/frontend/app/custom/kubernetes/workloads/list-types/kube-namespaces-filter-config.service.ts @@ -2,8 +2,6 @@ import { Injectable, OnDestroy } from '@angular/core'; import { Store } from '@ngrx/store'; import { safeUnsubscribe } from 'frontend/packages/core/src/core/utils.service'; import { AppState } from 'frontend/packages/store/src/app-state'; -import { PaginationMonitorFactory } from 'frontend/packages/store/src/monitors/pagination-monitor.factory'; -import { getPaginationObservables } from 'frontend/packages/store/src/reducers/pagination-reducer/pagination-reducer.helper'; import { connectedEndpointsOfTypesSelector } from 'frontend/packages/store/src/selectors/endpoint.selectors'; import { EndpointModel } from 'frontend/packages/store/src/types/endpoint.types'; import { BehaviorSubject, combineLatest, Observable, Subscription } from 'rxjs'; @@ -20,9 +18,9 @@ import { } from 'rxjs/operators'; import { getCurrentPageRequestInfo } from '../../../../../../store/src/reducers/pagination-reducer/pagination-reducer.types'; -import { KUBERNETES_ENDPOINT_TYPE, kubernetesEntityFactory } from '../../kubernetes-entity-factory'; +import { kubeEntityCatalog } from '../../kubernetes-entity-catalog'; +import { KUBERNETES_ENDPOINT_TYPE } from '../../kubernetes-entity-factory'; import { KubernetesNamespace } from '../../store/kube.types'; -import { GetKubernetesNamespaces } from '../../store/kubernetes.actions'; export interface KubernetesNamespacesFilterItem { list$: Observable; @@ -38,10 +36,8 @@ export class KubernetesNamespacesFilterService implements OnDestroy { public kube: KubernetesNamespacesFilterItem; public namespace: KubernetesNamespacesFilterItem; - private isLoading$: Observable; private subs: Subscription[] = []; - private paginationAction = new GetKubernetesNamespaces(null); private allNamespaces = this.getNamespacesObservable(); private allNamespacesLoading$ = this.allNamespaces.pagination$.pipe(map( pag => getCurrentPageRequestInfo(pag).busy @@ -49,32 +45,16 @@ export class KubernetesNamespacesFilterService implements OnDestroy { constructor( private store: Store, - private paginationMonitorFactory: PaginationMonitorFactory, ) { this.kube = this.createKube(); this.namespace = this.createNamespace(); - // Start watching the cf/org/space plus automatically setting values only when we actually have values to auto select + // Start watching the namespace plus automatically setting values only when we actually have values to auto select this.namespace.list$.pipe(first()).subscribe(() => this.setupAutoSelectors()); - - this.isLoading$ = combineLatest( - this.kube.loading$, - this.namespace.loading$, - ).pipe( - map(([kubeLoading, nsLoading]) => kubeLoading || nsLoading) - ); } private getNamespacesObservable() { - return getPaginationObservables({ - store: this.store, - action: this.paginationAction, - paginationMonitor: this.paginationMonitorFactory.create( - this.paginationAction.paginationKey, - kubernetesEntityFactory(this.paginationAction.entityType), - true - ) - }, true); + return kubeEntityCatalog.namespace.store.getPaginationService(null); } private createKube() { diff --git a/custom-src/frontend/app/custom/kubernetes/workloads/release/helm-release-tab-base/helm-release-tab-base.component.ts b/custom-src/frontend/app/custom/kubernetes/workloads/release/helm-release-tab-base/helm-release-tab-base.component.ts index f3d8d9927a..3c62493c90 100644 --- a/custom-src/frontend/app/custom/kubernetes/workloads/release/helm-release-tab-base/helm-release-tab-base.component.ts +++ b/custom-src/frontend/app/custom/kubernetes/workloads/release/helm-release-tab-base/helm-release-tab-base.component.ts @@ -1,32 +1,23 @@ import { Component, OnDestroy } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { Store } from '@ngrx/store'; -import { LoggerService } from 'frontend/packages/core/src/core/logger.service'; -import { IPageSideNavTab } from 'frontend/packages/core/src/features/dashboard/page-side-nav/page-side-nav.component'; -import { AppState } from 'frontend/packages/store/src/app-state'; -import { entityCatalog } from 'frontend/packages/store/src/entity-catalog/entity-catalog'; -import { PaginatedAction } from 'frontend/packages/store/src/types/pagination.types'; -import { EntityRequestAction, WrapperRequestActionSuccess } from 'frontend/packages/store/src/types/request.types'; import { Observable, Subject, Subscription } from 'rxjs'; import makeWebSocketObservable, { GetWebSocketResponses } from 'rxjs-websockets'; import { catchError, map, share, switchMap } from 'rxjs/operators'; +import { AppState } from '../../../../../../../store/src/app-state'; +import { entityCatalog } from '../../../../../../../store/src/entity-catalog/entity-catalog'; +import { EntityRequestAction, WrapperRequestActionSuccess } from '../../../../../../../store/src/types/request.types'; +import { LoggerService } from '../../../../../core/logger.service'; +import { IPageSideNavTab } from '../../../../../features/dashboard/page-side-nav/page-side-nav.component'; +import { kubeEntityCatalog } from '../../../kubernetes-entity-catalog'; import { KubernetesPodExpandedStatusHelper } from '../../../services/kubernetes-expanded-state'; -import { getKubeAPIResourceGuid } from '../../../store/kube.selectors'; -import { KubernetesPod } from '../../../store/kube.types'; -import { getHelmReleaseServiceId } from '../../store/workloads-entity-factory'; -import { - GetHelmReleaseGraph, - GetHelmReleasePods, - GetHelmReleaseResource, - GetHelmReleaseServices, -} from '../../store/workloads.actions'; -import { HelmReleaseGraph, HelmReleaseGuid, HelmReleasePod } from '../../workload.types'; +import { KubernetesPod, KubeService } from '../../../store/kube.types'; +import { KubePaginationAction } from '../../../store/kubernetes.actions'; +import { HelmReleaseGraph, HelmReleaseGuid, HelmReleasePod, HelmReleaseService } from '../../workload.types'; +import { workloadsEntityCatalog } from '../../workloads-entity-catalog'; import { HelmReleaseHelperService } from '../tabs/helm-release-helper.service'; -type IDGetterFunction = (data: any) => string; - - @Component({ selector: 'app-helm-release-tab-base', @@ -114,19 +105,21 @@ export class HelmReleaseTabBaseComponent implements OnDestroy { } else if (messageObj.kind === 'Pods') { const pods: KubernetesPod[] = messageObj.data || []; const podsWithInfo: KubernetesPod[] = pods.map(pod => KubernetesPodExpandedStatusHelper.updatePodWithExpandedStatus(pod)); - const releasePodsAction = new GetHelmReleasePods(this.helmReleaseHelper.endpointGuid, this.helmReleaseHelper.releaseTitle); - this.populateList(releasePodsAction, podsWithInfo, getKubeAPIResourceGuid); + const releasePodsAction = kubeEntityCatalog.pod.actions.getInWorkload( + this.helmReleaseHelper.endpointGuid, + this.helmReleaseHelper.releaseTitle + ); + this.populateList(releasePodsAction, podsWithInfo); } else if (messageObj.kind === 'Graph') { const graph: HelmReleaseGraph = messageObj.data; graph.endpointId = this.helmReleaseHelper.endpointGuid; graph.releaseTitle = this.helmReleaseHelper.releaseTitle; - const releaseGraphAction = new GetHelmReleaseGraph(graph.endpointId, graph.releaseTitle); - + const releaseGraphAction = workloadsEntityCatalog.graph.actions.get(graph.releaseTitle, graph.endpointId); this.addResource(releaseGraphAction, graph); } else if (messageObj.kind === 'Manifest' || messageObj.kind === 'Resources') { // Store all of the services const manifest = messageObj.data; - const svcs = []; + const svcs: KubeService[] = []; // Store ALL resources for the release manifest.forEach(resource => { if (resource.kind === 'Service' && prefix) { @@ -134,17 +127,20 @@ export class HelmReleaseTabBaseComponent implements OnDestroy { } }); if (svcs.length > 0) { - const releaseServicesAction = new GetHelmReleaseServices( + const releaseServicesAction = kubeEntityCatalog.service.actions.getInWorkload( + this.helmReleaseHelper.releaseTitle, this.helmReleaseHelper.endpointGuid, - this.helmReleaseHelper.releaseTitle - ); - this.populateList(releaseServicesAction, svcs, getHelmReleaseServiceId); + ) + this.populateList(releaseServicesAction, svcs); } const resources = { ...manifest }; resources.endpointId = this.helmReleaseHelper.endpointGuid; resources.releaseTitle = this.helmReleaseHelper.releaseTitle; - const releaseResourceAction = new GetHelmReleaseResource(resources.endpointId, resources.releaseTitle); + const releaseResourceAction = workloadsEntityCatalog.resource.actions.get( + resources.releaseTitle, + resources.endpointId, + ); this.addResource(releaseResourceAction, resources); } } @@ -167,19 +163,24 @@ export class HelmReleaseTabBaseComponent implements OnDestroy { this.store.dispatch(successWrapper); } - private populateList(action: PaginatedAction, resources: any, idGetter: IDGetterFunction) { + private populateList(action: KubePaginationAction, resources: any) { + const entity = entityCatalog.getEntity(action); const newResources = {}; resources.forEach(resource => { - const newResource: HelmReleasePod = { - endpointId: action.endpointGuid, + const newResource: HelmReleasePod | HelmReleaseService = { + endpointId: action.kubeGuid, releaseTitle: this.helmReleaseHelper.releaseTitle, ...resource }; - newResources[idGetter(newResource)] = newResource; + newResource.metadata.kubeId = action.kubeGuid; + // The service entity from manifest is missing this, but apply here to ensure any others are caught + newResource.metadata.namespace = this.helmReleaseHelper.namespace; + const entityId = action.entity[0].getId(resource) + newResources[entityId] = newResource; }); const releasePods = { - entities: { [entityCatalog.getEntityKey(action)]: newResources }, + entities: { [entity.entityKey]: newResources }, result: Object.keys(newResources) }; const successWrapper = new WrapperRequestActionSuccess(releasePods, action, 'fetch', releasePods.result.length, 1); diff --git a/custom-src/frontend/app/custom/kubernetes/workloads/release/tabs/helm-release-helper.service.ts b/custom-src/frontend/app/custom/kubernetes/workloads/release/tabs/helm-release-helper.service.ts index aa8a7b73c9..bcdef4478b 100644 --- a/custom-src/frontend/app/custom/kubernetes/workloads/release/tabs/helm-release-helper.service.ts +++ b/custom-src/frontend/app/custom/kubernetes/workloads/release/tabs/helm-release-helper.service.ts @@ -1,20 +1,10 @@ import { Injectable } from '@angular/core'; -import { Store } from '@ngrx/store'; -import { AppState } from 'frontend/packages/store/src/app-state'; -import { entityCatalog } from 'frontend/packages/store/src/entity-catalog/entity-catalog'; -import { EntityServiceFactory } from 'frontend/packages/store/src/entity-service-factory.service'; -import { PaginationMonitorFactory } from 'frontend/packages/store/src/monitors/pagination-monitor.factory'; -import { selectEntity } from 'frontend/packages/store/src/selectors/api.selectors'; import { Observable } from 'rxjs'; import { filter, map } from 'rxjs/operators'; +import { kubeEntityCatalog } from '../../../kubernetes-entity-catalog'; import { KubernetesPod } from '../../../store/kube.types'; -import { - GetHelmRelease, - GetHelmReleaseGraph, - GetHelmReleasePods, - GetHelmReleaseResource, -} from '../../store/workloads.actions'; +import { getHelmReleaseDetailsFromGuid } from '../../store/workloads-entity-factory'; import { HelmRelease, HelmReleaseChartData, @@ -22,6 +12,7 @@ import { HelmReleaseGuid, HelmReleaseResource, } from '../../workload.types'; +import { workloadsEntityCatalog } from '../../workloads-entity-catalog'; @Injectable() @@ -38,17 +29,18 @@ export class HelmReleaseHelperService { constructor( helmReleaseGuid: HelmReleaseGuid, - private store: Store, - private esf: EntityServiceFactory, - private paginationMonitorFactory: PaginationMonitorFactory, ) { this.guid = helmReleaseGuid.guid; - this.releaseTitle = this.guid.split(':')[2]; - this.namespace = this.guid.split(':')[1]; - this.endpointGuid = this.guid.split(':')[0]; - - const action = new GetHelmRelease(this.endpointGuid, this.namespace, this.releaseTitle); - const entityService = this.esf.create(action.guid, action); + const { endpointId, namespace, releaseTitle } = getHelmReleaseDetailsFromGuid(this.guid); + this.releaseTitle = releaseTitle; + this.namespace = namespace; + this.endpointGuid = endpointId; + + const entityService = workloadsEntityCatalog.release.store.getEntityService( + this.releaseTitle, + this.endpointGuid, + { namespace: this.namespace } + ); this.release$ = entityService.waitForEntity$.pipe( map((item) => item.entity), @@ -71,28 +63,26 @@ export class HelmReleaseHelperService { public fetchReleaseGraph(): Observable { // Get helm release - const action = new GetHelmReleaseGraph(this.endpointGuid, this.releaseTitle); - const entityKey = entityCatalog.getEntityKey(action); - return this.store.select(selectEntity(entityKey, action.guid)).pipe( + const guid = workloadsEntityCatalog.graph.actions.get(this.releaseTitle, this.endpointGuid).guid; + return workloadsEntityCatalog.graph.store.getEntityMonitor(guid).entity$.pipe( filter(graph => !!graph) ); } public fetchReleaseResources(): Observable { // Get helm release - const action = new GetHelmReleaseResource(this.endpointGuid, this.releaseTitle); - const entityKey = entityCatalog.getEntityKey(action); - return this.store.select(selectEntity(entityKey, action.guid)).pipe( + const action = workloadsEntityCatalog.resource.actions.get(this.releaseTitle, this.endpointGuid) + return workloadsEntityCatalog.resource.store.getEntityMonitor( + action.guid + ).entity$.pipe( filter(resources => !!resources) ); } public fetchReleaseChartStats(): Observable { - const action = new GetHelmReleasePods(this.endpointGuid, this.releaseTitle); - return this.paginationMonitorFactory.create( - action.paginationKey, - action.entity[0], - true + return kubeEntityCatalog.pod.store.getInWorkload.getPaginationMonitor( + this.endpointGuid, + this.releaseTitle ).currentPage$.pipe( filter(pods => !!pods), map(this.mapPods) diff --git a/custom-src/frontend/app/custom/kubernetes/workloads/release/tabs/helm-release-summary-tab/helm-release-summary-tab.component.ts b/custom-src/frontend/app/custom/kubernetes/workloads/release/tabs/helm-release-summary-tab/helm-release-summary-tab.component.ts index 43b268b89a..daa29e2160 100644 --- a/custom-src/frontend/app/custom/kubernetes/workloads/release/tabs/helm-release-summary-tab/helm-release-summary-tab.component.ts +++ b/custom-src/frontend/app/custom/kubernetes/workloads/release/tabs/helm-release-summary-tab/helm-release-summary-tab.component.ts @@ -12,8 +12,8 @@ import { combineLatest, Observable, ReplaySubject } from 'rxjs'; import { filter, first, map, publishReplay, refCount, startWith } from 'rxjs/operators'; import { endpointsEntityRequestDataSelector } from '../../../../../../../../store/src/selectors/endpoint.selectors'; -import { GetHelmReleases } from '../../../store/workloads.actions'; import { HelmReleaseChartData, HelmReleaseResource } from '../../../workload.types'; +import { workloadsEntityCatalog } from '../../../workloads-entity-catalog'; import { HelmReleaseHelperService } from '../helm-release-helper.service'; @Component({ @@ -188,7 +188,7 @@ export class HelmReleaseSummaryTabComponent implements OnDestroy { this.logService.error('Failed to delete release: ', err); }, complete: () => { - const action = new GetHelmReleases(); + const action = workloadsEntityCatalog.release.actions.getMultiple(); this.store.dispatch(new ClearPaginationOfType(action)); this.completeDelete(); this.store.dispatch(new RouterNav({ path: ['workloads'] })); diff --git a/custom-src/frontend/app/custom/kubernetes/workloads/store/workload-action-builders.ts b/custom-src/frontend/app/custom/kubernetes/workloads/store/workload-action-builders.ts new file mode 100644 index 0000000000..eb7591f9c5 --- /dev/null +++ b/custom-src/frontend/app/custom/kubernetes/workloads/store/workload-action-builders.ts @@ -0,0 +1,42 @@ +import { + OrchestratedActionBuilders, +} from '../../../../../../store/src/entity-catalog/action-orchestrator/action-orchestrator'; +import { GetHelmRelease, GetHelmReleaseGraph, GetHelmReleaseResource, GetHelmReleases } from './workloads.actions'; + +export interface WorkloadReleaseBuilders extends OrchestratedActionBuilders { + get: ( + title: string, + endpointGuid: string, + extraArgs: { namespace: string } + ) => GetHelmRelease; + getMultiple: () => GetHelmReleases; +} + +export const workloadReleaseBuilders: WorkloadReleaseBuilders = { + get: (title: string, endpointGuid: string, { namespace }: { namespace: string }) => { + return new GetHelmRelease(endpointGuid, namespace, title); + }, + getMultiple: () => new GetHelmReleases() +} + +export interface WorkloadGraphBuilders extends OrchestratedActionBuilders { + get: ( + releaseTitle: string, + endpointGuid: string + ) => GetHelmReleaseGraph +} + +export const workloadGraphBuilders: WorkloadGraphBuilders = { + get: (releaseTitle: string, endpointGuid: string) => new GetHelmReleaseGraph(endpointGuid, releaseTitle) +} + +export interface WorkloadResourceBuilders extends OrchestratedActionBuilders { + get: ( + releaseTitle: string, + endpointGuid: string, + ) => GetHelmReleaseResource +} + +export const workloadResourceBuilders: WorkloadResourceBuilders = { + get: (releaseTitle: string, endpointGuid: string) => new GetHelmReleaseResource(endpointGuid, releaseTitle) +} \ No newline at end of file diff --git a/custom-src/frontend/app/custom/kubernetes/workloads/store/workloads-entity-factory.ts b/custom-src/frontend/app/custom/kubernetes/workloads/store/workloads-entity-factory.ts index 804514030a..abce799544 100644 --- a/custom-src/frontend/app/custom/kubernetes/workloads/store/workloads-entity-factory.ts +++ b/custom-src/frontend/app/custom/kubernetes/workloads/store/workloads-entity-factory.ts @@ -1,6 +1,6 @@ import { EntitySchema } from '../../../../../../store/src/helpers/entity-schema'; import { addKubernetesEntitySchema, KubernetesEntitySchema } from '../../kubernetes-entity-factory'; -import { HelmRelease, HelmReleaseGraph, HelmReleaseResource, HelmReleaseService } from '../workload.types'; +import { HelmRelease, HelmReleaseGraph, HelmReleaseResource } from '../workload.types'; export const helmReleaseEntityKey = 'helmRelease'; export const helmReleasePodEntityType = 'helmReleasePod'; @@ -8,11 +8,21 @@ export const helmReleaseServiceEntityType = 'helmReleaseService'; export const helmReleaseGraphEntityType = 'helmReleaseGraph'; export const helmReleaseResourceEntityType = 'helmReleaseResource'; -export const getHelmReleaseId = (entity: HelmRelease) => `${entity.endpointId}-${entity.namespace}-${entity.name}`; -export const getHelmReleaseServiceId = - (entity: HelmReleaseService) => `${entity.endpointId}-${entity.releaseTitle}-${entity.metadata.name}`; -export const getHelmReleaseGraphId = (entity: HelmReleaseGraph) => `${entity.endpointId}-${entity.releaseTitle}`; -export const getHelmReleaseResourceId = (entity: HelmReleaseResource) => `${entity.endpointId}-${entity.releaseTitle}`; +const separator = ':'; +export const getHelmReleaseDetailsFromGuid = (guid: string) => { + const parts = guid.split(separator); + return { + endpointId: parts[0], + namespace: parts[1], + releaseTitle: parts[2] + } +} +export const getHelmReleaseId = (endpointId: string, namespace: string, name: string) => `${endpointId}${separator}${namespace}${separator}${name}`; +export const getHelmReleaseIdByObj = (entity: HelmRelease) => getHelmReleaseId(entity.endpointId, entity.namespace, entity.name); +export const getHelmReleaseGraphId = (endpointId: string, releaseTitle: string) => `${endpointId}${separator}${releaseTitle}`; +export const getHelmReleaseGraphIdByObj = (entity: HelmReleaseGraph) => getHelmReleaseGraphId(entity.endpointId, entity.releaseTitle); +export const getHelmReleaseResourceId = (endpointId: string, releaseTitle: string) => `${endpointId}${separator}${releaseTitle}`; +export const getHelmReleaseResourceIdByObj = (entity: HelmReleaseResource) => getHelmReleaseResourceId(entity.endpointId, entity.releaseTitle); const entityCache: { [key: string]: EntitySchema @@ -21,19 +31,19 @@ const entityCache: { entityCache[helmReleaseEntityKey] = new KubernetesEntitySchema( helmReleaseEntityKey, {}, - { idAttribute: getHelmReleaseId } + { idAttribute: getHelmReleaseIdByObj } ); entityCache[helmReleaseGraphEntityType] = new KubernetesEntitySchema( helmReleaseGraphEntityType, {}, - { idAttribute: getHelmReleaseGraphId } + { idAttribute: getHelmReleaseGraphIdByObj } ); entityCache[helmReleaseResourceEntityType] = new KubernetesEntitySchema( helmReleaseResourceEntityType, {}, - { idAttribute: getHelmReleaseResourceId } + { idAttribute: getHelmReleaseResourceIdByObj } ); Object.entries(entityCache).forEach(([key, workloadSchema]) => addKubernetesEntitySchema(key, workloadSchema)); diff --git a/custom-src/frontend/app/custom/kubernetes/workloads/store/workloads-entity-generator.ts b/custom-src/frontend/app/custom/kubernetes/workloads/store/workloads-entity-generator.ts index 3f326da1ed..f4a0939afa 100644 --- a/custom-src/frontend/app/custom/kubernetes/workloads/store/workloads-entity-generator.ts +++ b/custom-src/frontend/app/custom/kubernetes/workloads/store/workloads-entity-generator.ts @@ -1,12 +1,20 @@ -import { StratosEndpointExtensionDefinition } from 'frontend/packages/store/src/entity-catalog/entity-catalog.types'; -import { IFavoriteMetadata } from 'frontend/packages/store/src/types/user-favorites.types'; - import { StratosBaseCatalogEntity, StratosCatalogEntity, } from '../../../../../../store/src/entity-catalog/entity-catalog-entity/entity-catalog-entity'; +import { StratosEndpointExtensionDefinition } from '../../../../../../store/src/entity-catalog/entity-catalog.types'; +import { IFavoriteMetadata } from '../../../../../../store/src/types/user-favorites.types'; import { kubernetesEntityFactory } from '../../kubernetes-entity-factory'; import { HelmRelease, HelmReleaseGraph, HelmReleaseResource } from '../workload.types'; +import { workloadsEntityCatalog } from '../workloads-entity-catalog'; +import { + WorkloadGraphBuilders, + workloadGraphBuilders, + WorkloadReleaseBuilders, + workloadReleaseBuilders, + WorkloadResourceBuilders, + workloadResourceBuilders, +} from './workload-action-builders'; import { helmReleaseEntityKey, helmReleaseGraphEntityType, helmReleaseResourceEntityType } from './workloads-entity-factory'; @@ -18,14 +26,19 @@ export function generateWorkloadsEntities(endpointDefinition: StratosEndpointExt ]; } - function generateReleaseEntity(endpointDefinition: StratosEndpointExtensionDefinition) { const definition = { type: helmReleaseEntityKey, schema: kubernetesEntityFactory(helmReleaseEntityKey), endpoint: endpointDefinition }; - return new StratosCatalogEntity(definition); + workloadsEntityCatalog.release = new StratosCatalogEntity( + definition, + { + actionBuilders: workloadReleaseBuilders + } + ); + return workloadsEntityCatalog.release; } function generateReleaseGraphEntity(endpointDefinition: StratosEndpointExtensionDefinition) { @@ -34,7 +47,13 @@ function generateReleaseGraphEntity(endpointDefinition: StratosEndpointExtension schema: kubernetesEntityFactory(helmReleaseGraphEntityType), endpoint: endpointDefinition }; - return new StratosCatalogEntity(definition); + workloadsEntityCatalog.graph = new StratosCatalogEntity( + definition, + { + actionBuilders: workloadGraphBuilders + } + ); + return workloadsEntityCatalog.graph; } function generateReleaseResourceEntity(endpointDefinition: StratosEndpointExtensionDefinition) { @@ -43,6 +62,12 @@ function generateReleaseResourceEntity(endpointDefinition: StratosEndpointExtens schema: kubernetesEntityFactory(helmReleaseResourceEntityType), endpoint: endpointDefinition }; - return new StratosCatalogEntity(definition); + workloadsEntityCatalog.resource = new StratosCatalogEntity( + definition, + { + actionBuilders: workloadResourceBuilders + } + ); + return workloadsEntityCatalog.resource; } diff --git a/custom-src/frontend/app/custom/kubernetes/workloads/store/workloads.actions.ts b/custom-src/frontend/app/custom/kubernetes/workloads/store/workloads.actions.ts index 92818a4800..319ef74b8b 100644 --- a/custom-src/frontend/app/custom/kubernetes/workloads/store/workloads.actions.ts +++ b/custom-src/frontend/app/custom/kubernetes/workloads/store/workloads.actions.ts @@ -1,6 +1,6 @@ -import { Action } from '@ngrx/store'; import { EntityRequestAction } from 'frontend/packages/store/src/types/request.types'; +import { PaginatedAction } from '../../../../../../store/src/types/pagination.types'; import { MonocularPaginationAction } from '../../../helm/store/helm.actions'; import { KUBERNETES_ENDPOINT_TYPE, @@ -8,7 +8,15 @@ import { kubernetesPodsEntityType, kubernetesServicesEntityType, } from '../../kubernetes-entity-factory'; -import { helmReleaseEntityKey, helmReleaseGraphEntityType, helmReleaseResourceEntityType } from './workloads-entity-factory'; +import { KubePaginationAction } from '../../store/kubernetes.actions'; +import { + getHelmReleaseGraphId, + getHelmReleaseId, + getHelmReleaseResourceId, + helmReleaseEntityKey, + helmReleaseGraphEntityType, + helmReleaseResourceEntityType, +} from './workloads-entity-factory'; export const GET_HELM_RELEASES = '[Helm] Get Releases'; export const GET_HELM_RELEASES_SUCCESS = '[Helm] Get Releases Success'; @@ -30,6 +38,14 @@ export const UPDATE_HELM_RELEASE = '[Helm] Update Release'; export const UPDATE_HELM_RELEASE_SUCCESS = '[Helm] Update Release Success'; export const UPDATE_HELM_RELEASE_FAILURE = '[Helm] Update Release Failure'; +interface HelmReleaseSingleEntity extends EntityRequestAction { + guid: string; +} + +interface HelmReleasePaginated extends PaginatedAction, EntityRequestAction { + +} + export class GetHelmReleases implements MonocularPaginationAction { constructor() { this.paginationKey = 'helm-releases'; @@ -50,14 +66,15 @@ export class GetHelmReleases implements MonocularPaginationAction { }; } -export class GetHelmRelease implements EntityRequestAction { + +export class GetHelmRelease implements HelmReleaseSingleEntity { guid: string; constructor( public endpointGuid: string, public namespace: string, public releaseTitle: string ) { - this.guid = `${endpointGuid}:${namespace}:${releaseTitle}`; + this.guid = getHelmReleaseId(endpointGuid, namespace, releaseTitle); } type = GET_HELM_RELEASE; endpointType = KUBERNETES_ENDPOINT_TYPE; @@ -70,13 +87,13 @@ export class GetHelmRelease implements EntityRequestAction { ]; } -export class GetHelmReleaseGraph implements EntityRequestAction { +export class GetHelmReleaseGraph implements HelmReleaseSingleEntity { guid: string; constructor( public endpointGuid: string, public releaseTitle: string ) { - this.guid = `${endpointGuid}-${releaseTitle}`; + this.guid = getHelmReleaseGraphId(endpointGuid, releaseTitle); } type = this.constructor.name; endpointType = KUBERNETES_ENDPOINT_TYPE; @@ -85,30 +102,30 @@ export class GetHelmReleaseGraph implements EntityRequestAction { actions = [this.type]; } -export class GetHelmReleaseResource implements EntityRequestAction { - guid: string; +export class GetHelmReleaseResource implements HelmReleaseSingleEntity { constructor( public endpointGuid: string, public releaseTitle: string ) { - this.guid = `${endpointGuid}-${releaseTitle}`; + this.guid = getHelmReleaseResourceId(this.endpointGuid, this.releaseTitle); } type = this.constructor.name; endpointType = KUBERNETES_ENDPOINT_TYPE; entity = kubernetesEntityFactory(helmReleaseResourceEntityType); entityType = helmReleaseResourceEntityType; actions = [this.type]; + guid: string; } /** * Won't fetch pods, used to push/retrieve data from store */ -export class GetHelmReleasePods implements MonocularPaginationAction { +export class GetHelmReleasePods implements KubePaginationAction { constructor( - public endpointGuid: string, + public kubeGuid: string, public releaseTitle: string ) { - this.paginationKey = `${endpointGuid}/${releaseTitle}/pods`; + this.paginationKey = `${kubeGuid}/${releaseTitle}/pods`; } type = GET_HELM_RELEASE_PODS; endpointType = KUBERNETES_ENDPOINT_TYPE; @@ -124,17 +141,19 @@ export class GetHelmReleasePods implements MonocularPaginationAction { 'order-direction': 'desc', 'order-direction-field': 'name', }; + flattenPagination = true; } + /** - * Won't fetch pods, used to push/retrieve data from store + * Won't fetch services, used to push/retrieve data from store */ -export class GetHelmReleaseServices implements MonocularPaginationAction { +export class GetHelmReleaseServices implements KubePaginationAction { constructor( - public endpointGuid: string, + public kubeGuid: string, public releaseTitle: string ) { - this.paginationKey = `${endpointGuid}/${releaseTitle}/services`; + this.paginationKey = `${kubeGuid}/${releaseTitle}/services`; } type = GET_HELM_RELEASE_SERVICES; endpointType = KUBERNETES_ENDPOINT_TYPE; @@ -150,9 +169,5 @@ export class GetHelmReleaseServices implements MonocularPaginationAction { 'order-direction': 'desc', 'order-direction-field': 'name', }; -} - -export class HelmUpdateRelease implements Action { - constructor(public values: any) { } - type = UPDATE_HELM_RELEASE; + flattenPagination = true; } diff --git a/custom-src/frontend/app/custom/kubernetes/workloads/store/workloads.effects.ts b/custom-src/frontend/app/custom/kubernetes/workloads/store/workloads.effects.ts index 086bc29fd8..ea7add12fe 100644 --- a/custom-src/frontend/app/custom/kubernetes/workloads/store/workloads.effects.ts +++ b/custom-src/frontend/app/custom/kubernetes/workloads/store/workloads.effects.ts @@ -15,7 +15,9 @@ import { WrapperRequestActionFailed, WrapperRequestActionSuccess, } from '../../../../../../store/src/types/request.types'; +import { HelmEffects } from '../../../helm/store/helm.effects'; import { HelmRelease } from '../workload.types'; +import { getHelmReleaseId } from './workloads-entity-factory'; import { GET_HELM_RELEASE, GET_HELM_RELEASES, GetHelmRelease, GetHelmReleases } from './workloads.actions'; @Injectable() @@ -48,7 +50,7 @@ export class WorkloadsEffects { return; } endpointData.forEach((data) => { - const helmRelease = this.mapHelmRelease(data, endpointId); + const helmRelease = this.mapHelmRelease(data, endpointId, getHelmReleaseId(endpointId, data.namespace, data.name)); processedData.entities[entityKey][helmRelease.guid] = helmRelease; processedData.result.push(helmRelease.guid); }); @@ -73,20 +75,20 @@ export class WorkloadsEffects { } as NormalizedResponse; // Go through each endpoint ID - processedData.entities[entityKey][action.guid] = this.mapHelmRelease(response, action.endpointGuid); + processedData.entities[entityKey][action.guid] = this.mapHelmRelease(response, action.endpointGuid, action.guid); processedData.result.push(action.guid); return processedData; }, [action.endpointGuid]); }) ); - private mapHelmRelease(data, endpointId) { + private mapHelmRelease(data, endpointId, guid: string) { const helmRelease: HelmRelease = { ...data, endpointId }; // Release name is unique for an endpoint - for Helm 3, include the namespace - helmRelease.guid = endpointId + ':' + data.namespace + ':' + data.name; + helmRelease.guid = guid; // Make a note of the guid of the endpoint for the release helmRelease.status = data.info.status; helmRelease.lastDeployed = this.mapHelmModifiedDate(data.info.last_deployed); @@ -107,15 +109,19 @@ export class WorkloadsEffects { }; return this.httpClient.get(url, requestArgs).pipe( mergeMap((response: any) => [new WrapperRequestActionSuccess(mapResult(response), action)]), - catchError(error => [ - new WrapperRequestActionFailed(error.message, action, 'fetch', { - endpointIds, - url: error.url || url, - eventCode: error.status ? error.status + '' : '500', - message: 'Helm Release API request error', - error - }) - ]) + catchError(error => { + const { status, message } = HelmEffects.createHelmError(error); + const errorMessage = `Failed to fetch helm data: ${message}`; + return [ + new WrapperRequestActionFailed(errorMessage, action, 'fetch', { + endpointIds, + url: error.url || url, + eventCode: status, + message: errorMessage, + error + }) + ] + }) ); } diff --git a/custom-src/frontend/app/custom/kubernetes/workloads/workload.types.ts b/custom-src/frontend/app/custom/kubernetes/workloads/workload.types.ts index b0394359ab..f91220bad4 100644 --- a/custom-src/frontend/app/custom/kubernetes/workloads/workload.types.ts +++ b/custom-src/frontend/app/custom/kubernetes/workloads/workload.types.ts @@ -1,7 +1,6 @@ import { Injectable } from '@angular/core'; -import { Observable } from 'rxjs'; -import { KubeService } from '../store/kube.types'; +import { KubernetesPod, KubeService } from '../store/kube.types'; export interface HelmRelease { endpointId: string; @@ -27,28 +26,16 @@ export interface HelmRelease { }; } -export interface HelmReleasePod { +export interface HelmReleaseEntity { endpointId: string; releaseTitle: string; - name: string; - ready: string; - status: string; - restarts: string; - age: string; } -export interface HelmReleaseService { - endpointId: string; - releaseTitle: string; - name: string; - kubeService$?: Observable; - metadata: any; - spec: any; -} +export interface HelmReleasePod extends HelmReleaseEntity, KubernetesPod { } -export interface HelmReleaseGraph { - endpointId: string; - releaseTitle: string; +export interface HelmReleaseService extends HelmReleaseEntity, KubeService { } + +export interface HelmReleaseGraph extends HelmReleaseEntity { nodes: {}; links: {}; } diff --git a/custom-src/frontend/app/custom/kubernetes/workloads/workloads-entity-catalog.ts b/custom-src/frontend/app/custom/kubernetes/workloads/workloads-entity-catalog.ts new file mode 100644 index 0000000000..06d3a33c04 --- /dev/null +++ b/custom-src/frontend/app/custom/kubernetes/workloads/workloads-entity-catalog.ts @@ -0,0 +1,20 @@ +import { StratosCatalogEntity } from '../../../../../store/src/entity-catalog/entity-catalog-entity/entity-catalog-entity'; +import { IFavoriteMetadata } from '../../../../../store/src/types/user-favorites.types'; +import { WorkloadGraphBuilders, WorkloadReleaseBuilders, WorkloadResourceBuilders } from './store/workload-action-builders'; +import { HelmRelease, HelmReleaseGraph, HelmReleaseResource } from './workload.types'; + +/** + * A strongly typed collection of Workload Catalog Entities. + * This can be used to access functionality exposed by each specific type, such as get, update, delete, etc + */ +export class WorkloadsEntityCatalog { + release: StratosCatalogEntity; + graph: StratosCatalogEntity + resource: StratosCatalogEntity +} + +/** + * A strongly typed collection of Workload Catalog Entities. + * This can be used to access functionality exposed by each specific type, such as get, update, delete, etc + */ +export const workloadsEntityCatalog: WorkloadsEntityCatalog = new WorkloadsEntityCatalog(); diff --git a/src/frontend/packages/cf-autoscaler/src/shared/list-types/app-autoscaler-metric-chart/app-autoscaler-metric-chart-card/app-autoscaler-metric-chart-card.component.spec.ts b/src/frontend/packages/cf-autoscaler/src/shared/list-types/app-autoscaler-metric-chart/app-autoscaler-metric-chart-card/app-autoscaler-metric-chart-card.component.spec.ts index 1061670864..7f0a6a1cbf 100644 --- a/src/frontend/packages/cf-autoscaler/src/shared/list-types/app-autoscaler-metric-chart/app-autoscaler-metric-chart-card/app-autoscaler-metric-chart-card.component.spec.ts +++ b/src/frontend/packages/cf-autoscaler/src/shared/list-types/app-autoscaler-metric-chart/app-autoscaler-metric-chart-card/app-autoscaler-metric-chart-card.component.spec.ts @@ -26,8 +26,6 @@ import { AppAutoscalerMetricChartCardComponent } from './app-autoscaler-metric-c import { AppAutoscalerComboChartComponent } from './combo-chart/combo-chart.component'; import { AppAutoscalerComboSeriesVerticalComponent } from './combo-chart/combo-series-vertical.component'; -/* tslint:disable:max-line-length */ -/* tslint:enable:max-line-length */ describe('AppAutoscalerMetricChartCardComponent', () => { let component: AppAutoscalerMetricChartCardComponent; diff --git a/src/frontend/packages/cf-autoscaler/src/shared/list-types/app-autoscaler-metric-chart/app-autoscaler-metric-chart-list-config.service.spec.ts b/src/frontend/packages/cf-autoscaler/src/shared/list-types/app-autoscaler-metric-chart/app-autoscaler-metric-chart-list-config.service.spec.ts index 383469b8a8..4c6669fe61 100644 --- a/src/frontend/packages/cf-autoscaler/src/shared/list-types/app-autoscaler-metric-chart/app-autoscaler-metric-chart-list-config.service.spec.ts +++ b/src/frontend/packages/cf-autoscaler/src/shared/list-types/app-autoscaler-metric-chart/app-autoscaler-metric-chart-list-config.service.spec.ts @@ -18,9 +18,6 @@ import { PaginationMonitorFactory } from '../../../../../store/src/monitors/pagi import { CfAutoscalerTestingModule } from '../../../cf-autoscaler-testing.module'; import { AppAutoscalerMetricChartListConfigService } from './app-autoscaler-metric-chart-list-config.service'; -/* tslint:disable:max-line-length */ - -/* tslint:enable:max-line-length */ describe('AppAutoscalerMetricChartListConfigService', () => { beforeEach(() => { diff --git a/src/frontend/packages/cloud-foundry/src/actions/buildpack.action.ts b/src/frontend/packages/cloud-foundry/src/actions/buildpack.action.ts index 8fe4445485..d7a40dee9d 100644 --- a/src/frontend/packages/cloud-foundry/src/actions/buildpack.action.ts +++ b/src/frontend/packages/cloud-foundry/src/actions/buildpack.action.ts @@ -1,9 +1,10 @@ +import { HttpRequest } from '@angular/common/http'; + import { getActions } from '../../../store/src/actions/action.helper'; import { PaginatedAction } from '../../../store/src/types/pagination.types'; import { cfEntityFactory } from '../cf-entity-factory'; import { buildpackEntityType } from '../cf-entity-types'; import { CFStartAction } from './cf-action.types'; -import { HttpRequest } from '@angular/common/http'; export class FetchAllBuildpacks extends CFStartAction implements PaginatedAction { constructor(public endpointGuid: string, public paginationKey: string) { diff --git a/src/frontend/packages/cloud-foundry/src/actions/domains.actions.ts b/src/frontend/packages/cloud-foundry/src/actions/domains.actions.ts index 6d56f47d8d..13d4f6d59b 100644 --- a/src/frontend/packages/cloud-foundry/src/actions/domains.actions.ts +++ b/src/frontend/packages/cloud-foundry/src/actions/domains.actions.ts @@ -1,3 +1,5 @@ +import { HttpRequest } from '@angular/common/http'; + import { endpointSchemaKey } from '../../../store/src/helpers/entity-factory'; import { PaginatedAction } from '../../../store/src/types/pagination.types'; import { ICFAction } from '../../../store/src/types/request.types'; @@ -5,7 +7,6 @@ import { cfEntityFactory } from '../cf-entity-factory'; import { domainEntityType } from '../cf-entity-types'; import { createEntityRelationPaginationKey } from '../entity-relations/entity-relations.types'; import { CFStartAction } from './cf-action.types'; -import { HttpRequest } from '@angular/common/http'; export const GET_DOMAIN = '[domain] Get domain '; export const GET_DOMAIN_SUCCESS = '[domain] Get domain success'; diff --git a/src/frontend/packages/cloud-foundry/src/actions/relation.actions.ts b/src/frontend/packages/cloud-foundry/src/actions/relation.actions.ts index 1d8e1129fd..b0d2154801 100644 --- a/src/frontend/packages/cloud-foundry/src/actions/relation.actions.ts +++ b/src/frontend/packages/cloud-foundry/src/actions/relation.actions.ts @@ -1,13 +1,11 @@ +import { HttpParams, HttpRequest } from '@angular/common/http'; + import { EntityCatalogEntityConfig } from '../../../store/src/entity-catalog/entity-catalog.types'; -import { - EntityInlineChildAction, - EntityInlineParentAction, -} from '../entity-relations/entity-relations.types'; import { PaginatedAction } from '../../../store/src/types/pagination.types'; -import { RequestEntityLocation, RequestActionEntity } from '../../../store/src/types/request.types'; -import { CFStartAction } from './cf-action.types'; +import { RequestActionEntity, RequestEntityLocation } from '../../../store/src/types/request.types'; import { EntityTreeRelation } from '../entity-relations/entity-relation-tree'; -import { HttpRequest, HttpParams } from '@angular/common/http'; +import { EntityInlineChildAction, EntityInlineParentAction } from '../entity-relations/entity-relations.types'; +import { CFStartAction } from './cf-action.types'; const relationActionId = 'FetchRelationAction'; diff --git a/src/frontend/packages/cloud-foundry/src/actions/security-groups-actions.ts b/src/frontend/packages/cloud-foundry/src/actions/security-groups-actions.ts index 1930e67071..8d882c6a44 100644 --- a/src/frontend/packages/cloud-foundry/src/actions/security-groups-actions.ts +++ b/src/frontend/packages/cloud-foundry/src/actions/security-groups-actions.ts @@ -1,10 +1,11 @@ +import { HttpRequest } from '@angular/common/http'; + import { getActions } from '../../../store/src/actions/action.helper'; import { PaginatedAction } from '../../../store/src/types/pagination.types'; import { cfEntityFactory } from '../cf-entity-factory'; import { securityGroupEntityType, spaceEntityType } from '../cf-entity-types'; import { createEntityRelationKey, EntityInlineParentAction } from '../entity-relations/entity-relations.types'; import { CFStartAction } from './cf-action.types'; -import { HttpRequest } from '@angular/common/http'; export class GetAllSecurityGroups extends CFStartAction implements PaginatedAction, EntityInlineParentAction { constructor( diff --git a/src/frontend/packages/cloud-foundry/src/actions/service-bindings.actions.ts b/src/frontend/packages/cloud-foundry/src/actions/service-bindings.actions.ts index d0a2763cfb..cd7763a255 100644 --- a/src/frontend/packages/cloud-foundry/src/actions/service-bindings.actions.ts +++ b/src/frontend/packages/cloud-foundry/src/actions/service-bindings.actions.ts @@ -1,10 +1,11 @@ +import { HttpParams, HttpRequest } from '@angular/common/http'; + import { getActions } from '../../../store/src/actions/action.helper'; import { PaginatedAction, PaginationParam } from '../../../store/src/types/pagination.types'; import { ICFAction } from '../../../store/src/types/request.types'; import { cfEntityFactory } from '../cf-entity-factory'; import { serviceBindingEntityType } from '../cf-entity-types'; import { CFStartAction } from './cf-action.types'; -import { HttpRequest, HttpParams } from '@angular/common/http'; export const DELETE_SERVICE_BINDING_ACTION = '[ Service Instances ] Delete Service Binding'; export const DELETE_SERVICE_BINDING_ACTION_SUCCESS = '[ Service Instances ] Delete Service Binding success'; diff --git a/src/frontend/packages/cloud-foundry/src/actions/service-broker.actions.ts b/src/frontend/packages/cloud-foundry/src/actions/service-broker.actions.ts index a598c73a26..5dfefc6e7b 100644 --- a/src/frontend/packages/cloud-foundry/src/actions/service-broker.actions.ts +++ b/src/frontend/packages/cloud-foundry/src/actions/service-broker.actions.ts @@ -1,10 +1,11 @@ +import { HttpRequest } from '@angular/common/http'; + import { getActions } from '../../../store/src/actions/action.helper'; import { PaginatedAction } from '../../../store/src/types/pagination.types'; import { EntityRequestAction } from '../../../store/src/types/request.types'; import { cfEntityFactory } from '../cf-entity-factory'; import { serviceBrokerEntityType } from '../cf-entity-types'; import { CFStartAction } from './cf-action.types'; -import { HttpRequest } from '@angular/common/http'; export class GetServiceBrokers extends CFStartAction implements PaginatedAction { constructor( diff --git a/src/frontend/packages/cloud-foundry/src/actions/service-plan-visibility.actions.ts b/src/frontend/packages/cloud-foundry/src/actions/service-plan-visibility.actions.ts index 34e8b3dde4..42adf48a73 100644 --- a/src/frontend/packages/cloud-foundry/src/actions/service-plan-visibility.actions.ts +++ b/src/frontend/packages/cloud-foundry/src/actions/service-plan-visibility.actions.ts @@ -1,3 +1,5 @@ +import { HttpRequest } from '@angular/common/http'; + import { getActions } from '../../../store/src/actions/action.helper'; import { PaginatedAction } from '../../../store/src/types/pagination.types'; import { cfEntityFactory } from '../cf-entity-factory'; @@ -9,7 +11,6 @@ import { } from '../cf-entity-types'; import { createEntityRelationKey } from '../entity-relations/entity-relations.types'; import { CFStartAction } from './cf-action.types'; -import { HttpRequest } from '@angular/common/http'; export class GetServicePlanVisibilities extends CFStartAction implements PaginatedAction { constructor( diff --git a/src/frontend/packages/cloud-foundry/src/actions/service-plan.actions.ts b/src/frontend/packages/cloud-foundry/src/actions/service-plan.actions.ts index d12c5e0ee3..a7b2621cda 100644 --- a/src/frontend/packages/cloud-foundry/src/actions/service-plan.actions.ts +++ b/src/frontend/packages/cloud-foundry/src/actions/service-plan.actions.ts @@ -1,3 +1,5 @@ +import { HttpRequest } from '@angular/common/http'; + import { getActions } from '../../../store/src/actions/action.helper'; import { PaginatedAction } from '../../../store/src/types/pagination.types'; import { cfEntityFactory } from '../cf-entity-factory'; @@ -12,7 +14,6 @@ import { } from '../cf-entity-types'; import { createEntityRelationKey } from '../entity-relations/entity-relations.types'; import { CFStartAction } from './cf-action.types'; -import { HttpRequest } from '@angular/common/http'; export class GetServicePlanServiceInstances extends CFStartAction implements PaginatedAction { constructor( diff --git a/src/frontend/packages/core/sass/components/mat-table.scss b/src/frontend/packages/core/sass/components/mat-table.scss index 6eef03a63d..c623288894 100644 --- a/src/frontend/packages/core/sass/components/mat-table.scss +++ b/src/frontend/packages/core/sass/components/mat-table.scss @@ -16,10 +16,18 @@ $mat-table-header-paginator-font-size: 13px; padding: 10px 10px 10px 0; } - // Use margin, not padding for the left side of the first cell in the row/header/footer - .mat-cell:first-of-type, mat-footer-cell:first-of-type, mat-header-cell:first-of-type { - margin-left: 20px; - padding-left: 0; + .app-table { + // Use margin, not padding for the left side of the first cell in the row/header/footer + .mat-cell:first-of-type, mat-footer-cell:first-of-type, mat-header-cell:first-of-type { + margin-left: 20px; + padding-left: 0; + } + .has-expanded-row { + // Override the margin-left from above, there's a lot of white space going on + .mat-cell:first-of-type, mat-footer-cell:first-of-type, mat-header-cell:first-of-type { + margin-left: 10px; + } + } } // Use margin, not padding for the right side of the first cell in the row/header/footer diff --git a/src/frontend/packages/core/src/features/endpoints/backup-restore/backup-endpoints/backup-endpoints.component.html b/src/frontend/packages/core/src/features/endpoints/backup-restore/backup-endpoints/backup-endpoints.component.html index bfbec70bda..b86b52acc0 100644 --- a/src/frontend/packages/core/src/features/endpoints/backup-restore/backup-endpoints/backup-endpoints.component.html +++ b/src/frontend/packages/core/src/features/endpoints/backup-restore/backup-endpoints/backup-endpoints.component.html @@ -14,7 +14,9 @@

Backup Endpoints

- + +

There are no endpoints to backup

diff --git a/src/frontend/packages/core/src/features/metrics/metrics/metrics.component.html b/src/frontend/packages/core/src/features/metrics/metrics/metrics.component.html index 6407fa952b..d1558f2b9d 100644 --- a/src/frontend/packages/core/src/features/metrics/metrics/metrics.component.html +++ b/src/frontend/packages/core/src/features/metrics/metrics/metrics.component.html @@ -24,11 +24,11 @@

-
    -
  • - +
      +
    • + - +
      {{info.icon.name }}
- - + \ No newline at end of file diff --git a/src/frontend/packages/store/src/selectors/endpoint.selectors.ts b/src/frontend/packages/store/src/selectors/endpoint.selectors.ts index 0400350b59..cfcd00d4c9 100644 --- a/src/frontend/packages/store/src/selectors/endpoint.selectors.ts +++ b/src/frontend/packages/store/src/selectors/endpoint.selectors.ts @@ -61,10 +61,6 @@ export const endpointsCFEntitiesSelector = createSelector( cfEndpointEntitiesSelector ); -// const log = (label) => { -// return (val) => console.log(label, val); -// }; - // TODO: Move this #3769 export const endpointsCfEntitiesConnectedSelector = connectedEndpointsOfTypesSelector('cf'); diff --git a/src/frontend/packages/store/src/types/request.types.ts b/src/frontend/packages/store/src/types/request.types.ts index 1e14568f76..e1b855210c 100644 --- a/src/frontend/packages/store/src/types/request.types.ts +++ b/src/frontend/packages/store/src/types/request.types.ts @@ -1,9 +1,9 @@ import { HttpRequest } from '@angular/common/http'; import { Action } from '@ngrx/store'; +import { ApiActionTypes, RequestTypes } from '../actions/request.actions'; import { BasePipelineRequestAction } from '../entity-catalog/action-orchestrator/action-orchestrator'; import { EntityCatalogEntityConfig } from '../entity-catalog/entity-catalog.types'; -import { ApiActionTypes, RequestTypes } from '../actions/request.actions'; import { EntitySchema } from '../helpers/entity-schema'; import { ApiRequestTypes } from '../reducers/api-request-reducer/request-helpers'; import { NormalizedResponse } from './api.types';