Skip to content

Commit 2fd9106

Browse files
committed
Initialized patches and applied sagemaker-extension.diff
1 parent 0eb3b4c commit 2fd9106

21 files changed

+8750
-0
lines changed

patched-vscode/build/gulpfile.extensions.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ const compilations = [
6363
'php-language-features/tsconfig.json',
6464
'search-result/tsconfig.json',
6565
'references-view/tsconfig.json',
66+
'sagemaker-extension/tsconfig.json',
6667
'simple-browser/tsconfig.json',
6768
'tunnel-forwarding/tsconfig.json',
6869
'typescript-language-features/test-workspace/tsconfig.json',

patched-vscode/build/npm/dirs.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ const dirs = [
3939
'extensions/npm',
4040
'extensions/php-language-features',
4141
'extensions/references-view',
42+
'extensions/sagemaker-extension',
4243
'extensions/search-result',
4344
'extensions/simple-browser',
4445
'extensions/tunnel-forwarding',
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
.vscode/**
2+
.vscode-test/**
3+
out/test/**
4+
out/**
5+
test/**
6+
src/**
7+
tsconfig.json
8+
out/test/**
9+
out/**
10+
cgmanifest.json
11+
yarn.lock
12+
preview-src/**
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Sagemaker Extension
2+
3+
Sagemaker extension managed by Sagemaker team
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
6+
//@ts-check
7+
8+
'use strict';
9+
10+
const withBrowserDefaults = require('../shared.webpack.config').browser;
11+
12+
module.exports = withBrowserDefaults({
13+
context: __dirname,
14+
entry: {
15+
extension: './src/extension.ts'
16+
},
17+
});
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
6+
//@ts-check
7+
8+
'use strict';
9+
10+
const withDefaults = require('../shared.webpack.config');
11+
12+
module.exports = withDefaults({
13+
context: __dirname,
14+
resolve: {
15+
mainFields: ['module', 'main']
16+
},
17+
entry: {
18+
extension: './src/extension.ts',
19+
}
20+
});
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
{
2+
"name": "sagemaker-extension",
3+
"displayName": "Sagemaker Extension",
4+
"description": "Sagemaker Extension",
5+
"extensionKind": [
6+
"workspace"
7+
],
8+
"version": "1.0.0",
9+
"publisher": "sagemaker",
10+
"license": "MIT",
11+
"engines": {
12+
"vscode": "^1.70.0"
13+
},
14+
"main": "./out/extension",
15+
"categories": [
16+
"Other"
17+
],
18+
"activationEvents": [
19+
"*"
20+
],
21+
"capabilities": {
22+
"virtualWorkspaces": true,
23+
"untrustedWorkspaces": {
24+
"supported": true
25+
}
26+
},
27+
"contributes": {
28+
"configuration": {
29+
"type": "object",
30+
"title": "Sagemaker Extension",
31+
"properties": {}
32+
},
33+
"commands": [
34+
]
35+
},
36+
"scripts": {
37+
"compile": "gulp compile-extension:sagemaker-extension",
38+
"watch": "npm run build-preview && gulp watch-extension:sagemaker-extension",
39+
"vscode:prepublish": "npm run build-ext",
40+
"build-ext": "node ../../node_modules/gulp/bin/gulp.js --gulpfile ../../build/gulpfile.extensions.js compile-extension:sagemaker-extension ./tsconfig.json"
41+
},
42+
"dependencies": {
43+
},
44+
"repository": {
45+
}
46+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
// Constants
2+
export const WARNING_TIME_HEADER = 'Session expiring soon';
3+
4+
export const WARNING_BUTTON_REMIND_ME_IN_5_MINS = 'Remind me in 5 minutes';
5+
export const WARNING_BUTTON_SAVE = 'Save';
6+
export const WARNING_BUTTON_SAVE_AND_RENEW_SESSION = 'Save and renew session';
7+
export const WARNING_TIME_BUTTONS = {
8+
SSO: [WARNING_BUTTON_REMIND_ME_IN_5_MINS, WARNING_BUTTON_SAVE],
9+
IAM: [WARNING_BUTTON_REMIND_ME_IN_5_MINS, WARNING_BUTTON_SAVE_AND_RENEW_SESSION]
10+
};
11+
12+
// Constants for signInWarning
13+
export const SIGN_IN_HEADER = 'Please sign in again';
14+
export const SIGN_IN_MESSAGE = "You were logged out of your account. Choose 'Sign In' to continue using this workplace.";
15+
export const SIGN_IN_MESSAGE_WHEN_REDIRECT_URL_DOES_NOT_EXIST = "You were logged out of your account. You are not able to\n" +
16+
" perform actions in your workplace at this time. Please start a\n" +
17+
" new session.";
18+
export const SIGN_IN_BUTTON = 'Sign In';
19+
export const SSO_MESSAGE = 'To renew the session, log out from Studio App via "File" -> "Log Out" and then "Sign out" from AWS IAM Identity Center (successor to AWS SSO) user portal. Do you want to save all changes now?';
20+
export const IAM_MESSAGE = 'Do you want to renew your session now?'
21+
export enum AUTH_MODE {
22+
SSO = "Sso",
23+
IAM = "Iam"
24+
}
25+
export const FIFTEEN_MINUTES_INTERVAL_MILLIS = 15 * 60 * 1000;
26+
export const FIVE_MINUTES_INTERVAL_MILLIS = 5 * 60 * 1000;
27+
28+
export const SAGEMAKER_METADATA_PATH = '/opt/ml/metadata/resource-metadata.json';
29+
30+
export class SagemakerCookie {
31+
authMode: string
32+
expiryTime: number
33+
ssoExpiryTimestamp: number
34+
studioUserProfileName: string
35+
redirectURL: string
36+
37+
constructor(
38+
authMode: string,
39+
expiryTime: number,
40+
ssoExpiryTimestamp: number,
41+
studioUserProfileName: string,
42+
redirectURL: string
43+
) {
44+
this.authMode = authMode;
45+
this.expiryTime = expiryTime;
46+
this.ssoExpiryTimestamp = ssoExpiryTimestamp
47+
this.studioUserProfileName = studioUserProfileName
48+
this.redirectURL = redirectURL
49+
}
50+
};
51+
52+
export class SagemakerResourceMetadata {
53+
AppType?: string
54+
DomainId?: string
55+
SpaceName?: string
56+
ResourceArn?: string
57+
ResourceName?: string
58+
AppImageVersion?: string
59+
};
60+
export function isSSOMode(cookie: SagemakerCookie) {
61+
return (cookie.authMode === AUTH_MODE.SSO)
62+
}
63+
64+
export function getExpiryTime(cookie: SagemakerCookie): number {
65+
if (AUTH_MODE.SSO === cookie.authMode) {
66+
return cookie.ssoExpiryTimestamp;
67+
} else if (AUTH_MODE.IAM === cookie.authMode) {
68+
return cookie.expiryTime;
69+
} else {
70+
return -1;
71+
}
72+
}
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
import * as vscode from 'vscode';
2+
import * as fs from 'fs';
3+
import { SessionWarning } from "./sessionWarning";
4+
import {
5+
FIFTEEN_MINUTES_INTERVAL_MILLIS,
6+
FIVE_MINUTES_INTERVAL_MILLIS,
7+
SAGEMAKER_METADATA_PATH,
8+
SIGN_IN_BUTTON,
9+
WARNING_BUTTON_REMIND_ME_IN_5_MINS,
10+
WARNING_BUTTON_SAVE,
11+
WARNING_BUTTON_SAVE_AND_RENEW_SESSION,
12+
SagemakerCookie,
13+
SagemakerResourceMetadata,
14+
getExpiryTime
15+
} from "./constant";
16+
import * as console from "console";
17+
18+
19+
const PARSE_SAGEMAKER_COOKIE_COMMAND = 'sagemaker.parseCookies';
20+
21+
function showWarningDialog() {
22+
vscode.commands.executeCommand(PARSE_SAGEMAKER_COOKIE_COMMAND).then(response => {
23+
24+
const sagemakerCookie: SagemakerCookie = response as SagemakerCookie
25+
const remainingTime: number = getExpiryTime(sagemakerCookie) - Date.now();
26+
27+
if(!(Object.keys(sagemakerCookie).length === 0)) {
28+
if (getExpiryTime(sagemakerCookie) != null && remainingTime > FIFTEEN_MINUTES_INTERVAL_MILLIS) {
29+
// This means cookie has been reset, reinitializing again
30+
initialize(sagemakerCookie);
31+
} else if (getExpiryTime(sagemakerCookie) != null && remainingTime > 0) {
32+
// READ COOKIE again to decide to show this up
33+
34+
SessionWarning.sessionExpiringWarning(remainingTime, sagemakerCookie)
35+
.then((selection) => {
36+
if (selection === WARNING_BUTTON_REMIND_ME_IN_5_MINS) {
37+
// Trigger the function to show the warning again after 5 minutes.
38+
setTimeout(showWarningDialog, FIVE_MINUTES_INTERVAL_MILLIS);
39+
} else if (selection === WARNING_BUTTON_SAVE) {
40+
saveWorkspace();
41+
} else if (selection === WARNING_BUTTON_SAVE_AND_RENEW_SESSION) {
42+
saveWorkspace();
43+
// Trigger the function to make an API call to renew the session.
44+
renewSession(sagemakerCookie);
45+
}
46+
});
47+
48+
} else {
49+
// this means expiryTime cookie is either invalid or <0
50+
signInError(sagemakerCookie);
51+
}
52+
} else {
53+
// no cookie found so assuming its running locally
54+
}
55+
56+
});
57+
58+
}
59+
60+
function signInError(sagemakerCookie: SagemakerCookie) {
61+
// The session has expired
62+
SessionWarning.signInWarning(sagemakerCookie)
63+
.then((selection) => {
64+
if (selection === SIGN_IN_BUTTON) {
65+
vscode.env.openExternal(vscode.Uri.parse(<string>sagemakerCookie.redirectURL));
66+
}
67+
});
68+
}
69+
70+
function initialize(sagemakerCookie: SagemakerCookie) {
71+
const currentTime = Date.now();
72+
const timeToExpiry = getExpiryTime(sagemakerCookie) - currentTime;
73+
74+
if (timeToExpiry <= 0) {
75+
signInError(sagemakerCookie);
76+
} else if (timeToExpiry >= FIFTEEN_MINUTES_INTERVAL_MILLIS) {
77+
const warningTime = timeToExpiry - FIFTEEN_MINUTES_INTERVAL_MILLIS;
78+
setTimeout(() => {
79+
showWarningDialog();
80+
}, warningTime);
81+
} else {
82+
// If less than or equal to 15 minutes left, set a timer for the remaining time
83+
const warningTime = timeToExpiry % FIVE_MINUTES_INTERVAL_MILLIS;
84+
setTimeout(() => {
85+
showWarningDialog();
86+
}, warningTime);
87+
}
88+
}
89+
90+
function saveWorkspace() {
91+
vscode.workspace.saveAll().then(() => {
92+
// TODO: log workspace saved
93+
});
94+
}
95+
function renewSession(sagemakerCookie: SagemakerCookie) {
96+
// TODO: Log and trigger a Signin
97+
vscode.env.openExternal(vscode.Uri.parse(<string>sagemakerCookie.redirectURL));
98+
// Trigger the function to show the warning again after 5 minutes again to validate.
99+
setTimeout(showWarningDialog, FIVE_MINUTES_INTERVAL_MILLIS);
100+
}
101+
102+
function updateStatusItemWithMetadata(context: vscode.ExtensionContext) {
103+
fs.readFile(SAGEMAKER_METADATA_PATH, 'utf-8', (err, data) => {
104+
if (err) {
105+
// fail silently not to block users
106+
} else {
107+
try {
108+
const jsonData = JSON.parse(data) as SagemakerResourceMetadata;
109+
const spaceName = jsonData.SpaceName;
110+
111+
if (spaceName != null) {
112+
let spaceNameStatusBarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left, 100);
113+
spaceNameStatusBarItem.text = `Space: ${spaceName}`;
114+
spaceNameStatusBarItem.show();
115+
context.subscriptions.push(spaceNameStatusBarItem);
116+
}
117+
} catch (jsonError) {
118+
// fail silently not to block users
119+
}
120+
}
121+
});
122+
}
123+
124+
export function activate(context: vscode.ExtensionContext) {
125+
126+
// TODO: log activation of extension
127+
console.log('Activating Sagemaker Extension...');
128+
129+
// execute the get cookie command and save the data to cookies
130+
vscode.commands.executeCommand(PARSE_SAGEMAKER_COOKIE_COMMAND).then(r => {
131+
132+
const sagemakerCookie: SagemakerCookie = r as SagemakerCookie
133+
134+
initialize(sagemakerCookie);
135+
updateStatusItemWithMetadata(context);
136+
});
137+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import * as vscode from "vscode";
2+
import {
3+
IAM_MESSAGE,
4+
isSSOMode, SagemakerCookie,
5+
SIGN_IN_BUTTON,
6+
SIGN_IN_HEADER,
7+
SIGN_IN_MESSAGE, SIGN_IN_MESSAGE_WHEN_REDIRECT_URL_DOES_NOT_EXIST, SSO_MESSAGE,
8+
WARNING_TIME_BUTTONS,
9+
WARNING_TIME_HEADER
10+
} from "./constant";
11+
12+
export class SessionWarning {
13+
14+
public static sessionExpiringWarning (warningTime: number, cookie: SagemakerCookie): Thenable<string | undefined> {
15+
// convert warningTime from ms to minutes;
16+
const warningTimeInMinutes: number = Math.floor(warningTime / 60000);
17+
const detail: string = `Your session will expire in ${warningTimeInMinutes} minutes. If your session expires, you could lose unsaved changes \n ${isSSOMode(cookie) ? SSO_MESSAGE : IAM_MESSAGE}`
18+
const sessionExpiringOptions: vscode.MessageOptions = {
19+
detail: detail,
20+
modal: true
21+
};
22+
23+
// Session expiration warning...
24+
if (isSSOMode(cookie)) {
25+
return vscode.window.showWarningMessage(WARNING_TIME_HEADER, sessionExpiringOptions, ...WARNING_TIME_BUTTONS.SSO);
26+
} else {
27+
return vscode.window.showWarningMessage(WARNING_TIME_HEADER, sessionExpiringOptions, ...WARNING_TIME_BUTTONS.IAM);
28+
}
29+
}
30+
31+
public static signInWarning (cookie: SagemakerCookie): Thenable<string | undefined> {
32+
const signInOptions: vscode.MessageOptions = {
33+
detail: cookie.redirectURL ? SIGN_IN_MESSAGE : SIGN_IN_MESSAGE_WHEN_REDIRECT_URL_DOES_NOT_EXIST,
34+
modal: true
35+
};
36+
37+
// SignIn warning...
38+
if (cookie.redirectURL) {
39+
return vscode.window.showErrorMessage(SIGN_IN_HEADER, signInOptions, SIGN_IN_BUTTON);
40+
} else {
41+
return vscode.window.showErrorMessage(SIGN_IN_HEADER, signInOptions);
42+
}
43+
}
44+
}

0 commit comments

Comments
 (0)