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

Add support for a Kubernetes Terminal #384

Merged
merged 55 commits into from
Jun 26, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
a138e47
Merge branch 'code-tidy-up' into v2-master
nwmac Jun 23, 2019
b795ca8
Cloud Console WIP
nwmac Jul 15, 2019
00a9047
Merge remote-tracking branch 'origin/v2-master' into cloud-console
nwmac Aug 30, 2019
fc2668b
Merge remote-tracking branch 'origin/master' into cloud-console
nwmac Mar 5, 2020
1bc727a
Remove debug and unused
nwmac Mar 5, 2020
187b999
Fix Anagular 8 upgrade issues
nwmac Mar 5, 2020
b5bf5ba
Tidy up imports
nwmac Mar 5, 2020
fac7061
Merge remote-tracking branch 'origin/master' into cloud-console
nwmac Apr 20, 2020
8c09aed
Fix misaligned user button
richard-cox May 28, 2020
4d33c4d
Temporarily add branch v3.2.1 to travis
richard-cox May 29, 2020
839cc2f
check sso whitelist in more places
bengerman13 May 21, 2020
28920c0
refactor sso state checks into single function
bengerman13 May 21, 2020
87c6bf8
Update version
richard-cox May 29, 2020
4ede977
First pass at changelog (additional SSO fix required)
richard-cox May 29, 2020
da89276
Merge pull request #4328 from cloudfoundry/sso-whitelist
richard-cox May 29, 2020
e970d88
Update changelog
richard-cox May 29, 2020
ca4f7be
Merge pull request #4329 from cloudfoundry/v3.2.1-release-notes
richard-cox May 29, 2020
798eed7
Merge remote-tracking branch 'origin/v3.2.1' into merge-v3.2.1
richard-cox Jun 1, 2020
80ad363
Fix package-lock.json
richard-cox Jun 1, 2020
36670d2
Remove v3.2.1 was .travis.taml
richard-cox Jun 1, 2020
9dab0de
Merge pull request #4337 from cloudfoundry/merge-v3.2.1
richard-cox Jun 1, 2020
6447b3b
Remove need for --recreate-pods when upgrading
nwmac Jun 1, 2020
dedfe8e
WIP: Kubernetes terminal
nwmac Jun 2, 2020
38952b2
Merge remote-tracking branch 'origin/merge-upstream' into helm-chart-…
nwmac Jun 2, 2020
19a6590
Merge remote-tracking branch 'upstream/helm-recreate-pods' into helm-…
nwmac Jun 2, 2020
ac76942
Add support for helm chart customizations
nwmac Jun 2, 2020
b8d170c
Merge remote-tracking branch 'upstream/helm-recreate-pods' into helm-…
nwmac Jun 2, 2020
799124c
Removed change not needed
nwmac Jun 2, 2020
f30c4a3
Merge remote-tracking branch 'upstream/helm-recreate-pods' into helm-…
nwmac Jun 2, 2020
7227dca
Apply recreate-pods fix to SUSE additional containers
nwmac Jun 2, 2020
76a13f5
Kubernetes Terminal updates and tidy up
nwmac Jun 3, 2020
891a8de
Detect kube version
nwmac Jun 3, 2020
b9f6fdc
Tidy up
nwmac Jun 3, 2020
b0c3ae9
Merge remote-tracking branch 'origin/helm-chart-updates' into kube-te…
nwmac Jun 3, 2020
dc394aa
Bug fixes and further tidy up
nwmac Jun 3, 2020
5899bfd
Fix backend logging issue
nwmac Jun 3, 2020
fc22125
Change log level to debug
nwmac Jun 3, 2020
1deac6d
Change some naming to kube terminal
nwmac Jun 4, 2020
0bb6325
Close stream
nwmac Jun 4, 2020
745ae4b
Run container as stratos user
nwmac Jun 4, 2020
108f3e2
Fix image build
nwmac Jun 4, 2020
7af08f2
Reanme docker file and add image to CI pipeline
nwmac Jun 4, 2020
b935ca4
Allow fork to add images to the imagelist file
nwmac Jun 8, 2020
04eec83
Merge remote-tracking branch 'origin/master' into kube-terminal
richard-cox Jun 12, 2020
da9610c
Fix issue where no config caused panic
richard-cox Jun 12, 2020
8c2fbb6
Merge remote-tracking branch 'origin/master' into kube-terminal
nwmac Jun 23, 2020
e798fc6
Indicate which commands are available
nwmac Jun 23, 2020
f34497f
Fix merge issue
nwmac Jun 23, 2020
53a4b2a
Remove commented-out code
nwmac Jun 23, 2020
817b729
Fix unit test compilation
nwmac Jun 23, 2020
3ec9362
Bug fix for when terminal is not enabled
nwmac Jun 24, 2020
16326d5
Only enable if tech preview is on
nwmac Jun 24, 2020
cd65b14
Add dev doc and helper setup script
nwmac Jun 24, 2020
cd0d6d6
Fix dev helper script
nwmac Jun 26, 2020
4c206ad
Address PR feedback
nwmac Jun 26, 2020
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
61 changes: 61 additions & 0 deletions build/tools/kube-terminal-dev.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
#!/usr/bin/env bash

# Colours
CYAN="\033[96m"
YELLOW="\033[93m"
RED="\033[91m"
RESET="\033[0m"
BOLD="\033[1m"

# Program Paths:
PROG=$(basename ${BASH_SOURCE[0]})
PROG_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
STRATOS_DIR="$( cd "${PROG_DIR}/../.." && pwd )"

echo "Creating Service Account"
SRC="${STRATOS_DIR}/deploy/kubernetes/console/templates/service-account.yaml"

TEMPFILE=$(mktemp)
cp $SRC $TEMPFILE
sed -i.bak '/\s*helm/d' $TEMPFILE
sed -i.bak '/\s*app\.kubernetes\.io\/version/d' $TEMPFILE
sed -i.bak '/\s*app\.kubernetes\.io\/instance/d' $TEMPFILE
sed -i.bak '/\s*{{-/d' $TEMPFILE

# Create a namespace
NS="stratos-dev"
kubectl get ns $NS > /dev/null 2>&1
if [ $? -ne 0 ]; then
kubectl create ns $NS
fi

kubectl apply -n $NS -f $TEMPFILE
USER=stratos-dev-admin-user
USER=stratos

# Service account should be created - now need to get token
SECRET=$(kubectl get -n $NS sa $USER -o json | jq -r '.secrets[0].name')
TOKEN=$(kubectl get -n $NS secret $SECRET -o json | jq -r '.data.token')
echo "Token secret: $SECRET"
TOKEN=$(echo $TOKEN | base64 -d -)
echo "Token $TOKEN"

rm -f $TEMPFILE
rm -f $TEMPFILE.bak

CFG=${STRATOS_DIR}/src/jetstream/config.properties
touch $CFG

echo -e "\n# Kubernetes Terminal Config for dev" >> $CFG
echo "STRATOS_KUBERNETES_NAMESPACE=stratos-dev" >> $CFG
echo "STRATOS_KUBERNETES_TERMINAL_IMAGE=splatform/stratos-kube-terminal:dev" >> $CFG
echo "KUBE_TERMINAL_SERVICE_ACCOUNT_TOKEN=$TOKEN" >> $CFG

MKUBE=$(minikube ip)
if [ $? -eq 0 ]; then
echo "KUBERNETES_SERVICE_HOST=$MKUBE" >> $CFG
echo "KUBERNETES_SERVICE_PORT=8443" >> $CFG
else
echo "KUBERNETES_SERVICE_HOST=" >> $CFG
echo "KUBERNETES_SERVICE_PORT=8443" >> $CFG
fi
4 changes: 4 additions & 0 deletions custom-src/deploy/kubernetes/__stratos.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,8 @@
value: "mongodb://{{ .Release.Name }}-fdbdoclayer:27016"
- name: SYNC_SERVER_URL
value: "http://{{ .Release.Name }}-chartsync:8080"
- name: STRATOS_KUBERNETES_NAMESPACE
value: "{{ .Release.Namespace }}"
- name: STRATOS_KUBERNETES_TERMINAL_IMAGE
value: "{{.Values.kube.registry.hostname}}/{{.Values.kube.organization}}/stratos-kube-terminal:{{.Values.consoleVersion}}"
{{- end }}
4 changes: 4 additions & 0 deletions custom-src/deploy/kubernetes/custom-build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,8 @@ function custom_image_build() {
# Build and push an image for the Helm Repo Sync Tool
log "-- Building/publishing Monocular Chart Repo Sync Tool"
patchAndPushImage stratos-chartsync Dockerfile "${STRATOS_PATH}/src/jetstream/plugins/monocular/chart-repo"

# Build and push an image for the Kubernetes Terminal
log "-- Building/publishing Kubernetes Terminal"
patchAndPushImage stratos-kube-terminal Dockerfile.kubeterminal "${STRATOS_PATH}/deploy/containers/kube-terminal"
}
6 changes: 5 additions & 1 deletion custom-src/deploy/kubernetes/customize-helm.sh
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ echo "Customizations folder: ${DIR}"
echo "Chart folder : ${CHART_PATH}"
echo ""

# ===========================================================================================
# Copy our customization helper over the default, empty one
# ===========================================================================================
cp "${DIR}/__stratos.tpl" "${CHART_PATH}/templates/__stratos.tpl"

# ===========================================================================================
# Chart.yaml changes
# ===========================================================================================
Expand Down Expand Up @@ -45,7 +50,6 @@ echo -e "${CYAN}Patching README.md${RESET}"
sed -i.bak -e 's@Stratos@SUSE Stratos Console@g' ${CHART_PATH}/README.md

# Change first paragraph to include Kubernetes
console for Cloud Foundry.
SRC="console for Cloud Foundry."
DEST="console for Cloud Foundry and Kubernetes."
sed -i.bak -e 's@'"${SRC}"'@'"${DEST}"'@g' ${CHART_PATH}/README.md
Expand Down
1 change: 1 addition & 0 deletions custom-src/deploy/kubernetes/imagelist.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
stratos-kube-terminal:_VERSION_
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<app-page-header [breadcrumbs]="breadcrumbs$ | async">
<h1>Kubernetes Terminal</h1>
<div class="page-header-right">
<span>
<button mat-icon-button matTooltip="Disconnect" name="stop" *ngIf="sshViewer.isConnected" (click)="sshViewer.disconnect()" [disabled]="sshViewer.attemptingConnection">
<mat-icon>stop</mat-icon>
</button>
<button mat-icon-button matTooltip="Connect" name="start" *ngIf="!sshViewer.isConnected" (click)="sshViewer.reconnect()" [disabled]="sshViewer.attemptingConnection">
<mat-icon>play_arrow</mat-icon>
</button>
<button mat-icon-button matTooltip="Back" [routerLink]="kubeSummaryLink">
<mat-icon>close</mat-icon>
</button>
</span>
</div>
</app-page-header>

<app-ssh-viewer #sshViewer [errorMessage]="errorMessage" [sshStream]="messages" [sshInput]="sshInput" [connectionStatus]="connectionStatus"></app-ssh-viewer>
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing';
import { createBasicStoreModule } from '@stratosui/store/testing';

import { ApplicationService } from '../../../../../cloud-foundry/src/features/applications/application.service';
import { ApplicationServiceMock } from '../../../../../cloud-foundry/test-framework/application-service-helper';
import { TabNavService } from '../../../../tab-nav.service';
import { CoreModule } from '../../../core/core.module';
import { SharedModule } from '../../../shared/shared.module';
import { KubeConsoleComponent } from './kube-console.component';

describe('KubeConsoleComponent', () => {
let component: KubeConsoleComponent;
let fixture: ComponentFixture<KubeConsoleComponent>;

beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [KubeConsoleComponent],
imports: [
CoreModule,
SharedModule,
RouterTestingModule,
createBasicStoreModule()
],
providers: [
{ provide: ApplicationService, useClass: ApplicationServiceMock },
TabNavService
],
})
.compileComponents();
}));

beforeEach(() => {
fixture = TestBed.createComponent(KubeConsoleComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import { Component, OnInit, ViewChild } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { NEVER, Observable, Subject, Subscription } from 'rxjs';
import websocketConnect, { normalClosureMessage } from 'rxjs-websockets';
import { catchError, tap, switchMap, map } from 'rxjs/operators';

import { IHeaderBreadcrumb } from '../../../shared/components/page-header/page-header.types';
import { SshViewerComponent } from '../../../shared/components/ssh-viewer/ssh-viewer.component';
import { KubernetesEndpointService } from '../services/kubernetes-endpoint.service';
import { BaseKubeGuid } from '../kubernetes-page.types';
import { KubernetesService } from '../services/kubernetes.service';


@Component({
selector: 'app-kube-console',
templateUrl: './kube-console.component.html',
styleUrls: ['./kube-console.component.scss'],
providers: [
{
provide: BaseKubeGuid,
useFactory: (activatedRoute: ActivatedRoute) => {
return {
guid: activatedRoute.snapshot.params.endpointId
};
},
deps: [
ActivatedRoute
]
},
KubernetesService,
KubernetesEndpointService,
]
})
export class KubeConsoleComponent implements OnInit {

public messages: Observable<string>;

public connectionStatus = new Subject<number>();

public sshInput: Subject<string>;

public errorMessage: string;

public connected: boolean;

public kubeSummaryLink: string;

public breadcrumbs$: Observable<IHeaderBreadcrumb[]>;

@ViewChild('sshViewer', { static: false }) sshViewer: SshViewerComponent;

constructor(
public kubeEndpointService: KubernetesEndpointService,
) { }

ngOnInit() {
this.connectionStatus.next(0);
const guid = this.kubeEndpointService.baseKube.guid;
this.kubeSummaryLink = `/kubernetes/${guid}/summary`;

if (!guid) {
this.messages = NEVER;
this.connectionStatus.next(0);
this.errorMessage = 'No Endpoint ID available';
} else {
const host = window.location.host;
const protocol = window.location.protocol === 'https:' ? 'wss' : 'ws';
const streamUrl = (
`${protocol}://${host}/pp/v1/kubeterminal/${guid}`
);
this.sshInput = new Subject<string>();
const connection = websocketConnect(streamUrl);

this.messages = connection.pipe(
tap(() => this.connectionStatus.next(1)),
switchMap(getResponse => getResponse(this.sshInput)),
catchError((e: Error) => {
if (e.message !== normalClosureMessage && !this.sshViewer.isConnected) {
this.errorMessage = 'Error launching Kubernetes Terminal';
}
return [];
}));

// Breadcrumbs
this.breadcrumbs$ = this.kubeEndpointService.endpoint$.pipe(
map(endpoint => ([{
breadcrumbs: [
{ value: endpoint.entity.name, routerLink: `/kubernetes/${endpoint.entity.guid}` },
]
}])
)
);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ import { KubernetesNamespacesTabComponent } from './tabs/kubernetes-namespaces-t
import { KubernetesNodesTabComponent } from './tabs/kubernetes-nodes-tab/kubernetes-nodes-tab.component';
import { KubernetesPodsTabComponent } from './tabs/kubernetes-pods-tab/kubernetes-pods-tab.component';
import { KubernetesSummaryTabComponent } from './tabs/kubernetes-summary-tab/kubernetes-summary.component';
import { KubeConsoleComponent } from './kube-terminal/kube-console.component';


/* tslint:enable */
Expand Down Expand Up @@ -142,6 +143,7 @@ import { KubernetesSummaryTabComponent } from './tabs/kubernetes-summary-tab/kub
NodePodCountComponent,
KubernetesServicePortsComponent,
KubernetesPodStatusComponent,
KubeConsoleComponent,
KubeServiceCardComponent,
KubernetesResourceViewerComponent,
KubeServiceCardComponent,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { KubernetesNodesTabComponent } from './tabs/kubernetes-nodes-tab/kuberne
import { KubernetesPodsTabComponent } from './tabs/kubernetes-pods-tab/kubernetes-pods-tab.component';
import { KubernetesSummaryTabComponent } from './tabs/kubernetes-summary-tab/kubernetes-summary.component';
import { KubedashConfigurationComponent } from './kubernetes-dashboard/kubedash-configuration/kubedash-configuration.component';
import { KubeConsoleComponent } from './kube-terminal/kube-console.component';

const kubernetes: Routes = [{
path: '',
Expand Down Expand Up @@ -129,6 +130,13 @@ const kubernetes: Routes = [{
{
path: ':endpointId/dashboard-config',
component: KubedashConfigurationComponent,
},
{
path: ':endpointId/terminal',
component: KubeConsoleComponent,
data: {
uiNoMargin: true
}
}
];

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export class KubernetesEndpointService {
kubeDashboardStatus$: Observable<KubeDashboardStatus>;
kubeDashboardLabel$: Observable<string>;
kubeDashboardConfigured$: Observable<boolean>;
kubeTerminalEnabled$: Observable<boolean>;

constructor(
public baseKube: BaseKubeGuid,
Expand Down Expand Up @@ -158,6 +159,11 @@ export class KubernetesEndpointService {
map(auth => auth.sessionData['plugin-config'].kubeDashboardEnabled === 'true')
);

this.kubeTerminalEnabled$ = this.store.select('auth').pipe(
filter(auth => !!auth.sessionData['plugin-config']),
map(auth => auth.sessionData['plugin-config'].kubeTerminalEnabled === 'true')
);

const kubeDashboardStatus$ = kubeEntityCatalog.dashboard.store.getEntityService(this.kubeGuid).waitForEntity$.pipe(
map(status => status.entity),
filter(status => !!status)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@
<mat-icon>dashboard</mat-icon>
<span class="kube-details__button">View Dashboard</span>
</button>
<button *ngIf="kubeEndpointService.kubeTerminalEnabled$ | async" [routerLink]="kubeTerminalLink" mat-button>
<mat-icon>desktop_windows</mat-icon>
<span class="kube-details__button">Open Terminal</span>
</button>
</app-page-sub-nav>

<app-loading-page [isLoading]="isLoading$" [text]="'Retrieving Kubernetes details'">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ export class KubernetesSummaryTabComponent implements OnInit, OnDestroy {
source: SafeResourceUrl;

dashboardLink: string;
kubeTerminalLink: string;

public podCapacity$: Observable<ISimpleUsageChartData>;
public diskPressure$: Observable<ISimpleUsageChartData>;
public memoryPressure$: Observable<ISimpleUsageChartData>;
Expand Down Expand Up @@ -159,6 +161,7 @@ export class KubernetesSummaryTabComponent implements OnInit, OnDestroy {
warningText: `Nodes with unknown ready status found`
});
this.dashboardLink = `/kubernetes/${guid}/dashboard`;
this.kubeTerminalLink = `/kubernetes/${guid}/terminal`;

this.kubeNodeVersions$ = this.kubeEndpointService.getNodeKubeVersions(nodes$).pipe(startWith('-'));

Expand Down
1 change: 1 addition & 0 deletions deploy/ci/build-aio-image-canary.yml
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ jobs:
tag: stratos/deploy/ci/tasks/build-images/canary-tag
tag_as_latest: false
labels_file: image-tag/image-labels
squash: true
build_args_file: image-tag/ui-build-args
build_args:
CANARY_BUILD: true
15 changes: 14 additions & 1 deletion deploy/ci/suse-console-dev-releases.yml
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,13 @@ resources:
username: ((docker-username))
password: ((docker-password))
repository: ((docker-repository))/stratos-chartsync

- name: kube-terminal-image
type: docker-image
source:
username: ((docker-username))
password: ((docker-password))
repository: ((docker-repository))/stratos-kube-terminal

# Artifacts
- name: image-tag
type: s3
Expand Down Expand Up @@ -147,6 +153,13 @@ jobs:
tag: image-tag/v2-alpha-tag
patch_base_reg: ((patch-base-reg))
patch_base_tag: ((patch-base-tag))
- put: kube-terminal-image
params:
dockerfile: stratos/deploy/containers/kube-terminal/Dockerfile.kubeterminal
build: stratos/deploy/containers/kube-terminal
tag: image-tag/v2-alpha-tag
patch_base_reg: ((patch-base-reg))
patch_base_tag: ((patch-base-tag))
- do:
- put: ui-image
params:
Expand Down
Loading