Skip to content

Commit

Permalink
support percent completion indication for cloud credential update (#4380
Browse files Browse the repository at this point in the history
)
  • Loading branch information
Feroze Mohideen authored Mar 6, 2024
1 parent 459df01 commit 37889b5
Show file tree
Hide file tree
Showing 7 changed files with 83 additions and 51 deletions.
1 change: 1 addition & 0 deletions api/server/handlers/project_integration/create_aws.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ func (p *CreateAWSHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
return
}
res.CloudProviderCredentialIdentifier = credResp.Msg.CredentialsIdentifier
res.PercentCompleted = credResp.Msg.PercentCompleted
} else {
credReq := porterv1.CreateAssumeRoleChainRequest{ //nolint:staticcheck // being deprecated by the above UpdateCloudProviderCredentials
ProjectId: int64(project.ID),
Expand Down
3 changes: 2 additions & 1 deletion api/types/project_integration.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,8 @@ type CreateAWSRequest struct {

type CreateAWSResponse struct {
*AWSIntegration
CloudProviderCredentialIdentifier string `json:"cloud_provider_credentials_id"`
CloudProviderCredentialIdentifier string `json:"cloud_provider_credentials_id"`
PercentCompleted float32 `json:"percent_completed"`
}

type OverwriteAWSRequest struct {
Expand Down
12 changes: 9 additions & 3 deletions dashboard/src/lib/hooks/useCloudProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,22 @@ export const isAWSArnAccessible = async ({
targetArn: string;
externalId: string;
projectId: number;
}): Promise<boolean> => {
await api.createAWSIntegration(
}): Promise<number> => {
const res = await api.createAWSIntegration(
"<token>",
{
aws_target_arn: targetArn,
aws_external_id: externalId,
},
{ id: projectId }
);
return true;
const parsed = await z
.object({
percent_completed: z.number(),
})
.parseAsync(res.data);

return parsed.percent_completed;
};

export const connectToAzureAccount = async ({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import Image from "components/porter/Image";
import Input from "components/porter/Input";
import Link from "components/porter/Link";
import Spacer from "components/porter/Spacer";
import StatusBar from "components/porter/StatusBar";
import Text from "components/porter/Text";
import VerticalSteps from "components/porter/VerticalSteps";
import { type ButtonStatus } from "main/home/app-dashboard/app-view/AppDataContainer";
Expand All @@ -22,7 +23,6 @@ import { useClusterAnalytics } from "lib/hooks/useClusterAnalytics";
import { useIntercom } from "lib/hooks/useIntercom";

import GrantAWSPermissionsHelpModal from "../../modals/help/permissions/GrantAWSPermissionsHelpModal";
import { CheckItem } from "../../modals/PreflightChecksModal";

type Props = {
goBack: () => void;
Expand All @@ -44,7 +44,8 @@ const GrantAWSPermissions: React.FC<Props> = ({
const [showNeedHelpModal, setShowNeedHelpModal] = useState(false);
const [accountIdContinueButtonStatus, setAccountIdContinueButtonStatus] =
useState<ButtonStatus>("");
const [isAccountAccessible, setIsAccountAccessible] = useState(false);
const [permissionsGrantCompletionPercentage, setAWSPermissionsProgress] =
useState(0);
const { reportToAnalytics } = useClusterAnalytics();
const { showIntercomWithMessage } = useIntercom();

Expand All @@ -71,53 +72,74 @@ const GrantAWSPermissions: React.FC<Props> = ({
return externalId;
}, [AWSAccountID, awsAccountIdInputError]);

const awsPermissionsLoadingMessage = useMemo(() => {
if (permissionsGrantCompletionPercentage === 0) {
return "Setting up access roles and policies...";
}
if (permissionsGrantCompletionPercentage < 50) {
return "Creating cluster management roles...";
}
if (permissionsGrantCompletionPercentage < 100) {
return "Creating cluster management policies...";
}
return "";
}, [permissionsGrantCompletionPercentage]);

const data = useQuery(
[
"cloudFormationStackCreated",
AWSAccountID,
projectId,
isAccountAccessible,
permissionsGrantCompletionPercentage,
externalId,
],
async () => {
try {
await isAWSArnAccessible({
const res = await isAWSArnAccessible({
targetArn: `arn:aws:iam::${AWSAccountID}:role/porter-manager`,
externalId,
projectId,
});
return true;
return res;
} catch (err) {
return false;
return 0;
}
},
{
enabled: currentStep === 3 && !isAccountAccessible, // no need to check if it's already accessible
enabled:
currentStep === 3 && permissionsGrantCompletionPercentage !== 100, // no need to check if it's already accessible
refetchInterval: 5000,
refetchIntervalInBackground: true,
}
);
useEffect(() => {
if (data.isSuccess) {
setIsAccountAccessible(data.data);
setAWSPermissionsProgress(data.data);
}
}, [data]);

const handleAWSAccountIDChange = (accountId: string): void => {
setAWSAccountID(accountId);
setIsAccountAccessible(false); // any time they change the account ID, we need to re-check if it's accessible
setAWSPermissionsProgress(0); // any time they change the account ID, we need to re-check if it's accessible
};

const checkIfAlreadyAccessible = async (): Promise<void> => {
setAccountIdContinueButtonStatus("loading");
try {
await isAWSArnAccessible({
const awsIntegrationPercentCompleted = await isAWSArnAccessible({
targetArn: `arn:aws:iam::${AWSAccountID}:role/porter-manager`,
externalId,
projectId,
});
setCurrentStep(3);
setIsAccountAccessible(true);
if (awsIntegrationPercentCompleted > 0) {
// this indicates the permission check is already in place; no need to re-create cloudformation stack
setCurrentStep(3);
setAWSPermissionsProgress(awsIntegrationPercentCompleted);
setAccountIdContinueButtonStatus("");
} else {
setCurrentStep(2);
setAccountIdContinueButtonStatus("");
}
} catch (err) {
let shouldProceed = true;
if (axios.isAxiosError(err)) {
Expand Down Expand Up @@ -266,6 +288,7 @@ const GrantAWSPermissions: React.FC<Props> = ({
setCurrentStep(0);
setAccountIdContinueButtonStatus("");
setAWSAccountID("");
setAWSPermissionsProgress(0);
}}
color="#222222"
>
Expand Down Expand Up @@ -308,7 +331,7 @@ const GrantAWSPermissions: React.FC<Props> = ({
onClick={directToCloudFormation}
color="linear-gradient(180deg, #26292e, #24272c)"
withBorder
disabled={isAccountAccessible}
disabled={permissionsGrantCompletionPercentage === 100}
disabledTooltipMessage={
"Porter can already access your account!"
}
Expand Down Expand Up @@ -338,36 +361,33 @@ const GrantAWSPermissions: React.FC<Props> = ({
</>,
<>
<Text size={16}>Check permissions</Text>
<Spacer y={0.5} />
<Text color="helper">
Checking if Porter can access AWS account with ID {AWSAccountID}
. This can take up to 10 minutes.
<Spacer inline width="10px" />
<Link
hasunderline
onClick={() => {
setShowNeedHelpModal(true);
}}
>
Need help?
</Link>
</Text>
<Spacer y={1} />
{isAccountAccessible ? (
<CheckItem
preflightCheck={{
title: "AWS account is accessible by Porter!",
status: "success",
}}
/>
) : (
<CheckItem
preflightCheck={{
title: "Checking if AWS account is accessible by Porter",
status: "pending",
}}
/>
)}
<StatusBar
icon={CloudProviderAWS.icon}
title={"AWS permissions setup"}
titleDescriptor={awsPermissionsLoadingMessage}
subtitle={
permissionsGrantCompletionPercentage === 100
? "Porter can access your account! You may now continue."
: "Porter is creating roles and policies to access your account. This can take up to 15 minutes. Please stay on this page."
}
percentCompleted={Math.max(
permissionsGrantCompletionPercentage,
5
)}
/>
<Spacer y={0.5} />
<Link
hasunderline
onClick={() => {
showIntercomWithMessage({
message: "I need help with AWS permissions setup.",
delaySeconds: 0,
});
}}
>
Need help?
</Link>
<Spacer y={1} />
<Container row>
<Button
Expand All @@ -381,7 +401,7 @@ const GrantAWSPermissions: React.FC<Props> = ({
<Spacer inline x={0.5} />
<Button
onClick={handleGrantPermissionsComplete}
disabled={!isAccountAccessible}
disabled={permissionsGrantCompletionPercentage !== 100}
>
Continue
</Button>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,11 @@ const CreateAKSClusterForm: React.FC<Props> = ({
const { reportToAnalytics } = useClusterAnalytics();

useEffect(() => {
const projectNameLimit = 31 - "-cluster-".length - 6; // 6 characters for the random suffix
const truncatedProjectName = projectName.substring(0, projectNameLimit);
const clusterName = `${truncatedProjectName}-cluster-${Math.random()
const truncatedProjectName = projectName
.substring(0, 24)
.replace(/-+$/, "");

const clusterName = `${truncatedProjectName}-${Math.random()
.toString(36)
.substring(2, 8)}`;

Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ require (
github.com/matryer/is v1.4.0
github.com/nats-io/nats.go v1.24.0
github.com/open-policy-agent/opa v0.44.0
github.com/porter-dev/api-contracts v0.2.113
github.com/porter-dev/api-contracts v0.2.114
github.com/riandyrn/otelchi v0.5.1
github.com/santhosh-tekuri/jsonschema/v5 v5.0.1
github.com/stefanmcshane/helm v0.0.0-20221213002717-88a4a2c6e77d
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1525,6 +1525,8 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
github.com/polyfloyd/go-errorlint v0.0.0-20210722154253-910bb7978349/go.mod h1:wi9BfjxjF/bwiZ701TzmfKu6UKC357IOAtNr0Td0Lvw=
github.com/porter-dev/api-contracts v0.2.113 h1:sv1huO9MpykJaWhV2D5zTD2LouMbRSBV5ATt/5Ukrbo=
github.com/porter-dev/api-contracts v0.2.113/go.mod h1:fX6JmP5QuzxDLvqP3evFOTXjI4dHxsG0+VKNTjImZU8=
github.com/porter-dev/api-contracts v0.2.114 h1:qfEq70BJ8xXTkiZU7ygzOSGnMCqJHOa5Lbkfu4OzQBI=
github.com/porter-dev/api-contracts v0.2.114/go.mod h1:fX6JmP5QuzxDLvqP3evFOTXjI4dHxsG0+VKNTjImZU8=
github.com/porter-dev/switchboard v0.0.3 h1:dBuYkiVLa5Ce7059d6qTe9a1C2XEORFEanhbtV92R+M=
github.com/porter-dev/switchboard v0.0.3/go.mod h1:xSPzqSFMQ6OSbp42fhCi4AbGbQbsm6nRvOkrblFeXU4=
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
Expand Down

0 comments on commit 37889b5

Please sign in to comment.