feat: add support for default container annotation (#8015) (#9769)

* feat: add support for default container in logs/exec

Signed-off-by: Edward Grönroos <edward@gronroos.se>

* chore: resolve linting issues

Signed-off-by: Edward Grönroos <edward@gronroos.se>
This commit is contained in:
Edward Grönroos
2022-08-09 16:30:48 +02:00
committed by GitHub
parent 10303dc168
commit af40d52ca0
4 changed files with 37 additions and 22 deletions

View File

@@ -25,11 +25,12 @@ export interface PodLogsProps {
timestamp?: string;
setPage: (pageData: {number: number; untilTimes: string[]}) => void;
containerGroups?: any[];
onClickContainer?: (group: any, i: number) => any;
onClickContainer?: (group: any, i: number, tab: string) => any;
}
export const PodsLogsViewer = (props: PodLogsProps & {fullscreen?: boolean}) => {
if (!props.containerName || props.containerName === '') {
const {containerName, onClickContainer} = props;
if (!containerName || containerName === '') {
return <div>Pod does not have container with name {props.containerName}</div>;
}
@@ -55,7 +56,7 @@ export const PodsLogsViewer = (props: PodLogsProps & {fullscreen?: boolean}) =>
group.containers.forEach((container: any, index: number) => {
const title = (
<div className='d-inline-block'>
<i className={`fa fa-angle-right ${container.name === props.containerName ? '' : 'invisible'}`} />
{container.name === containerName && <i className='fa fa-angle-right' />}
<span title={container.name} className='container-item'>
{container.name.toUpperCase()}
</span>
@@ -63,7 +64,7 @@ export const PodsLogsViewer = (props: PodLogsProps & {fullscreen?: boolean}) =>
);
containerItems.push({
title,
action: () => (container.name === props.containerName ? {} : props.onClickContainer(group, index))
action: () => (container.name === containerName ? {} : onClickContainer(group, index, 'logs'))
});
});
});

View File

@@ -4,8 +4,7 @@ import * as models from '../../../shared/models';
import * as React from 'react';
import './pod-terminal-viewer.scss';
import 'xterm/css/xterm.css';
import * as AppUtils from '../utils';
import {useCallback, useEffect, useState} from 'react';
import {useCallback, useEffect} from 'react';
import {debounceTime, takeUntil} from 'rxjs/operators';
import {fromEvent, ReplaySubject, Subject} from 'rxjs';
import {Context} from '../../../shared/context';
@@ -15,6 +14,8 @@ export interface PodTerminalViewerProps {
projectName: string;
selectedNode: models.ResourceNode;
podState: models.State;
containerName: string;
onClickContainer?: (group: any, i: number, tab: string) => any;
}
export interface ShellFrame {
operation: string;
@@ -23,14 +24,13 @@ export interface ShellFrame {
cols?: number;
}
export const PodTerminalViewer: React.FC<PodTerminalViewerProps> = ({selectedNode, applicationName, projectName, podState}) => {
export const PodTerminalViewer: React.FC<PodTerminalViewerProps> = ({selectedNode, applicationName, projectName, podState, containerName, onClickContainer}) => {
const terminalRef = React.useRef(null);
const appContext = React.useContext(Context); // used to show toast
const fitAddon = new FitAddon();
let terminal: Terminal;
let webSocket: WebSocket;
const keyEvent = new ReplaySubject<KeyboardEvent>(2);
const [activeContainer, setActiveContainer] = useState(0);
let connSubject = new ReplaySubject<ShellFrame>(100);
let incommingMessage = new Subject<ShellFrame>();
const unsubscribe = new Subject<void>();
@@ -143,10 +143,9 @@ export const PodTerminalViewer: React.FC<PodTerminalViewerProps> = ({selectedNod
const {name = '', namespace = ''} = selectedNode || {};
const url = `${location.host}${appContext.baseHref}`.replace(/\/$/, '');
webSocket = new WebSocket(
`${location.protocol === 'https:' ? 'wss' : 'ws'}://${url}/terminal?pod=${name}&container=${AppUtils.getContainerName(
podState,
activeContainer
)}&appName=${applicationName}&projectName=${projectName}&namespace=${namespace}`
`${
location.protocol === 'https:' ? 'wss' : 'ws'
}://${url}/terminal?pod=${name}&container=${containerName}&appName=${applicationName}&projectName=${projectName}&namespace=${namespace}`
);
webSocket.onopen = onConnectionOpen;
webSocket.onclose = onConnectionClose;
@@ -171,7 +170,7 @@ export const PodTerminalViewer: React.FC<PodTerminalViewerProps> = ({selectedNod
// Save a reference to the node
terminalRef.current = node;
},
[activeContainer]
[containerName]
);
useEffect(() => {
@@ -202,7 +201,7 @@ export const PodTerminalViewer: React.FC<PodTerminalViewerProps> = ({selectedNod
incommingMessage.complete();
};
}, [activeContainer]);
}, [containerName]);
const containerGroups = [
{
@@ -228,12 +227,12 @@ export const PodTerminalViewer: React.FC<PodTerminalViewerProps> = ({selectedNod
className='application-details__container'
key={container.name}
onClick={() => {
if (group.offset + i !== activeContainer) {
if (container.name !== containerName) {
disconnect();
setActiveContainer(group.offset + i);
onClickContainer(group, i, 'exec');
}
}}>
{group.offset + i === activeContainer && <i className='fa fa-angle-right' />}
{container.name === containerName && <i className='fa fa-angle-right' />}
<span title={container.name}>{container.name}</span>
</div>
))}

View File

@@ -1,5 +1,6 @@
import {DataLoader, Tab, Tabs} from 'argo-ui';
import * as React from 'react';
import {useState} from 'react';
import {EventsList, YamlEditor} from '../../../shared/components';
import * as models from '../../../shared/models';
import {ErrorBoundary} from '../../../shared/components/error-boundary/error-boundary';
@@ -34,6 +35,7 @@ interface ResourceDetailsProps {
export const ResourceDetails = (props: ResourceDetailsProps) => {
const {selectedNode, updateApp, application, isAppSelected, tree} = {...props};
const [activeContainer, setActiveContainer] = useState();
const appContext = React.useContext(Context);
const tab = new URLSearchParams(appContext.history.location.search).get('tab');
const selectedNodeInfo = NodeInfo(new URLSearchParams(appContext.history.location.search).get('node'));
@@ -86,7 +88,10 @@ export const ResourceDetails = (props: ResourceDetailsProps) => {
});
}
const onClickContainer = (group: any, i: number) => SelectNode(selectedNodeKey, group.offset + i, 'logs', appContext);
const onClickContainer = (group: any, i: number, activeTab: string) => {
setActiveContainer(group.offset + i);
SelectNode(selectedNodeKey, activeContainer, activeTab, appContext);
};
if (logsAllowed) {
tabs = tabs.concat([
@@ -103,7 +108,7 @@ export const ResourceDetails = (props: ResourceDetailsProps) => {
name={node.name}
namespace={podState.metadata.namespace}
applicationName={application.metadata.name}
containerName={AppUtils.getContainerName(podState, selectedNodeInfo.container)}
containerName={AppUtils.getContainerName(podState, activeContainer)}
page={{number: page, untilTimes}}
setPage={pageData => appContext.navigation.goto('.', {page: pageData.number, untilTimes: pageData.untilTimes.join(',')})}
containerGroups={containerGroups}
@@ -121,7 +126,14 @@ export const ResourceDetails = (props: ResourceDetailsProps) => {
icon: 'fa fa-terminal',
title: 'Terminal',
content: (
<PodTerminalViewer applicationName={application.metadata.name} projectName={application.spec.project} podState={podState} selectedNode={selectedNode} />
<PodTerminalViewer
applicationName={application.metadata.name}
projectName={application.spec.project}
podState={podState}
selectedNode={selectedNode}
containerName={AppUtils.getContainerName(podState, activeContainer)}
onClickContainer={onClickContainer}
/>
)
}
]);

View File

@@ -1071,9 +1071,12 @@ export function parseApiVersion(apiVersion: string): {group: string; version: st
return {version: parts[0], group: ''};
}
export function getContainerName(pod: any, containerIndex: number): string {
export function getContainerName(pod: any, containerIndex: number | null): string {
if (containerIndex == null && pod.metadata?.annotations?.['kubectl.kubernetes.io/default-container']) {
return pod.metadata?.annotations?.['kubectl.kubernetes.io/default-container'];
}
const containers = (pod.spec.containers || []).concat(pod.spec.initContainers || []);
const container = containers[containerIndex];
const container = containers[containerIndex || 0];
return container.name;
}