Skip to content
156 changes: 111 additions & 45 deletions src/plugins/setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
checkIsAuthenticated,
requestAuthentication,
saveAuthToken,
readAuthToken,
} from "../utils/authenticate.ts";
import { configureAwsProfiles } from "../utils/configure-aws.ts";
import { runInstallProcess } from "../utils/install.ts";
Expand All @@ -15,6 +16,7 @@
} from "../utils/license.ts";
import { minDelay } from "../utils/promises.ts";
import { updateDockerImage } from "../utils/setup.ts";
import { get_setup_ended } from "../utils/telemetry.ts";

export default createPlugin(
"setup",
Expand All @@ -38,30 +40,10 @@
payload: {
namespace: "onboarding",
origin: origin_trigger,
expected_steps: [
{
name: "emulator_installed",
is_first_step: true,
is_last_step: false,
position: 1,
},
{
name: "auth_token_configured",
is_first_step: false,
is_last_step: false,
position: 2,
},
{
name: "aws_profile_configured",
is_first_step: false,
is_last_step: true,
position: 3,
},
],
},
});

window.withProgress(

Check warning on line 46 in src/plugins/setup.ts

View workflow job for this annotation

GitHub Actions / Lint

Promises must be awaited, end with a call to .catch, end with a call to .then with a rejection handler or be explicitly marked as ignored with the `void` operator
{
location: ProgressLocation.Notification,
title: "Setup LocalStack",
Expand All @@ -69,27 +51,39 @@
},
async (progress, cancellationToken) => {
/////////////////////////////////////////////////////////////////////
let cliStatus: "COMPLETED" | "SKIPPED" = "COMPLETED";
let authenticationStatus: "COMPLETED" | "SKIPPED" = "COMPLETED";
{
const installationStartedAt = new Date().toISOString();
const { cancelled } = await runInstallProcess(
const { cancelled, skipped } = await runInstallProcess(
progress,
cancellationToken,
outputChannel,
telemetry,
origin_trigger,
);
cliStatus = skipped === true ? "SKIPPED" : "COMPLETED";
if (cancelled || cancellationToken.isCancellationRequested) {
telemetry.track({
name: "emulator_installed",
payload: {
namespace: "onboarding",
origin: origin_trigger,
position: 1,
step_order: 1,
started_at: installationStartedAt,
ended_at: new Date().toISOString(),
status: "CANCELLED",
},
});
telemetry.track(
get_setup_ended(
cliStatus,
"SKIPPED",
"SKIPPED",
"SKIPPED",
"CANCELLED",
),
);
return;
}
}
Expand All @@ -110,30 +104,45 @@
const authenticated = await minDelay(checkIsAuthenticated());
if (cancellationToken.isCancellationRequested) {
telemetry.track({
name: "setup_ended",
name: "auth_token_configured",
payload: {
namespace: "onboarding",
steps: [1, 2, 3],
origin: origin_trigger,
step_order: 2,
started_at: authStartedAuthAt,
ended_at: new Date().toISOString(),
status: "CANCELLED",
},
});
telemetry.track(
get_setup_ended(
cliStatus,
"CANCELLED",
"SKIPPED",
"SKIPPED",
"CANCELLED",
await readAuthToken(),
),
);
return;
}
if (authenticated) {
progress.report({
message: "Skipping authentication...",
});
authenticationStatus = "SKIPPED";
telemetry.track({
name: "auth_token_configured",
payload: {
namespace: "onboarding",
origin: origin_trigger,
position: 2,
step_order: 2,
started_at: authStartedAuthAt,
ended_at: new Date().toISOString(),
status: "SKIPPED",
},
});

await minDelay(Promise.resolve());
} else {
/////////////////////////////////////////////////////////////////////
Expand All @@ -153,13 +162,23 @@
payload: {
namespace: "onboarding",
origin: origin_trigger,
position: 2,
step_order: 2,
auth_token: authToken,
started_at: authStartedAuthAt,
ended_at: new Date().toISOString(),
status: "CANCELLED",
},
});
telemetry.track(
get_setup_ended(
cliStatus,
"CANCELLED",
"SKIPPED",
"SKIPPED",
"CANCELLED",
await readAuthToken(),
),
);
return;
}

Expand All @@ -174,14 +193,23 @@
payload: {
namespace: "onboarding",
origin: origin_trigger,
position: 2,
step_order: 2,
auth_token: authToken,
started_at: authStartedAuthAt,
ended_at: new Date().toISOString(),
status: "CANCELLED",
},
});

telemetry.track(
get_setup_ended(
cliStatus,
"CANCELLED",
"SKIPPED",
"SKIPPED",
"CANCELLED",
authToken,
),
);
return;
}
}
Expand All @@ -193,6 +221,7 @@
// then there will be no license info to be reported by `localstack license info`.
// Also, an expired license could be cached.
// Activating the license pre-emptively to know its state during the setup process.
const licenseCheckStartedAt = new Date().toISOString();
const licenseIsValid = await minDelay(
activateLicense(outputChannel).then(() =>
checkIsLicenseValid(outputChannel),
Expand All @@ -213,10 +242,43 @@
}

if (cancellationToken.isCancellationRequested) {
telemetry.track({
name: "license_setup_ended",
payload: {
namespace: "onboarding",
step_order: 3,
origin: origin_trigger,
auth_token: await readAuthToken(),
started_at: licenseCheckStartedAt,
ended_at: new Date().toISOString(),
status: "CANCELLED",
},
});
telemetry.track(
get_setup_ended(
cliStatus,
authenticationStatus,
"CANCELLED",
"SKIPPED",
"CANCELLED",
await readAuthToken(),
),
);
return;
}

//TODO add telemetry
telemetry.track({
name: "license_setup_ended",
payload: {
namespace: "onboarding",
step_order: 3,
origin: origin_trigger,
auth_token: await readAuthToken(),
started_at: licenseCheckStartedAt,
ended_at: new Date().toISOString(),
status: "COMPLETED",
},
});

/////////////////////////////////////////////////////////////////////
progress.report({
Expand Down Expand Up @@ -245,50 +307,54 @@
}

if (cancellationToken.isCancellationRequested) {
telemetry.track({
name: "setup_ended",
payload: {
namespace: "onboarding",
steps: [1, 2, 3],
status: "CANCELLED",
},
});
telemetry.track(
get_setup_ended(
cliStatus,
authenticationStatus,
"COMPLETED",
"COMPLETED",
"CANCELLED",
await readAuthToken(),
),
);
return;
}

/////////////////////////////////////////////////////////////////////
if (localStackStatusTracker.status() === "running") {
window

Check warning on line 325 in src/plugins/setup.ts

View workflow job for this annotation

GitHub Actions / Lint

Promises must be awaited, end with a call to .catch, end with a call to .then with a rejection handler or be explicitly marked as ignored with the `void` operator
.showInformationMessage("LocalStack is running.", {
title: "View Logs",
command: "localstack.viewLogs",
})
.then((selection) => {
if (selection) {
commands.executeCommand(selection.command);

Check warning on line 332 in src/plugins/setup.ts

View workflow job for this annotation

GitHub Actions / Lint

Promises must be awaited, end with a call to .catch, end with a call to .then with a rejection handler or be explicitly marked as ignored with the `void` operator
}
});
} else {
window

Check warning on line 336 in src/plugins/setup.ts

View workflow job for this annotation

GitHub Actions / Lint

Promises must be awaited, end with a call to .catch, end with a call to .then with a rejection handler or be explicitly marked as ignored with the `void` operator
.showInformationMessage("LocalStack is ready to start.", {
title: "Start LocalStack",
command: "localstack.start",
})
.then((selection) => {
if (selection) {
commands.executeCommand(selection.command);

Check warning on line 343 in src/plugins/setup.ts

View workflow job for this annotation

GitHub Actions / Lint

Promises must be awaited, end with a call to .catch, end with a call to .then with a rejection handler or be explicitly marked as ignored with the `void` operator
}
});
}

telemetry.track({
name: "setup_ended",
payload: {
namespace: "onboarding",
steps: [1, 2, 3],
status: "COMPLETED",
},
});
telemetry.track(
get_setup_ended(
cliStatus,
authenticationStatus,
"COMPLETED",
"COMPLETED",
"COMPLETED",
await readAuthToken(),
),
);
},
);
},
Expand All @@ -296,14 +362,14 @@
);

if (setupStatusTracker.status() === "setup_required") {
window

Check warning on line 365 in src/plugins/setup.ts

View workflow job for this annotation

GitHub Actions / Lint

Promises must be awaited, end with a call to .catch, end with a call to .then with a rejection handler or be explicitly marked as ignored with the `void` operator
.showInformationMessage("Setup LocalStack to get started.", {
title: "Setup",
command: "localstack.setup",
})
.then((selected) => {
if (selected) {
commands.executeCommand(selected.command, "extension_startup");

Check warning on line 372 in src/plugins/setup.ts

View workflow job for this annotation

GitHub Actions / Lint

Promises must be awaited, end with a call to .catch, end with a call to .then with a rejection handler or be explicitly marked as ignored with the `void` operator
}
});
}
Expand Down
43 changes: 24 additions & 19 deletions src/utils/authenticate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,34 +124,39 @@ export async function saveAuthToken(
}
}

/**
* Checks if the user is authenticated by validating the stored auth token.
*
* License is validated separately
*
* @returns boolean indicating if the authentication is valid
*/
export async function checkIsAuthenticated() {
function isAuthTokenPresent(authObject: unknown) {
return (
typeof authObject === "object" &&
authObject !== null &&
AUTH_TOKEN_KEY in authObject
);
}

// Reads the auth token from the auth.json file for logging in the user
export async function readAuthToken(): Promise<string> {
try {
const authJson = await fs.readFile(LOCALSTACK_AUTH_FILENAME, "utf-8");
const authObject = JSON.parse(authJson) as unknown;
if (!isAuthTokenPresent(authObject)) {
return false;
return "";
}
const authToken = authObject[AUTH_TOKEN_KEY];
if (typeof authToken !== "string") {
return false;
return "";
}
return true;
} catch (error) {
return false;
return authToken;
} catch {
return "";
}
}

function isAuthTokenPresent(authObject: unknown) {
return (
typeof authObject === "object" &&
authObject !== null &&
AUTH_TOKEN_KEY in authObject
);
/**
* Checks if the user is authenticated by validating the stored auth token.
*
* License is validated separately
*
* @returns boolean indicating if the authentication is valid
*/
export async function checkIsAuthenticated() {
return (await readAuthToken()) !== "";
}
Loading
Loading