Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optionally enable helm hub (disabled by default) #4643

Merged
merged 3 commits into from
Oct 8, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions deploy/kubernetes/console/templates/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,8 @@ spec:
value: "{{.Values.kube.registry.hostname}}/{{.Values.kube.organization}}/stratos-kube-terminal:{{.Values.consoleVersion}}"
- name: STRATOS_KUBERNETES_DASHBOARD_IMAGE
value: "{{.Values.console.kubeDashboardImage}}"
- name: HELM_HUB_ENABLED
value: {{ default "false" .Values.console.helmHubEnabled | quote }}
{{- include "stratosJetstreamEnv" . | indent 8 }}
readinessProbe:
httpGet:
Expand Down
3 changes: 3 additions & 0 deletions deploy/kubernetes/console/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,9 @@ console:
# Download link when installing the Kubernetes Dashboard in a targetted Kube Endpoint
kubeDashboardImage:

# Enable Helm Hub
helmHubEnabled: false

# Size for analysis reports volume
reportsVolumeSize: 1Gi

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Component } from '@angular/core';
import { Store } from '@ngrx/store';
import { Observable } from 'rxjs';
import { combineLatest, filter, first, map } from 'rxjs/operators';
import { combineLatest, Observable, of } from 'rxjs';
import { filter, first, map, switchMap } from 'rxjs/operators';

import { RouterNav } from '../../../../../../store/src/actions/router.actions';
import { GeneralEntityAppState } from '../../../../../../store/src/app-state';
Expand All @@ -21,10 +21,14 @@ interface ICreateEndpointTilesData extends ITileData {
parentType: string;
}

type EndpointsByType = {
[endpointType: string]: number,
type ExpandedEndpoint<T = number> = {
current: number,
limit: T;
definition: IStratosEndpointDefinition;
};

type ExpandedEndpoints<T = number> = ExpandedEndpoint<T>[];

@Component({
selector: 'app-create-endpoint-base-step',
templateUrl: './create-endpoint-base-step.component.html',
Expand Down Expand Up @@ -91,18 +95,24 @@ export class CreateEndpointBaseStepComponent {
}));
}
}
constructor(public store: Store<GeneralEntityAppState>,) {
constructor(public store: Store<GeneralEntityAppState>, ) {
// Need to filter the endpoint types on the tech preview flag
this.tileSelectorConfig$ = store.select(selectSessionData()).pipe(
combineLatest(this.getEndpointTypesByCount()),
// Get a list of all known endpoint types
map(sessionData => entityCatalog.getAllEndpointTypes(sessionData.config.enableTechPreview || false)),
// Add additional metadata to each endpoint type
switchMap(endpointTypes => this.expandEndpointTypes(endpointTypes)),
first(),
map(([sessionData, endpointTypesByCount]) => {
const techPreviewIsEnabled = sessionData.config.enableTechPreview || false;
return entityCatalog.getAllEndpointTypes(techPreviewIsEnabled)
.filter(endpoint => this.filterByEndpointCount(endpoint, endpointTypesByCount))
map(expandedEndpointTypes => {
// For each endpoint type...
return expandedEndpointTypes
// .. remove any that are over the types limit
.filter(expandedEndpointType => this.filterByEndpointCount(expandedEndpointType))
// .. sort
.sort((endpointA, endpointB) => this.sortEndpointTiles(endpointA.definition, endpointB.definition))
.map(catalogEndpoint => {
const endpoint = catalogEndpoint.definition;
// .. map into tile format
.map(expandedEndpointType => {
const endpoint = expandedEndpointType.definition;
return this.tileManager.getNextTileConfig<ICreateEndpointTilesData>(
endpoint.label,
endpoint.logoUrl ? {
Expand All @@ -118,42 +128,47 @@ export class CreateEndpointBaseStepComponent {
}
);
});
})
}),
);
}

private getEndpointDefinitionKey = (type: string, subType: string): string => type + '_sep_' + subType;
private getEndpointTypesByCount = (): Observable<EndpointsByType> =>
private expandEndpointTypes = (endpointEntities: StratosCatalogEndpointEntity[]): Observable<ExpandedEndpoints> =>
stratosEntityCatalog.endpoint.store.getAll.getPaginationService().entities$.pipe(
filter(endpoints => !!endpoints),
map(endpoints => {
const endpointsByType: { [endpointType: string]: number; } = {};
return endpoints.reduce((res, endpoint) => {
const type = this.getEndpointDefinitionKey(endpoint.cnsi_type, endpoint.sub_type);
if (!res[type]) {
res[type] = 0;
}
res[type]++;
const endpointsByType: ExpandedEndpoints<Observable<number>> = [];
return endpointEntities.reduce((res, endpointEntity) => {
const { type: endpointType, subType: endpointSubType } = endpointEntity.getTypeAndSubtype();
res.push({
current: endpoints.filter(em => em.cnsi_type === endpointType && em.sub_type === endpointSubType).length,
limit: this.getEndpointRegisteredLimit(endpointEntity),
definition: endpointEntity.definition
});
return res;
}, endpointsByType);
}),
switchMap(endpointsByType => combineLatest(Object.values(endpointsByType).map(type => type.limit.pipe(
map(limit => ({
...type,
limit
}))
)))),
);
private filterByEndpointCount = (endpoint: StratosCatalogEndpointEntity, endpointTypesByCount: EndpointsByType) => {
// No limit applied, always show endpoint
if (typeof endpoint.definition.registeredLimit !== 'number') {
return true;

private getEndpointRegisteredLimit(endpoint: StratosCatalogEndpointEntity): Observable<number> {
const registeredLimit = endpoint.definition.registeredLimit;
if (!registeredLimit) {
return of(Number.MAX_SAFE_INTEGER);
}
// Zero limit, never show endpoint
if (endpoint.definition.registeredLimit === 0) {
return false;
if (typeof registeredLimit === 'number') {
return of(registeredLimit);
}

const res = registeredLimit(this.store);
return typeof res === 'number' ? of(res) : res;
}
private filterByEndpointCount = (endpointType: ExpandedEndpoint): boolean => {
// Check that the limit is not exceeded by endpoints already registered
const type = endpoint.definition.parentType ?
this.getEndpointDefinitionKey(endpoint.definition.parentType, endpoint.definition.type) :
this.getEndpointDefinitionKey(endpoint.definition.type, '');
const count = endpointTypesByCount[type] || 0;
return count < endpoint.definition.registeredLimit;
return endpointType.current < endpointType.limit;
};

}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Store } from '@ngrx/store';
import { of } from 'rxjs';
import { catchError, first, map } from 'rxjs/operators';
import { Observable, of } from 'rxjs';
import { catchError, filter, first, map } from 'rxjs/operators';

import { IListAction } from '../../../core/src/shared/components/list/list.component.types';
import { AppState } from '../../../store/src/app-state';
Expand Down Expand Up @@ -41,7 +41,7 @@ export function generateHelmEntities(): StratosBaseCatalogEntity[] {
type: HELM_ENDPOINT_TYPE,
logoUrl: '/core/assets/custom/helm.svg',
authTypes: [],
registeredLimit: 0,
registeredLimit: () => 0,
icon: 'helm',
iconFont: 'stratos-icons',
label: 'Helm',
Expand Down Expand Up @@ -77,7 +77,7 @@ export function generateHelmEntities(): StratosBaseCatalogEntity[] {
}];
},
renderPriority: helmRepoRenderPriority,
registeredLimit: null,
registeredLimit: null, // Ensure this is null, otherwise inherits parent's value
},
{
type: HELM_HUB_ENDPOINT_TYPE,
Expand All @@ -88,7 +88,10 @@ export function generateHelmEntities(): StratosBaseCatalogEntity[] {
logoUrl: '/core/assets/custom/helm.svg',
renderPriority: helmRepoRenderPriority + 1,
registrationComponent: HelmHubRegistrationComponent,
registeredLimit: 1,
registeredLimit: (store: Store<AppState>): Observable<number> => store.select('auth').pipe(
filter(auth => !!auth.sessionData['plugin-config']),
map(auth => auth.sessionData['plugin-config'].helmHubEnabled === 'true' ? 1 : 0),
)
},
],
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ export interface IStratosEndpointDefinition<T = EntityCatalogSchemas | EntitySch
/**
* How many endpoints of this type can be registered, 0 - many
*/
readonly registeredLimit?: number;
readonly registeredLimit?: (store: Store<AppState>) => Observable<number> | number;
/**
* Indicates if this endpoint type is in tech preview and should only be shown when tech preview mode is enabled
*/
Expand Down
5 changes: 4 additions & 1 deletion src/jetstream/config.example
Original file line number Diff line number Diff line change
Expand Up @@ -76,4 +76,7 @@ INVITE_USER_CLIENT_SECRET=
# STRATOS_KUBERNETES_DASHBOARD_IMAGE=

# Cache folder for Helm Charts
# HELM_CACHE_FOLDER=./helm-cache
# HELM_CACHE_FOLDER=./helm-cache

# Enabled Helm Hub
HELM_HUB_ENABLED=false
21 changes: 21 additions & 0 deletions src/jetstream/plugins/monocular/20201007113503_RemoveHelmHub.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package monocular

import (
"database/sql"

"bitbucket.org/liamstask/goose/lib/goose"

"github.com/cloudfoundry-incubator/stratos/src/jetstream/datastore"
)

func init() {
datastore.RegisterMigration(20201007113503, "RemoveHelmHub", func(txn *sql.Tx, conf *goose.DBConf) error {
cleanCNSIS := "DELETE FROM cnsis WHERE guid IN (SELECT guid FROM cnsis WHERE cnsi_type='helm' AND sub_type='hub');"
_, err := txn.Exec(cleanCNSIS)
if err != nil {
return err
}

return nil
})
}
13 changes: 13 additions & 0 deletions src/jetstream/plugins/monocular/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ const (
kubeReleaseNameEnvVar = "STRATOS_HELM_RELEASE"
cacheFolderEnvVar = "HELM_CACHE_FOLDER"
defaultCacheFolder = "./.helm-cache"
helmHubEnabledEnvVar = "HELM_HUB_ENABLED"
helmHubEnabled = "helmHubEnabled"
)

// Monocular is a plugin for Monocular
Expand Down Expand Up @@ -59,6 +61,12 @@ func Init(portalProxy interfaces.PortalProxy) (interfaces.StratosPlugin, error)
func (m *Monocular) Init() error {
log.Debug("Monocular init .... ")

if val, ok := m.portalProxy.Env().Lookup(helmHubEnabledEnvVar); ok {
m.portalProxy.GetConfig().PluginConfig[helmHubEnabled] = val
} else {
m.portalProxy.GetConfig().PluginConfig[helmHubEnabled] = "false"
}

m.CacheFolder = m.portalProxy.Env().String(cacheFolderEnvVar, defaultCacheFolder)
folder, err := filepath.Abs(m.CacheFolder)
if err != nil {
Expand Down Expand Up @@ -288,6 +296,11 @@ func (m *Monocular) baseHandleMonocularInstance(c echo.Context, monocularEndpoin
log.Debug("baseHandleMonocularInstance")
// Generic proxy is handled last, after plugins.

if m.portalProxy.GetConfig().PluginConfig[helmHubEnabled] != "true" {
err := errors.New("Monocular forwarding is disabled")
return echo.NewHTTPError(http.StatusInternalServerError, err.Error())
}

if monocularEndpoint == nil {
err := errors.New("No monocular endpoint")
return echo.NewHTTPError(http.StatusBadRequest, err.Error())
Expand Down