Skip to content
This repository has been archived by the owner on Jan 24, 2023. It is now read-only.

Commit

Permalink
Add support for Helm Upgrade and history (#458)
Browse files Browse the repository at this point in the history
* Improve presentation and fix issue with development versions

* Add support for Helm Upgrade and Helm history

* Remove console logging

* Add comment

* Minor tweaks following self-review

* Remove debug logging

* Fix whitespace

* Minor tidy ups

* Fix compile issue

* Fix front-end unit tests

* Always show upgrade button

* Minor entity store type updates

* Address PR feedback

* Revert

* Remove description when checking for similar charts

* Only show button when the helm chart is available

Co-authored-by: Richard Cox <[email protected]>
  • Loading branch information
nwmac and richard-cox committed Sep 10, 2020
1 parent 3d4829d commit c44204a
Show file tree
Hide file tree
Showing 42 changed files with 1,318 additions and 118 deletions.
4 changes: 4 additions & 0 deletions src/frontend/packages/core/sass/mat-desktop.scss
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ $desktop-toggle-button-item-height: $desktop-menu-item-height - 2px;
font-size: $desktop-font-size;
}

.mat-slide-toggle-label {
font-size: $desktop-font-size;
}

// Allow a slightly-wider snackbar on desktop
.mat-snack-bar-container {
max-width: 40vw;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
<mat-select id="{{multiFilterManager.filterKey}}" matInput [(value)]="multiFilterManager.value"
[disabled]="!(multiFilterManager.filterIsReady$ | async)"
(selectionChange)="multiFilterManager.selectItem($event.value)">
<mat-option>{{ multiFilterManager.allLabel }}</mat-option>
<mat-option *ngIf="!multiFilterManager.hideAllOption">{{ multiFilterManager.allLabel }}</mat-option>
<mat-option *ngFor="let selectItem of multiFilterManager.filterItems$ | async"
[value]="selectItem.value">
{{selectItem.label}}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Injectable, Type } from '@angular/core';
import * as moment from 'moment';
import { BehaviorSubject, combineLatest, Observable, of as observableOf } from 'rxjs';
import { map, startWith } from 'rxjs/operators';
import { first, map, startWith } from 'rxjs/operators';

import { ListView } from '../../../../../store/src/actions/list.actions';
import { ActionState } from '../../../../../store/src/reducers/api-request-reducer/types';
Expand Down Expand Up @@ -130,9 +130,11 @@ export interface IListMultiFilterConfig {
key: string;
label: string;
allLabel?: string;
hideAllOption?: boolean;
list$: Observable<IListMultiFilterConfigItem[]>;
loading$: Observable<boolean>;
select: BehaviorSubject<any>;
autoSelectFirst?: boolean;
}

export interface IListFilter {
Expand Down Expand Up @@ -208,17 +210,28 @@ export class MultiFilterManager<T> {

public filterKey: string;
public allLabel: string;
public hideAllOption = false;

constructor(
public multiFilterConfig: IListMultiFilterConfig,
dataSource: IListDataSource<T>,
) {
this.filterKey = this.multiFilterConfig.key;
this.allLabel = multiFilterConfig.allLabel || 'All';
this.hideAllOption = multiFilterConfig.hideAllOption || false;
this.filterItems$ = this.getItemObservable(multiFilterConfig);
this.hasOneOrLessItems$ = this.filterItems$.pipe(map(items => items.length <= 1));
this.hasItems$ = this.filterItems$.pipe(map(items => !!items.length));
this.filterIsReady$ = this.getReadyObservable(multiFilterConfig, dataSource, this.hasItems$);

// Also select the first option if configured
if (multiFilterConfig.autoSelectFirst) {
this.filterItems$.pipe(first()).subscribe(options => {
if (options && options.length > 0) {
this.selectItem(options[0].value);
}
})
}
}

private getReadyObservable(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export interface StepOnNextResult {
data?: any;
}

export type StepOnNextFunction = () => Observable<StepOnNextResult>;
export type StepOnNextFunction = (index: number, step: StepComponent) => Observable<StepOnNextResult>;

@Component({
selector: 'app-step',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ export class SteppersComponent implements OnInit, AfterContentInit, OnDestroy {
if (this.currentIndex < this.steps.length) {
const step = this.steps[this.currentIndex];
step.busy = true;
const obs$ = step.onNext();
const obs$ = step.onNext(this.currentIndex, step);
if (!(obs$ instanceof Observable)) {
return;
}
Expand Down
2 changes: 2 additions & 0 deletions src/frontend/packages/suse-extensions/sass/_all-theme.scss
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
@import '../src/custom/kubernetes/tabs/kubernetes-analysis-tab/kubernetes-analysis-report/kubernetes-analysis-report.component.theme';
@import '../src/custom/kubernetes/tabs/kubernetes-analysis-tab/kubernetes-analysis-info/analysis-info-card/analysis-info-card.component.theme';
@import '../src/custom/helm/list-types/monocular-chart-card/monocular-chart-card.component.theme';
@import '../src/custom/kubernetes/workloads/release/tabs/helm-release-summary-tab/helm-release-summary-tab.component.theme';
@import '../src/custom/kubernetes/list-types/kubernetes-nodes/kubernetes-node-link/kubernetes-node-link.component.theme';

@mixin apply-theme-suse-extensions($stratos-theme) {
Expand All @@ -15,6 +16,7 @@
@include kube-analysis-report-theme($theme, $app-theme);
@include kube-analysis-card-theme($theme, $app-theme);
@include monocular-chart-card($theme, $app-theme);
@include helm-release-summary-tab-theme($theme, $app-theme);
@include kube-node-link-theme($theme, $app-theme);

}
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
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';
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, MonocularVersion } from './store/helm.types'; import { HelmChartActionBuilders, HelmVersionActionBuilders, HelmChartVersionsActionBuilders } 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<IFavoriteMetadata, MonocularChart, HelmChartActionBuilders>
version: StratosCatalogEntity<IFavoriteMetadata, HelmVersion, HelmVersionActionBuilders>
chart: StratosCatalogEntity<IFavoriteMetadata, MonocularChart, HelmChartActionBuilders>;
version: StratosCatalogEntity<IFavoriteMetadata, HelmVersion, HelmVersionActionBuilders>;
chartVersions: StratosCatalogEntity<IFavoriteMetadata, MonocularVersion[], HelmChartVersionsActionBuilders>;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { HelmVersion, MonocularChart } from './store/helm.types';

export const helmVersionsEntityType = 'helmVersions';
export const monocularChartsEntityType = 'monocularCharts';
export const monocularChartVersionsEntityType = 'monocularChartVersions';

export const getMonocularChartId = (entity: MonocularChart) => entity.id;
export const getHelmVersionId = (entity: HelmVersion) => entity.endpointId;
Expand Down Expand Up @@ -45,6 +46,12 @@ entityCache[helmVersionsEntityType] = new HelmEntitySchema(
{ idAttribute: getHelmVersionId }
);

entityCache[monocularChartVersionsEntityType] = new HelmEntitySchema(
monocularChartVersionsEntityType,
{},
{ idAttribute: getHelmVersionId }
);

export function helmEntityFactory(key: string): EntitySchema {
const entity = entityCache[key];
if (!entity) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,17 @@ import {
helmEntityFactory,
helmVersionsEntityType,
monocularChartsEntityType,
monocularChartVersionsEntityType,
} from './helm-entity-factory';
import {
HelmChartActionBuilders,
helmChartActionBuilders,
HelmChartVersionsActionBuilders,
helmChartVersionsActionBuilders,
HelmVersionActionBuilders,
helmVersionActionBuilders,
} from './store/helm.action-builders';
import { HelmVersion, MonocularChart } from './store/helm.types';
import { HelmVersion, MonocularChart, MonocularVersion } from './store/helm.types';


export function generateHelmEntities(): StratosBaseCatalogEntity[] {
Expand All @@ -35,10 +38,12 @@ export function generateHelmEntities(): StratosBaseCatalogEntity[] {
authTypes: [],
renderPriority: 10,
};

return [
generateEndpointEntity(endpointDefinition),
generateChartEntity(endpointDefinition),
generateVersionEntity(endpointDefinition),
generateChartVersionsEntity(endpointDefinition),
];
}

Expand Down Expand Up @@ -80,4 +85,19 @@ function generateVersionEntity(endpointDefinition: StratosEndpointExtensionDefin
return helmEntityCatalog.version;
}

function generateChartVersionsEntity(endpointDefinition: StratosEndpointExtensionDefinition) {
const definition = {
type: monocularChartVersionsEntityType,
schema: helmEntityFactory(monocularChartVersionsEntityType),
endpoint: endpointDefinition
};
helmEntityCatalog.chartVersions = new StratosCatalogEntity<IFavoriteMetadata, MonocularVersion[], HelmChartVersionsActionBuilders>(
definition,
{
actionBuilders: helmChartVersionsActionBuilders
}
);
return helmEntityCatalog.chartVersions;
}


Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { OrchestratedActionBuilders } from '../../../../../store/src/entity-catalog/action-orchestrator/action-orchestrator';
import { GetHelmVersions, GetMonocularCharts, HelmInstall } from './helm.actions';
import { GetHelmChartVersions, GetHelmVersions, GetMonocularCharts, HelmInstall } from './helm.actions';
import { HelmInstallValues } from './helm.types';

export interface HelmChartActionBuilders extends OrchestratedActionBuilders {
Expand All @@ -20,4 +20,12 @@ export interface HelmVersionActionBuilders extends OrchestratedActionBuilders {

export const helmVersionActionBuilders: HelmVersionActionBuilders = {
getMultiple: () => new GetHelmVersions()
}
}

export interface HelmChartVersionsActionBuilders extends OrchestratedActionBuilders {
getMultiple: (repoName: string, chartName: string) => GetHelmChartVersions
}

export const helmChartVersionsActionBuilders: HelmChartVersionsActionBuilders = {
getMultiple: (repoName: string, chartName: string) => new GetHelmChartVersions(repoName, chartName)
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,18 @@ import {
helmEntityFactory,
helmVersionsEntityType,
monocularChartsEntityType,
monocularChartVersionsEntityType,
} from '../helm-entity-factory';
import { HelmInstallValues } from './helm.types';

export const GET_MONOCULAR_CHARTS = '[Monocular] Get Charts';
export const GET_MONOCULAR_CHARTS_SUCCESS = '[Monocular] Get Charts Success';
export const GET_MONOCULAR_CHARTS_FAILURE = '[Monocular] Get Charts Failure';

export const GET_MONOCULAR_CHART_VERSIONS = '[Monocular] Get Chart Versions';
export const GET_MONOCULAR_CHART_VERSIONS_SUCCESS = '[Monocular] Get Chart Versions Success';
export const GET_MONOCULAR_CHART_VERSIONS_FAILURE = '[Monocular] Get Chart Versions Failure';

export const GET_HELM_VERSIONS = '[Helm] Get Versions';
export const GET_HELM_VERSIONS_SUCCESS = '[Helm] Get Versions Success';
export const GET_HELM_VERSIONS_FAILURE = '[Helm] Get Versions Failure';
Expand Down Expand Up @@ -73,3 +78,24 @@ export class GetHelmVersions implements MonocularPaginationAction {
};
flattenPagination = true;
}

export class GetHelmChartVersions implements MonocularPaginationAction {
constructor(public repoName: string, public chartName: string) {
this.paginationKey = `'monocular-chart-versions-${repoName}-${chartName}`;
}
type = GET_MONOCULAR_CHART_VERSIONS;
endpointType = HELM_ENDPOINT_TYPE;
entityType = monocularChartVersionsEntityType;
entity = [helmEntityFactory(monocularChartVersionsEntityType)];
actions = [
GET_MONOCULAR_CHART_VERSIONS,
GET_MONOCULAR_CHART_VERSIONS_SUCCESS,
GET_MONOCULAR_CHART_VERSIONS_FAILURE
];
paginationKey: string;
initialParams = {
'order-direction': 'asc',
'order-direction-field': 'version',
};
flattenPagination = true;
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ import { helmEntityCatalog } from '../helm-entity-catalog';
import { getHelmVersionId, getMonocularChartId, HELM_ENDPOINT_TYPE } from '../helm-entity-factory';
import {
GET_HELM_VERSIONS,
GET_MONOCULAR_CHART_VERSIONS,
GET_MONOCULAR_CHARTS,
GetHelmChartVersions,
GetHelmVersions,
GetMonocularCharts,
HELM_INSTALL,
Expand Down Expand Up @@ -128,6 +130,32 @@ export class HelmEffects {
})
);

@Effect()
fetchChartVersions$ = this.actions$.pipe(
ofType<GetHelmChartVersions>(GET_MONOCULAR_CHART_VERSIONS),
flatMap(action => {
const entityKey = entityCatalog.getEntityKey(action);
return this.makeRequest(action, `/pp/${this.proxyAPIVersion}/chartsvc/v1/charts/${action.repoName}/${action.chartName}/versions`,
(response) => {
const base = {
entities: { [entityKey]: {} },
result: []
} as NormalizedResponse;

const items = response.data as Array<any>;
const processedData = items.reduce((res, data) => {
const id = getMonocularChartId(data);
res.entities[entityKey][id] = data;
// Promote the name to the top-level object for simplicity
data.name = data.attributes.name;
res.result.push(id);
return res;
}, base);
return processedData;
}, []);
})
);

@Effect()
helmInstall$ = this.actions$.pipe(
ofType<HelmInstall>(HELM_INSTALL),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import { Chart } from './../monocular/shared/models/chart';
import { ChartVersion } from './../monocular/shared/models/chart-version';

export interface MonocularRepository {
name: string;
url: string;
Expand All @@ -7,26 +10,18 @@ export interface MonocularRepository {
status: string;
}

export interface MonocularChart {
id: string;
// Reuse types from the Monocular codebase
export interface MonocularChart extends Chart {
name: string;
attributes: {
description: string;
home: string;
icon: string;
keywords: string[];
repo: {
name: string;
url: string;
};
};
relationships: {
latestChartVersion: {
data: {
version: string
}
}
};
}

export type MonocularVersion = ChartVersion;

// Basic Chart Metadata
export interface ChartMetadata {
name: string;
description: string;
sources: string[];
}

export interface HelmVersion {
Expand All @@ -50,12 +45,19 @@ export enum HelmStatus {
Pending_Rollback = 8
}



export interface HelmInstallValues {
endpoint: string;
releaseName: string;
releaseNamespace: string;
values: string;
chart: string;
}

export interface HelmUpgradeValues {
chart: {
name: string;
repo: string;
version: string;
};
restartPods?: boolean;
}
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ export class HelmReleaseTabBaseComponent implements OnDestroy {
{ link: 'summary', label: 'Summary', icon: 'helm', iconFont: 'stratos-icons' },
{ link: 'notes', label: 'Notes', icon: 'subject' },
{ link: 'values', label: 'Values', icon: 'list' },
{ link: 'history', label: 'History', icon: 'schedule' },
{ link: 'analysis', label: 'Analysis', icon: 'assignment', hidden$: this.analysisService.hideAnalysis$ },
{ link: '-', label: 'Resources' },
{ link: 'graph', label: 'Overview', icon: 'share', hidden$: sessionService.isTechPreview().pipe(map(tp => !tp)) },
Expand Down
Loading

0 comments on commit c44204a

Please sign in to comment.