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

fix(ui): Change pod names to new format. Fixes #6865 #6925

Merged
merged 7 commits into from
Oct 15, 2021
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
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {ResourceEditor} from '../../../shared/components/resource-editor/resourc
import {services} from '../../../shared/services';
import {WorkflowArtifacts} from '../../../workflows/components/workflow-artifacts';

import {Utils} from '../../../shared/utils';
import {WorkflowResourcePanel} from '../../../workflows/components/workflow-details/workflow-resource-panel';
import {WorkflowLogsViewer} from '../../../workflows/components/workflow-logs-viewer/workflow-logs-viewer';
import {WorkflowNodeInfo} from '../../../workflows/components/workflow-node-info/workflow-node-info';
Expand Down Expand Up @@ -217,7 +218,9 @@ export class ArchivedWorkflowDetails extends BasePage<RouteComponentProps<any>,
)}
<SlidingPanel isShown={!!this.sidePanel} onClose={() => (this.sidePanel = null)}>
{this.sidePanel === 'yaml' && <WorkflowYamlViewer workflow={this.state.workflow} selectedNode={this.node} />}
{this.sidePanel === 'logs' && <WorkflowLogsViewer workflow={this.state.workflow} nodeId={this.nodeId} container={this.container} archived={true} />}
{this.sidePanel === 'logs' && (
<WorkflowLogsViewer workflow={this.state.workflow} initialPodName={this.podName} nodeId={this.nodeId} container={this.container} archived={true} />
)}
{this.sidePanel === 'resubmit' && (
<ResourceEditor<Workflow>
editing={true}
Expand Down Expand Up @@ -246,6 +249,14 @@ export class ArchivedWorkflowDetails extends BasePage<RouteComponentProps<any>,
return this.nodeId && this.state.workflow.status.nodes[this.nodeId];
}

private get podName() {
if (this.nodeId && this.state.workflow) {
const workflowName = this.state.workflow.metadata.name;
const {name, templateName} = this.node;
return Utils.getPodName(workflowName, name, templateName, this.nodeId);
}
}

private deleteArchivedWorkflow() {
if (!confirm('Are you sure you want to delete this archived workflow?\nThere is no undo.')) {
return;
Expand Down
40 changes: 40 additions & 0 deletions ui/src/app/shared/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ import {NODE_PHASE} from '../../models';

const managedNamespaceKey = 'managedNamespace';
const currentNamespaceKey = 'current_namespace';
const maxK8sResourceNameLength = 253;
const k8sNamingHashLength = 10;

export const Utils = {
statusIconClasses(status: string): string {
let classes = [];
Expand Down Expand Up @@ -117,5 +120,42 @@ export const Utils = {
// return a namespace, never return null/undefined, defaults to "default"
getNamespaceWithDefault(namespace: string) {
return this.managedNamespace || namespace || this.currentNamespace || 'default';
},

ensurePodNamePrefixLength(prefix: string): string {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd be tempted to put these into their own file, maybe add tests. I think that work could be done as tech debt.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense

const maxPrefixLength = maxK8sResourceNameLength - k8sNamingHashLength;

if (prefix.length > maxPrefixLength - 1) {
return prefix.substring(0, maxPrefixLength - 1);
}

return prefix;
},

// getPodName returns a deterministic pod name
getPodName(workflowName: string, nodeName: string, templateName: string, nodeID: string): string {
if (workflowName === nodeName) {
return workflowName;
}

let prefix = `${workflowName}-${templateName}`;
prefix = this.ensurePodNamePrefixLength(prefix);

const hash = createFNVHash(nodeName);
return `${prefix}-${hash}`;
}
};

const createFNVHash = (input: string): number => {
const data = new Buffer(input);

let hashint = 2166136261;

/* tslint:disable:no-bitwise */
for (const character of data) {
hashint = hashint ^ character;
hashint += (hashint << 1) + (hashint << 4) + (hashint << 7) + (hashint << 8) + (hashint << 24);
}

return hashint >>> 0;
};
1 change: 1 addition & 0 deletions ui/src/app/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"experimentalDecorators": true,
"noUnusedLocals": true,
"declaration": false,
"downlevelIteration": true,
"lib": [
"es2017",
"dom"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import * as classNames from 'classnames';
import * as React from 'react';
import {useContext, useEffect, useState} from 'react';
import {RouteComponentProps} from 'react-router';
import {execSpec, Link, Workflow} from '../../../../models';
import {execSpec, Link, NodeStatus, Workflow} from '../../../../models';
import {uiUrl} from '../../../shared/base';
import {CostOptimisationNudge} from '../../../shared/components/cost-optimisation-nudge';
import {ErrorNotice} from '../../../shared/components/error-notice';
Expand All @@ -16,6 +16,7 @@ import {historyUrl} from '../../../shared/history';
import {RetryWatch} from '../../../shared/retry-watch';
import {services} from '../../../shared/services';
import {useQueryParams} from '../../../shared/use-query-params';
import {Utils} from '../../../shared/utils';
import * as Operations from '../../../shared/workflow-operations-map';
import {WorkflowOperations} from '../../../shared/workflow-operations-map';
import {WidgetGallery} from '../../../widgets/widget-gallery';
Expand Down Expand Up @@ -232,7 +233,17 @@ export const WorkflowDetails = ({history, location, match}: RouteComponentProps<
});
};

const getPodName = (wf: Workflow, node: NodeStatus, nodeID: string): string => {
if (workflow && node) {
return Utils.getPodName(wf.metadata.name, node.name, node.templateName, node.id);
}

return nodeID;
};

const selectedNode = workflow && workflow.status && workflow.status.nodes && workflow.status.nodes[nodeId];
const podName = getPodName(workflow, selectedNode, nodeId);

return (
<Page
title={'Workflow Details'}
Expand Down Expand Up @@ -301,7 +312,7 @@ export const WorkflowDetails = ({history, location, match}: RouteComponentProps<
{workflow && (
<SlidingPanel isShown={!!sidePanel} onClose={() => setSidePanel(null)}>
{parsedSidePanel.type === 'logs' && (
<WorkflowLogsViewer workflow={workflow} nodeId={parsedSidePanel.nodeId} container={parsedSidePanel.container} archived={false} />
<WorkflowLogsViewer workflow={workflow} initialPodName={podName} nodeId={parsedSidePanel.nodeId} container={parsedSidePanel.container} archived={false} />
)}
{parsedSidePanel.type === 'events' && <EventsPanel namespace={namespace} kind='Pod' name={parsedSidePanel.nodeId} />}
{parsedSidePanel.type === 'share' && <WidgetGallery namespace={namespace} name={name} />}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@ import {ErrorNotice} from '../../../shared/components/error-notice';
import {InfoIcon, WarningIcon} from '../../../shared/components/fa-icons';
import {Links} from '../../../shared/components/links';
import {services} from '../../../shared/services';
import {Utils} from '../../../shared/utils';
import {FullHeightLogsViewer} from './full-height-logs-viewer';

interface WorkflowLogsViewerProps {
workflow: models.Workflow;
nodeId?: string;
initialPodName: string;
container: string;
archived: boolean;
}
Expand All @@ -22,8 +24,8 @@ function identity<T>(value: T) {
return () => value;
}

export const WorkflowLogsViewer = ({workflow, nodeId, container, archived}: WorkflowLogsViewerProps) => {
const [podName, setPodName] = useState(nodeId || '');
export const WorkflowLogsViewer = ({workflow, nodeId, initialPodName, container, archived}: WorkflowLogsViewerProps) => {
const [podName, setPodName] = useState(initialPodName || '');
const [selectedContainer, setContainer] = useState(container);
const [grep, setGrep] = useState('');
const [error, setError] = useState<Error>();
Expand Down Expand Up @@ -59,7 +61,11 @@ export const WorkflowLogsViewer = ({workflow, nodeId, container, archived}: Work
const podNames = [{value: '', label: 'All'}].concat(
Object.values(workflow.status.nodes || {})
.filter(x => x.type === 'Pod')
.map(x => ({value: x.id, label: (x.displayName || x.name) + ' (' + x.id + ')'}))
.map(targetNode => {
const {name, id, templateName, displayName} = targetNode;
const targetPodName = Utils.getPodName(workflow.metadata.name, name, templateName, id);
return {value: targetPodName, label: (displayName || name) + ' (' + targetPodName + ')'};
})
);

const node = workflow.status.nodes[nodeId];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {Timestamp} from '../../../shared/components/timestamp';
import {ResourcesDuration} from '../../../shared/resources-duration';
import {services} from '../../../shared/services';
import {getResolvedTemplates} from '../../../shared/template-resolution';
import {Utils} from '../../../shared/utils';

require('./workflow-node-info.scss');

Expand Down Expand Up @@ -79,6 +80,10 @@ const AttributeRows = (props: {attributes: {title: string; value: any}[]}) => (
);

const WorkflowNodeSummary = (props: Props) => {
const {workflow, node} = props;

const podName = Utils.getPodName(workflow.metadata.name, node.name, node.templateName, node.id);

const attributes = [
{title: 'NAME', value: <ClipboardText text={props.node.name} />},
{title: 'TYPE', value: props.node.type},
Expand Down Expand Up @@ -131,7 +136,7 @@ const WorkflowNodeSummary = (props: Props) => {
attributes.splice(
2,
0,
{title: 'POD NAME', value: <ClipboardText text={props.node.id} />},
{title: 'POD NAME', value: <ClipboardText text={podName} />},
{
title: 'HOST NODE NAME',
value: <ClipboardText text={props.node.hostNodeName} />
Expand Down