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

refactor(runJob/kubernetes): use joblogviewer #6917

Merged
merged 1 commit into from
May 2, 2019
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
21 changes: 21 additions & 0 deletions app/scripts/modules/kubernetes/src/v2/manifest/manifest.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,15 @@ export interface IManifestContainer {
manifest: IManifest;
}

export interface IStageManifest {
kind: string;
apiVersion: string;
metadata: {
namespace: string;
name: string;
};
}

export interface IManifestParams {
account: string;
location: string;
Expand Down Expand Up @@ -32,4 +41,16 @@ export class KubernetesManifestService {
private static updateManifest(params: IManifestParams, fn: IManifestCallback) {
ManifestReader.getManifest(params.account, params.location, params.name).then(manifest => fn(manifest));
}

public static manifestIdentifier(manifest: IStageManifest) {
const kind = manifest.kind.toLowerCase();
// manifest.metadata.namespace doesn't exist if it's a namespace being deployed
const namespace = (manifest.metadata.namespace || '_').toLowerCase();
const name = manifest.metadata.name.toLowerCase();
const apiVersion = (manifest.apiVersion || '_').toLowerCase();
// assuming this identifier is opaque and not parsed anywhere. Including the
// apiVersion will prevent collisions with CRD kinds without having any visible
// effect elsewhere
return `${namespace} ${kind} ${apiVersion} ${name}`;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ import {
StageFailureMessage,
IManifest,
} from '@spinnaker/core';
import { KubernetesManifestService } from 'kubernetes/v2/manifest/manifest.service';

import { KubernetesManifestService, IStageManifest } from 'kubernetes/v2/manifest/manifest.service';

import { ManifestStatus } from './ManifestStatus';

// from https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.12/
Expand Down Expand Up @@ -35,15 +37,6 @@ export interface IManifestSubscription {
manifest: IManifest;
}

interface IStageManifest {
kind: string;
apiVersion: string;
metadata: {
namespace: string;
name: string;
};
}

export interface IDeployStatusState {
subscriptions: IManifestSubscription[];
manifestIds: string[];
Expand All @@ -67,11 +60,11 @@ export class DeployStatus extends React.Component<IExecutionDetailsSectionProps,

public componentDidUpdate(_prevProps: IExecutionDetailsSectionProps, prevState: IDeployStatusState) {
const manifests: IStageManifest[] = get(this.props.stage, ['context', 'outputs.manifests'], []).filter(m => !!m);
const manifestIds = manifests.map(m => this.manifestIdentifier(m)).sort();
const manifestIds = manifests.map(m => KubernetesManifestService.manifestIdentifier(m)).sort();
if (prevState.manifestIds.join('') !== manifestIds.join('')) {
this.unsubscribeAll();
const subscriptions = manifests.map(manifest => {
const id = this.manifestIdentifier(manifest);
const id = KubernetesManifestService.manifestIdentifier(manifest);
return {
id,
unsubscribe: this.subscribeToManifestUpdates(id, manifest),
Expand Down Expand Up @@ -103,18 +96,6 @@ export class DeployStatus extends React.Component<IExecutionDetailsSectionProps,
this.state.subscriptions.forEach(({ unsubscribe }) => unsubscribe());
}

private manifestIdentifier(manifest: IStageManifest) {
const kind = manifest.kind.toLowerCase();
// manifest.metadata.namespace doesn't exist if it's a namespace being deployed
const namespace = (manifest.metadata.namespace || '_').toLowerCase();
const name = manifest.metadata.name.toLowerCase();
const apiVersion = (manifest.apiVersion || '_').toLowerCase();
// assuming this identifier is opaque and not parsed anywhere. Including the
// apiVersion will prevent collisions with CRD kinds without having any visible
// effect elsewhere
return `${namespace} ${kind} ${apiVersion} ${name}`;
}

private apiGroup(manifest: IStageManifest): string {
const parts = (manifest.apiVersion || '_').split('/');
if (parts.length < 2) {
Expand Down Expand Up @@ -160,7 +141,8 @@ export class DeployStatus extends React.Component<IExecutionDetailsSectionProps,
<div className="col-md-12">
<div className="well alert alert-info">
{manifests.map(manifest => {
const uid = manifest.manifest.metadata.uid || this.manifestIdentifier(manifest.manifest);
const uid =
manifest.manifest.metadata.uid || KubernetesManifestService.manifestIdentifier(manifest.manifest);
return <ManifestStatus key={uid} manifest={manifest} stage={stage} />;
})}
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ export class JobManifestPodLogs extends React.Component<IJobManifestPodLogsProps
<a onClick={this.onClick} className="clickable">
{this.props.linkName}
</a>
<Modal show={showModal} onHide={this.close}>
<Modal show={showModal} onHide={this.close} dialogClassName="modal-lg modal-fullscreen">
<Modal.Header closeButton={true}>
<Modal.Title>Console Output: {this.podName()} </Modal.Title>
</Modal.Header>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,43 +1,113 @@
import * as React from 'react';
import { get } from 'lodash';

import {
import { IExecutionDetailsSectionProps, ExecutionDetailsSection, AccountTag, IManifest } from '@spinnaker/core';

import { JobManifestPodLogs } from '../deployManifest/react/JobManifestPodLogs';

import { KubernetesManifestService, IStageManifest } from 'kubernetes/v2/manifest/manifest.service';

import { IManifestSubscription } from '../deployManifest/react/DeployStatus';

interface IStageDeployedJobs {
[namespace: string]: string[];
}

interface IRunJobExecutionDetailsState {
subscription: IManifestSubscription;
manifestId: string;
}

export class RunJobExecutionDetails extends React.Component<
IExecutionDetailsSectionProps,
ExecutionDetailsSection,
AccountTag,
ReactModal,
ReactInjector,
LogsModal,
ILogsModalProps,
} from '@spinnaker/core';

export class RunJobExecutionDetails extends React.Component<IExecutionDetailsSectionProps> {
IRunJobExecutionDetailsState
> {
public static title = 'runJobConfig';
public state = {
subscription: { id: '', unsubscribe: () => {}, manifest: {} } as IManifestSubscription,
manifestId: '',
};

public componentDidMount() {
this.componentDidUpdate(this.props, this.state);
}

public showLogsModal = (_event: any): void => {
const { stage, execution } = this.props;
const { executionService } = ReactInjector;
executionService.getExecution(execution.id).then((fullExecution: any) => {
const fullStage = fullExecution.stages.find((s: any) => s.id === stage.id);
if (!fullStage) {
return;
}

const modalProps = { dialogClassName: 'modal-lg modal-fullscreen' };
ReactModal.show(
LogsModal,
{
logs: get(fullStage, 'context.jobStatus.logs', 'No log output found.'),
} as ILogsModalProps,
modalProps,
);
public componentWillUnmount() {
this.unsubscribe();
}

public componentDidUpdate(_prevProps: IExecutionDetailsSectionProps, prevState: IRunJobExecutionDetailsState) {
const manifest: IStageManifest = get(this.props.stage, ['context', 'manifest']);
const manifestId = KubernetesManifestService.manifestIdentifier(manifest);
if (prevState.manifestId !== manifestId) {
this.unsubscribe();
const subscription = {
id: manifestId,
unsubscribe: this.subscribeToManifestUpdates(manifest),
manifest: this.stageManifestToIManifest(
manifest,
get(this.props.stage, ['context', 'deploy.jobs'], {}),
this.props.stage.context.account,
),
};
this.setState({
subscription,
manifestId,
});
}
}

private unsubscribe() {
this.state.subscription && this.state.subscription.unsubscribe && this.state.subscription.unsubscribe();
}

private subscribeToManifestUpdates(manifest: IStageManifest): () => void {
const params = {
account: this.props.stage.context.account,
name: this.extractDeployedJobName(manifest, get(this.props.stage, ['context', 'deploy.jobs'], {})),
location: manifest.metadata.namespace == null ? '_' : manifest.metadata.namespace,
};
return KubernetesManifestService.subscribe(this.props.application, params, (updated: IManifest) => {
const subscription = { ...this.state.subscription, manifest: updated };
this.setState({ subscription });
});
};
}

private extractDeployedJobName(manifest: IStageManifest, deployedJobs: IStageDeployedJobs): string {
const namespace = get(manifest, ['metadata', 'namespace'], '');
const jobNames = get(deployedJobs, namespace, []);
return jobNames.length > 0 ? jobNames[0] : '';
}

private stageManifestToIManifest(
manifest: IStageManifest,
deployedJobs: IStageDeployedJobs,
account: string,
): IManifest {
const namespace = get(manifest, ['metadata', 'namespace'], '');
const name = this.extractDeployedJobName(manifest, deployedJobs);

return {
name,
moniker: null,
account,
cloudProvider: 'kubernetes',
location: namespace,
manifest,
status: {},
artifacts: [],
events: [],
};
}

public render() {
const { stage, name, current } = this.props;
const { context } = stage;

const manifest = get(this.state, ['subscription', 'manifest'], null);
let event: any = null;
if (manifest && manifest.events) {
event = manifest.events.find((e: any) => e.message.startsWith('Created pod'));
}
return (
<ExecutionDetailsSection name={name} current={current}>
<div className="row">
Expand All @@ -55,14 +125,9 @@ export class RunJobExecutionDetails extends React.Component<IExecutionDetailsSec
</dl>
)}
</div>
{stage.context.jobStatus && stage.context.jobStatus.logs && (
<div className="col-md-9">
<dl className="dl-narrow dl-horizontal">
<dt>Logs</dt>
<dd>
<a onClick={this.showLogsModal}>Console Output (Raw)</a>
</dd>
</dl>
{manifest && event && (
<div className="col-md-9 well">
<JobManifestPodLogs manifest={manifest} manifestEvent={event} linkName="Console Output (Raw)" />
</div>
)}
</div>
Expand Down