Skip to content

Commit

Permalink
refactor preflight checks so we can call them elsewhere (#4653)
Browse files Browse the repository at this point in the history
  • Loading branch information
Feroze Mohideen authored May 16, 2024
1 parent 094315d commit e2fe66d
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 75 deletions.
155 changes: 85 additions & 70 deletions dashboard/src/lib/hooks/useCluster.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import { useContext, useState } from "react";
import { Contract, PreflightCheckRequest } from "@porter-dev/api-contracts";
import {
Contract,
EnumCloudProvider,
PreflightCheckRequest,
} from "@porter-dev/api-contracts";
import { useQuery } from "@tanstack/react-query";
import axios from "axios";
import { match } from "ts-pattern";
Expand Down Expand Up @@ -334,6 +338,80 @@ export const useClusterState = ({
};
};

export const preflightChecks = async (
contract: Contract,
projectId: number
): Promise<UpdateClusterResponse["preflightChecks"]> => {
if (!contract.cluster) {
throw new Error("Cluster is missing");
}

let preflightCheckResp;
if (
contract.cluster.cloudProvider === EnumCloudProvider.AWS ||
contract.cluster.cloudProvider === EnumCloudProvider.AZURE
) {
preflightCheckResp = await api.cloudContractPreflightCheck(
"<token>",
contract,
{
project_id: projectId,
}
);
} else {
preflightCheckResp = await api.legacyPreflightCheck(
"<token>",
new PreflightCheckRequest({
contract,
}),
{
id: projectId,
}
);
}

const parsed = await preflightCheckValidator.parseAsync(
preflightCheckResp.data
);

if (parsed.errors.length > 0) {
const cloudProviderSpecificChecks = match(contract.cluster.cloudProvider)
.with(EnumCloudProvider.AWS, () => CloudProviderAWS.preflightChecks)
.with(EnumCloudProvider.GCP, () => CloudProviderGCP.preflightChecks)
.with(EnumCloudProvider.AZURE, () => CloudProviderAzure.preflightChecks)
.otherwise(() => []);

return parsed.errors.map((e) => {
return match(
cloudProviderSpecificChecks.find(
(cloudProviderCheck) => e.name === cloudProviderCheck.name
)
)
.returnType<ClientPreflightCheck>()
.with(undefined, () => ({
title: "Unknown preflight check",
status: "failure" as const,
name: "UNKNOWN" as const,
error: {
detail:
"Your cloud provider returned an unknown error. Please reach out to Porter support.",
metadata: {},
},
}))
.otherwise((preflightCheckMatch) => ({
title: preflightCheckMatch.displayName,
status: "failure" as const,
name: preflightCheckMatch.name,
error: {
detail: e.error.message,
metadata: e.error.metadata,
resolution: preflightCheckMatch.resolution,
},
}));
});
}
};

type TUseUpdateCluster = {
updateCluster: (
clientContract: ClientClusterContract,
Expand All @@ -343,6 +421,7 @@ type TUseUpdateCluster = {
isHandlingPreflightChecks: boolean;
isCreatingContract: boolean;
};

export const useUpdateCluster = ({
projectId,
}: {
Expand Down Expand Up @@ -374,76 +453,12 @@ export const useUpdateCluster = ({
if (!skipPreflightChecks) {
setIsHandlingPreflightChecks(true);
try {
let preflightCheckResp;
if (
clientContract.cluster.cloudProvider === "AWS" ||
clientContract.cluster.cloudProvider === "Azure"
) {
preflightCheckResp = await api.cloudContractPreflightCheck(
"<token>",
newContract,
{
project_id: projectId,
}
);
} else {
preflightCheckResp = await api.legacyPreflightCheck(
"<token>",
new PreflightCheckRequest({
contract: newContract,
}),
{
id: projectId,
}
);
}

const parsed = await preflightCheckValidator.parseAsync(
preflightCheckResp.data
const preflightCheckResults = await preflightChecks(
newContract,
projectId
);

if (parsed.errors.length > 0) {
const cloudProviderSpecificChecks = match(
clientContract.cluster.cloudProvider
)
.with("AWS", () => CloudProviderAWS.preflightChecks)
.with("GCP", () => CloudProviderGCP.preflightChecks)
.with("Azure", () => CloudProviderAzure.preflightChecks)
.otherwise(() => []);

const clientPreflightChecks: ClientPreflightCheck[] = parsed.errors
.map((e) => {
const preflightCheckMatch = cloudProviderSpecificChecks.find(
(cloudProviderCheck) => e.name === cloudProviderCheck.name
);
if (!preflightCheckMatch) {
return {
title: "Unknown preflight check",
status: "failure" as const,
name: "UNKNOWN" as const,
error: {
detail:
"Your cloud provider returned an unknown error. Please reach out to Porter support.",
metadata: {},
},
};
}
return {
title: preflightCheckMatch.displayName,
status: "failure" as const,
name: preflightCheckMatch.name,
error: {
detail: e.error.message,
metadata: e.error.metadata,
resolution: preflightCheckMatch.resolution,
},
};
})
.filter(valueExists);

return {
preflightChecks: clientPreflightChecks,
};
if (preflightCheckResults) {
return { preflightChecks: preflightCheckResults };
}
// otherwise, continue to create the contract
} catch (err) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ const PreflightChecksModal: React.FC<Props> = ({
);

const acceptChanges = async (): Promise<void> => {
void submitAndPatchCheckSuggestions({
await submitAndPatchCheckSuggestions({
preflightChecks: checksWithSuggestions,
});
onClose();
Expand All @@ -140,8 +140,8 @@ const PreflightChecksModal: React.FC<Props> = ({
</Text>
<PorterOperatorComponent>
<Button
onClick={async () => {
await submitSkippingPreflightChecks();
onClick={() => {
void submitSkippingPreflightChecks();
}}
color="red"
>
Expand All @@ -162,8 +162,8 @@ const PreflightChecksModal: React.FC<Props> = ({
<ButtonContainer>
{allHaveSuggestions ? (
<Button
onClick={async () => {
await acceptChanges();
onClick={() => {
void acceptChanges();
}}
>
<Icon src={file_diff} height={"15px"} />
Expand Down

0 comments on commit e2fe66d

Please sign in to comment.