Skip to content

Commit 82fef67

Browse files
committed
remove I prefix from interfaces. minor fixes on lint errors.
1 parent 2ce384f commit 82fef67

17 files changed

+390
-214
lines changed

frontend/.gitignore

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,4 @@ yarn-error.log*
2929
coverage
3030

3131
# vscode
32-
.vscode
32+
.vscode

frontend/.vscode/launch.json

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
// Use IntelliSense to learn about possible attributes.
3+
// Hover to view descriptions of existing attributes.
4+
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5+
"version": "0.2.0",
6+
"configurations": [
7+
{
8+
"type": "node",
9+
"name": "vscode-jest-tests",
10+
"request": "launch",
11+
"args": [
12+
"test",
13+
"--env=jsdom",
14+
"--runInBand"
15+
],
16+
"cwd": "${workspaceFolder}",
17+
"console": "integratedTerminal",
18+
"internalConsoleOptions": "neverOpen",
19+
"runtimeExecutable": "${workspaceFolder}/node_modules/.bin/react-scripts-ts",
20+
"protocol": "inspector"
21+
}
22+
]
23+
}

frontend/server/app.ts

+54-20
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,11 @@ import * as express from 'express';
1616
import { Application, static as StaticHandler } from 'express';
1717
import * as proxy from 'http-proxy-middleware';
1818

19-
import { IConfigs } from './configs';
19+
import { UIConfigs } from './configs';
2020
import { getAddress } from './utils';
2121
import { getBuildMetadata, getHealthzEndpoint, getHealthzHandler } from './handlers/healthz';
2222
import { getArtifactsHandler } from './handlers/artifacts';
23-
import { getCreateTensorboardHandler, getGetTensorboardHandler } from './handlers/tensorboard';
23+
import { getCreateTensorboardHandler, getTensorboardHandler, deleteTensorboardHandler } from './handlers/tensorboard';
2424
import { getPodLogsHandler } from './handlers/pod-logs';
2525
import { clusterNameHandler, projectIdHandler } from './handlers/core';
2626
import { getAllowCustomVisualizationsHandler } from './handlers/vis';
@@ -40,72 +40,101 @@ function getRegisterHandler(app: Application, basePath: string) {
4040
};
4141
}
4242

43+
/**
44+
* UIServer wraps around a express application to:
45+
* - proxy requests to ml-pipeline api server
46+
* - retrieve artifacts from the various backend
47+
* - create and retrieve new viewer instances
48+
* - serve static front-end resources (i.e. react app)
49+
*/
4350
export class UIServer {
4451
app: Application;
4552
httpServer?: Server;
4653

47-
constructor(public readonly options: IConfigs) {
54+
constructor(public readonly options: UIConfigs) {
4855
this.app = createUIServer(options);
4956
}
5057

58+
/**
59+
* Starts the http server.
60+
* @param port optionally overwrite the provided port to listen to.
61+
*/
5162
start(port?: number | string) {
63+
if (!!this.httpServer) {
64+
throw new Error('UIServer already started.');
65+
}
5266
port = port || this.options.server.port;
5367
this.httpServer = this.app.listen(port, () => {
5468
console.log('Server listening at http://localhost:' + port);
5569
});
5670
return this.httpServer;
5771
}
5872

73+
/**
74+
* Stops the http server.
75+
*/
5976
close() {
60-
return this.httpServer && this.httpServer.close();
77+
if (!!this.httpServer) {
78+
this.httpServer.close();
79+
}
80+
this.httpServer = undefined;
81+
return this;
6182
}
6283
}
6384

64-
function createUIServer(options: IConfigs) {
85+
function createUIServer(options: UIConfigs) {
6586
const currDir = path.resolve(__dirname);
6687
const basePath = options.server.basePath;
67-
const apiVersion = options.server.apiVersion;
88+
const apiVersionPrefix = options.server.apiVersionPrefix;
6889
const apiServerAddress = getAddress(options.pipeline);
6990
const envoyServiceAddress = getAddress(options.metadata.envoyService);
7091

7192
const app: Application = express();
7293
const registerHandler = getRegisterHandler(app, basePath);
7394

74-
app.use(function(req, _, next) {
95+
/** log to stdout */
96+
app.use((req, _, next) => {
7597
console.info(req.method + ' ' + req.originalUrl);
7698
next();
7799
});
78100

101+
/** Healthz */
79102
registerHandler(
80103
app.get,
81-
`/${apiVersion}/healthz`,
104+
`/${apiVersionPrefix}/healthz`,
82105
getHealthzHandler({
83-
healthzEndpoint: getHealthzEndpoint(apiServerAddress, options.server.apiVersion),
106+
healthzEndpoint: getHealthzEndpoint(apiServerAddress, apiVersionPrefix),
84107
healthzStats: getBuildMetadata(currDir),
85108
}),
86109
);
87110

111+
/** Artifact */
88112
registerHandler(app.get, '/artifacts/get', getArtifactsHandler(options.artifacts));
89113

90-
registerHandler(app.get, '/apps/tensorboard', getGetTensorboardHandler());
114+
/** Tensorboard viewer */
115+
registerHandler(app.get, '/apps/tensorboard', getTensorboardHandler);
116+
registerHandler(app.delete, '/apps/tensorboard', deleteTensorboardHandler);
91117
registerHandler(
92118
app.post,
93119
'/apps/tensorboard',
94120
getCreateTensorboardHandler(options.viewer.tensorboard.podTemplateSpec),
95121
);
96122

123+
/** Pod logs */
97124
registerHandler(app.get, '/k8s/pod/logs', getPodLogsHandler(options.argo, options.artifacts));
98125

126+
/** Cluster (GKS only) */
99127
registerHandler(app.get, '/system/cluster-name', clusterNameHandler);
100128
registerHandler(app.get, '/system/project-id', projectIdHandler);
101129

130+
/** Visualization */
102131
registerHandler(
103132
app.get,
104133
'/visualizations/allowed',
105134
getAllowCustomVisualizationsHandler(options.visualizations.allowCustomVisualizations),
106135
);
107136

108-
// Proxy metadata requests to the Envoy instance which will handle routing to the metadata gRPC server
137+
/** Proxy metadata requests to the Envoy instance which will handle routing to the metadata gRPC server */
109138
app.all(
110139
'/ml_metadata.*',
111140
proxy({
@@ -119,11 +148,12 @@ function createUIServer(options: IConfigs) {
119148

120149
// Order matters here, since both handlers can match any proxied request with a referer,
121150
// and we prioritize the basepath-friendly handler
122-
proxyMiddleware(app, `${basePath}/${apiVersion}`);
123-
proxyMiddleware(app, `/${apiVersion}`);
151+
proxyMiddleware(app, `${basePath}/${apiVersionPrefix}`);
152+
proxyMiddleware(app, `/${apiVersionPrefix}`);
124153

154+
/** Proxy to ml-pipeline api server */
125155
app.all(
126-
`/${apiVersion}/*`,
156+
`/${apiVersionPrefix}/*`,
127157
proxy({
128158
changeOrigin: true,
129159
onProxyReq: proxyReq => {
@@ -132,29 +162,33 @@ function createUIServer(options: IConfigs) {
132162
target: apiServerAddress,
133163
}),
134164
);
135-
136165
app.all(
137-
`${basePath}/${apiVersion}/*`,
166+
`${basePath}/${apiVersionPrefix}/*`,
138167
proxy({
139168
changeOrigin: true,
140169
onProxyReq: proxyReq => {
141170
console.log('Proxied request: ', (proxyReq as any).path);
142171
},
143-
pathRewrite: path =>
144-
path.startsWith(basePath) ? path.substr(basePath.length, path.length) : path,
172+
pathRewrite: pathStr =>
173+
pathStr.startsWith(basePath) ? pathStr.substr(basePath.length, pathStr.length) : pathStr,
145174
target: apiServerAddress,
146175
}),
147176
);
148177

149-
// These pathes can be matched by static handler. Putting them before it to
150-
// override behavior for index html.
178+
/**
179+
* Modify index.html.
180+
* These pathes can be matched by static handler. Putting them before it to
181+
* override behavior for index html.
182+
*/
151183
const indexHtmlHandler = getIndexHTMLHandler(options.server);
152184
registerHandler(app.get, '/', indexHtmlHandler);
153185
registerHandler(app.get, '/index.html', indexHtmlHandler);
154186

187+
/** Static resource (i.e. react app) */
155188
app.use(basePath, StaticHandler(options.server.staticDir));
156189
app.use(StaticHandler(options.server.staticDir));
157190

191+
/** Fallback to index.html */
158192
app.get('*', indexHtmlHandler);
159193

160194
return app;

frontend/server/aws-helper.ts

+23-11
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@
1313
// limitations under the License.
1414
import fetch from 'node-fetch';
1515

16-
/** IAWSMetadataCredentials describes the credentials provided by aws metadata store. */
17-
export interface IAWSMetadataCredentials {
16+
/** AWSMetadataCredentials describes the credentials provided by aws metadata store. */
17+
export interface AWSMetadataCredentials {
1818
Code: string;
1919
LastUpdated: string;
2020
Type: string;
@@ -39,7 +39,9 @@ async function getIAMInstanceProfile(): Promise<string | undefined> {
3939
}
4040
return;
4141
} catch (error) {
42-
console.error(`Unable to fetch credentials from AWS metadata store: ${error}`);
42+
console.error(
43+
`Unable to fetch credentials from AWS metadata store (${metadataUrl}/iam/security-credentials/): ${error}`,
44+
);
4345
return;
4446
}
4547
}
@@ -49,7 +51,7 @@ async function getIAMInstanceProfile(): Promise<string | undefined> {
4951
*/
5052
class AWSInstanceProfileCredentials {
5153
_iamProfile?: string;
52-
_credentials?: IAWSMetadataCredentials;
54+
_credentials?: AWSMetadataCredentials;
5355
_expiration: number = 0;
5456

5557
/** reset all caches */
@@ -64,7 +66,13 @@ class AWSInstanceProfileCredentials {
6466
* EC2 Instance profile
6567
*/
6668
async profile() {
67-
this._iamProfile = this._iamProfile || (await getIAMInstanceProfile());
69+
if (!this._iamProfile) {
70+
try {
71+
this._iamProfile = await getIAMInstanceProfile();
72+
} catch (err) {
73+
console.error(err);
74+
}
75+
}
6876
return this._iamProfile;
6977
}
7078

@@ -80,10 +88,12 @@ class AWSInstanceProfileCredentials {
8088
}
8189
}
8290

83-
async _fetchCredentials(): Promise<IAWSMetadataCredentials | undefined> {
91+
async _fetchCredentials(): Promise<AWSMetadataCredentials | undefined> {
8492
try {
85-
const resp = await fetch(`${metadataUrl}/iam/security-credentials/${await this.profile()}`);
86-
return resp.json();
93+
const profile = await this.profile();
94+
const resp = await fetch(`${metadataUrl}/iam/security-credentials/${profile}`);
95+
const credentials = await resp.json();
96+
return credentials;
8797
} catch (error) {
8898
console.error(`Unable to fetch credentials from AWS metadata store: ${error}`);
8999
return;
@@ -93,13 +103,15 @@ class AWSInstanceProfileCredentials {
93103
/**
94104
* Get the AWS metadata store session credentials.
95105
*/
96-
async getCredentials(): Promise<IAWSMetadataCredentials> {
106+
async getCredentials(): Promise<AWSMetadataCredentials> {
97107
// query for credentials if going to expire or no credentials yet
98108
if (Date.now() + 10 >= this._expiration || !this._credentials) {
99109
this._credentials = await this._fetchCredentials();
100-
if (this._credentials && this._credentials.Expiration)
110+
if (this._credentials && this._credentials.Expiration) {
101111
this._expiration = new Date(this._credentials.Expiration).getTime();
102-
else this._expiration = -1; // always retry
112+
} else {
113+
this._expiration = -1; // always retry
114+
}
103115
}
104116
return this._credentials;
105117
}

0 commit comments

Comments
 (0)