Prechádzať zdrojové kódy

enable azure gpu on frontend (#4226)

d-g-town 2 rokov pred
rodič
commit
05acfee3a3

+ 98 - 24
dashboard/src/components/AzureProvisionerSettings.tsx

@@ -33,7 +33,9 @@ import InputRow from "./form-components/InputRow";
 import Button from "./porter/Button";
 import Error from "./porter/Error";
 import Icon from "./porter/Icon";
+import InputSlider from "./porter/InputSlider";
 import Link from "./porter/Link";
+import Select from "./porter/Select";
 import Spacer from "./porter/Spacer";
 import Step from "./porter/Step";
 import Text from "./porter/Text";
@@ -53,6 +55,7 @@ type Props = RouteComponentProps & {
   provisionerError?: string;
   credentialId: string;
   clusterId?: number;
+  gpuModal?: boolean;
 };
 
 const VALID_CIDR_RANGE_PATTERN =
@@ -71,6 +74,11 @@ const AzureProvisionerSettings: React.FC<Props> = (props) => {
   const [clusterName, setClusterName] = useState("");
   const [azureLocation, setAzureLocation] = useState("eastus");
   const [machineType, setMachineType] = useState("Standard_B2als_v2");
+  const [gpuMinInstances, setGpuMinInstances] = useState(1);
+  const [gpuMaxInstances, setGpuMaxInstances] = useState(5);
+  const [gpuInstanceType, setGpuInstanceType] = useState(
+    "Standard_NC4as_T4_v3"
+  );
   const [isExpanded, setIsExpanded] = useState(false);
   const [minInstances, setMinInstances] = useState(1);
   const [maxInstances, setMaxInstances] = useState(10);
@@ -85,6 +93,12 @@ const AzureProvisionerSettings: React.FC<Props> = (props) => {
     regionFilteredMachineTypeOptions,
     setRegionFilteredMachineTypeOptions,
   ] = useState<MachineTypeOption[]>(azureSupportedMachineTypes(azureLocation));
+  const [
+    regionFilteredGPUMachineTypeOptions,
+    setRegionFilteredGPUMachineTypeOptions,
+  ] = useState<MachineTypeOption[]>(
+    azureSupportedMachineTypes(azureLocation, true)
+  );
 
   const { showIntercomWithMessage } = useIntercom();
 
@@ -92,6 +106,9 @@ const AzureProvisionerSettings: React.FC<Props> = (props) => {
     setRegionFilteredMachineTypeOptions(
       azureSupportedMachineTypes(azureLocation)
     );
+    setRegionFilteredGPUMachineTypeOptions(
+      azureSupportedMachineTypes(azureLocation, true)
+    );
   }, [azureLocation]);
 
   const markStepStarted = async (
@@ -188,6 +205,42 @@ const AzureProvisionerSettings: React.FC<Props> = (props) => {
       console.log(err);
     }
 
+    const nodePools = [
+      new AKSNodePool({
+        instanceType: "Standard_B2als_v2",
+        minInstances: 1,
+        maxInstances: 3,
+        nodePoolType: NodePoolType.SYSTEM,
+        mode: "User",
+      }),
+      new AKSNodePool({
+        instanceType: "Standard_B2as_v2",
+        minInstances: 1,
+        maxInstances: 3,
+        nodePoolType: NodePoolType.MONITORING,
+        mode: "User",
+      }),
+      new AKSNodePool({
+        instanceType: machineType,
+        minInstances: minInstances || 1,
+        maxInstances: maxInstances || 10,
+        nodePoolType: NodePoolType.APPLICATION,
+        mode: "User",
+      }),
+    ];
+
+    // Conditionally add the last EKSNodeGroup if gpuModal is enabled
+    if (props.gpuModal) {
+      nodePools.push(
+        new AKSNodePool({
+          instanceType: gpuInstanceType,
+          minInstances: gpuMinInstances || 0,
+          maxInstances: gpuMaxInstances || 5,
+          nodePoolType: NodePoolType.CUSTOM,
+        })
+      );
+    }
+
     const data = new Contract({
       cluster: new Cluster({
         projectId: currentProject.id,
@@ -201,29 +254,7 @@ const AzureProvisionerSettings: React.FC<Props> = (props) => {
             clusterVersion: clusterVersion || "v1.27.3",
             cidrRange: cidrRange || "10.78.0.0/16",
             location: azureLocation,
-            nodePools: [
-              new AKSNodePool({
-                instanceType: "Standard_B2als_v2",
-                minInstances: 1,
-                maxInstances: 3,
-                nodePoolType: NodePoolType.SYSTEM,
-                mode: "User",
-              }),
-              new AKSNodePool({
-                instanceType: "Standard_B2as_v2",
-                minInstances: 1,
-                maxInstances: 3,
-                nodePoolType: NodePoolType.MONITORING,
-                mode: "User",
-              }),
-              new AKSNodePool({
-                instanceType: machineType,
-                minInstances: minInstances || 1,
-                maxInstances: maxInstances || 10,
-                nodePoolType: NodePoolType.APPLICATION,
-                mode: "User",
-              }),
-            ],
+            nodePools,
             skuTier,
           }),
         },
@@ -317,7 +348,10 @@ const AzureProvisionerSettings: React.FC<Props> = (props) => {
 
     // TODO: pass in contract as the already parsed object, rather than JSON (requires changes to AWS/GCP provisioning)
     const contract = Contract.fromJsonString(
-      JSON.stringify(props.selectedClusterVersion)
+      JSON.stringify(props.selectedClusterVersion),
+      {
+        ignoreUnknownFields: true,
+      }
     );
 
     if (
@@ -471,6 +505,46 @@ const AzureProvisionerSettings: React.FC<Props> = (props) => {
     );
   };
 
+  if (props.gpuModal) {
+    return (
+      <>
+        <Select
+          options={regionFilteredGPUMachineTypeOptions}
+          width="350px"
+          disabled={isReadOnly}
+          value={gpuInstanceType}
+          setValue={(x: string) => {
+            setGpuInstanceType(x);
+          }}
+          label="GPU Instance type"
+        />
+        <Spacer y={1} />
+        <InputSlider
+          label="Max Instances: "
+          unit="nodes"
+          min={0}
+          max={5}
+          step={1}
+          width="350px"
+          disabled={isReadOnly}
+          value={gpuMaxInstances.toString()}
+          setValue={(x: number) => {
+            setGpuMaxInstances(x);
+          }}
+        />
+        <Button
+          disabled={isDisabled()}
+          onClick={createCluster}
+          status={getStatus()}
+        >
+          Provision
+        </Button>
+
+        <Spacer y={0.5} />
+      </>
+    );
+  }
+
   return (
     <>
       <StyledForm>{renderForm()}</StyledForm>

+ 100 - 3
dashboard/src/components/azureUtils.ts

@@ -25,17 +25,34 @@ export const AzureLocationOptions = [
 export type MachineTypeOption = {
   value: string;
   label: string;
+  resources: { vCPU: number; RAM: number; GPU?: number };
   supportedRegions: Set<string>;
 };
 
 export const azureSupportedMachineTypes = (
-  region: string
+  region: string,
+  gpu?: boolean
 ): MachineTypeOption[] => {
-  return AzureMachineTypeOptions.filter((option) =>
-    option.supportedRegions.has(region)
+  return AzureMachineTypeOptions.filter(
+    (option) =>
+      option.supportedRegions.has(region) && !!option.resources.GPU === !!gpu
   );
 };
 
+export const azureMachineTypeDetails = (
+  type: string
+): MachineTypeOption | undefined => {
+  const matches = AzureMachineTypeOptions.filter(
+    (option) => option.value === type
+  );
+
+  if (matches.length === 0) {
+    return undefined;
+  }
+
+  return matches[0];
+};
+
 // Retrieve updated list of supported regions by running the following command: az vm list-skus --all --output table | grep <INSTANCE_TYPE> | grep 1,2,3 | grep None | awk '{print "\047" tolower($2) "\047"}' | paste -s -d, -
 // last updated 12/19/2020
 //
@@ -44,6 +61,7 @@ const AzureMachineTypeOptions: MachineTypeOption[] = [
   {
     value: "Standard_B2als_v2",
     label: "Standard_B2als_v2",
+    resources: { vCPU: 2, RAM: 4 },
     supportedRegions: new Set<string>([
       "australiaeast",
       "brazilsouth",
@@ -71,6 +89,7 @@ const AzureMachineTypeOptions: MachineTypeOption[] = [
   {
     value: "Standard_B2as_v2",
     label: "Standard_B2as_v2",
+    resources: { vCPU: 2, RAM: 8 },
     supportedRegions: new Set<string>([
       "australiaeast",
       "brazilsouth",
@@ -98,6 +117,7 @@ const AzureMachineTypeOptions: MachineTypeOption[] = [
   {
     value: "Standard_A2_v2",
     label: "Standard_A2_v2",
+    resources: { vCPU: 2, RAM: 4 },
     supportedRegions: new Set<string>([
       "australiaeast",
       "canadacentral",
@@ -122,6 +142,7 @@ const AzureMachineTypeOptions: MachineTypeOption[] = [
   {
     value: "Standard_A4_v2",
     label: "Standard_A4_v2",
+    resources: { vCPU: 4, RAM: 8 },
     supportedRegions: new Set<string>([
       "australiaeast",
       "canadacentral",
@@ -146,6 +167,7 @@ const AzureMachineTypeOptions: MachineTypeOption[] = [
   {
     value: "Standard_DS1_v2",
     label: "Standard_DS1_v2",
+    resources: { vCPU: 1, RAM: 3.5 },
     supportedRegions: new Set<string>([
       "australiaeast",
       "canadacentral",
@@ -170,6 +192,7 @@ const AzureMachineTypeOptions: MachineTypeOption[] = [
   {
     value: "Standard_DS2_v2",
     label: "Standard_DS2_v2",
+    resources: { vCPU: 2, RAM: 7 },
     supportedRegions: new Set<string>([
       "australiaeast",
       "canadacentral",
@@ -202,6 +225,7 @@ const AzureMachineTypeOptions: MachineTypeOption[] = [
   {
     value: "Standard_D2ads_v5",
     label: "Standard_D2ads_v5",
+    resources: { vCPU: 2, RAM: 8 },
     supportedRegions: new Set<string>([
       "australiaeast",
       "canadacentral",
@@ -221,6 +245,7 @@ const AzureMachineTypeOptions: MachineTypeOption[] = [
   {
     value: "Standard_B4als_v2",
     label: "Standard_B4als_v2",
+    resources: { vCPU: 4, RAM: 8 },
     supportedRegions: new Set<string>([
       "australiaeast",
       "brazilsouth",
@@ -245,4 +270,76 @@ const AzureMachineTypeOptions: MachineTypeOption[] = [
       "westus3",
     ]),
   },
+  {
+    value: "Standard_NC4as_T4_v3",
+    label: "Standard_NC4as_T4_v3",
+    resources: { vCPU: 4, RAM: 28, GPU: 1 },
+    supportedRegions: new Set<string>([
+      "australiaeast",
+      "centralindia",
+      "eastus",
+      "eastus2",
+      "japaneast",
+      "northeurope",
+      "southcentralus",
+      "southeastasia",
+      "uksouth",
+      "westeurope",
+      "westus2",
+    ]),
+  },
+  {
+    value: "Standard_NC8as_T4_v3",
+    label: "Standard_NC8as_T4_v3",
+    resources: { vCPU: 8, RAM: 56, GPU: 1 },
+    supportedRegions: new Set<string>([
+      "australiaeast",
+      "centralindia",
+      "eastus",
+      "eastus2",
+      "japaneast",
+      "northeurope",
+      "southcentralus",
+      "southeastasia",
+      "uksouth",
+      "westeurope",
+      "westus2",
+    ]),
+  },
+  {
+    value: "Standard_NC16as_T4_v3",
+    label: "Standard_NC16as_T4_v3",
+    resources: { vCPU: 16, RAM: 110, GPU: 1 },
+    supportedRegions: new Set<string>([
+      "australiaeast",
+      "centralindia",
+      "eastus",
+      "eastus2",
+      "japaneast",
+      "northeurope",
+      "southcentralus",
+      "southeastasia",
+      "uksouth",
+      "westeurope",
+      "westus2",
+    ]),
+  },
+  {
+    value: "Standard_NC64as_T4_v3",
+    label: "Standard_NC64as_T4_v3",
+    resources: { vCPU: 64, RAM: 440, GPU: 4 },
+    supportedRegions: new Set<string>([
+      "australiaeast",
+      "centralindia",
+      "eastus",
+      "eastus2",
+      "japaneast",
+      "northeurope",
+      "southcentralus",
+      "southeastasia",
+      "uksouth",
+      "westeurope",
+      "westus2",
+    ]),
+  },
 ];

+ 11 - 4
dashboard/src/lib/hooks/useClusterResourceLimits.ts

@@ -12,12 +12,13 @@ import { z } from "zod";
 
 import {
   AWS_INSTANCE_LIMITS,
-  AZURE_INSTANCE_LIMITS,
   GPU_INSTANCE_LIMIT,
 } from "main/home/app-dashboard/validate-apply/services-settings/tabs/utils";
 
 import api from "shared/api";
 
+import { azureMachineTypeDetails } from "components/azureUtils";
+
 const DEFAULT_INSTANCE_CLASS = "t3";
 const DEFAULT_INSTANCE_SIZE = "medium";
 
@@ -131,12 +132,13 @@ const clusterNodesValidator = z
     }
     // Azure instance types are all prefixed with "Standard_"
     if (instanceType.startsWith("Standard_")) {
-      if (AZURE_INSTANCE_LIMITS[instanceType]) {
-        const { vCPU, RAM } = AZURE_INSTANCE_LIMITS[instanceType];
+      const azureMachineType = azureMachineTypeDetails(instanceType);
+      if (azureMachineType) {
+        const { vCPU, RAM, GPU } = azureMachineType.resources;
         return {
           maxCPU: vCPU,
           maxRAM: RAM,
-          maxGPU: 1,
+          maxGPU: GPU,
           azureType: instanceType,
         };
       } else {
@@ -384,6 +386,11 @@ export const useClusterResourceLimits = ({
                 ng.instanceType.includes("n1"))
           );
         })
+        .with({ kindValues: { case: "aksKind" } }, (c) => {
+          return c.kindValues.value.nodePools.some(
+            (ng) => ng.nodePoolType === NodePoolType.CUSTOM
+          );
+        })
         .otherwise(() => false);
 
       const loadBalancerType: ClientLoadBalancerType = match(contract)

+ 118 - 120
dashboard/src/main/home/app-dashboard/validate-apply/services-settings/tabs/Resources.tsx

@@ -228,130 +228,128 @@ const Resources: React.FC<ResourcesProps> = ({
         )}
       />
 
-      {(currentCluster?.cloud_provider === "AWS" ||
-        currentCluster?.cloud_provider === "GCP") &&
-        currentProject?.gpu_enabled && (
-          <>
-            <Spacer y={1} />
-            <Controller
-              name={`app.services.${index}.gpu`}
-              control={control}
-              render={({ field: { value, onChange } }) => (
-                <>
-                  <Container row>
-                    <Switch
-                      size="small"
-                      color="primary"
-                      checked={value.enabled.value}
-                      disabled={!clusterContainsGPUNodes}
-                      onChange={() => {
-                        onChange({
-                          ...value,
-                          enabled: {
-                            ...value.enabled,
-                            value: !value.enabled.value,
-                          },
-                          gpuCoresNvidia: {
-                            ...value.gpuCoresNvidia,
-                            value: value.enabled.value ? 0 : 1,
-                          },
-                        });
-                      }}
-                      inputProps={{ "aria-label": "controlled" }}
-                    />
-                    <Spacer inline x={0.5} />
-                    <Text>
-                      <>
-                        <span>Enable GPU</span>
-                      </>
-                    </Text>
-
-                    {!clusterContainsGPUNodes && (
-                      <>
-                        <Spacer inline x={1} />
-                        <Text color="helper">
-                          You cluster has no GPU nodes available.
-                        </Text>
-                        <Spacer inline x={0.5} />
-                        {currentCluster.status !== "UPDATING" && (
-                          <Tag>
-                            <Link
-                              onClick={() => {
-                                setClusterModalVisible(true);
-                              }}
-                            >
-                              <TagIcon src={addCircle} />
-                              Add GPU nodes
-                            </Link>
-                          </Tag>
-                        )}
-                      </>
-                    )}
-                  </Container>
-
-                  <Spacer y={0.5} />
-                  {clusterModalVisible && (
-                    <ProvisionClusterModal
-                      closeModal={() => {
-                        setClusterModalVisible(false);
-                      }}
-                      gpuModal={true}
-                      gcp={currentCluster?.cloud_provider === "GCP"}
-                    />
-                  )}
-                </>
-              )}
-            />
-            {maxGPU > 1 && gpu.value && (
+      {currentProject?.gpu_enabled && (
+        <>
+          <Spacer y={1} />
+          <Controller
+            name={`app.services.${index}.gpu`}
+            control={control}
+            render={({ field: { value, onChange } }) => (
               <>
-                <Spacer y={1} />
-                <Controller
-                  name={`app.services.${index}.gpu`}
-                  control={control}
-                  render={({ field: { value, onChange } }) => (
-                    <InputSlider
-                      label="GPU"
-                      unit=""
-                      min={0}
-                      max={maxGPU}
-                      value={value?.gpuCoresNvidia.value ?? "1"}
-                      disabled={value?.readOnly}
-                      setValue={(e) => {
-                        onChange({
-                          ...value,
-                          gpuCoresNvidia: {
-                            ...value.gpuCoresNvidia,
-                            value: e,
-                          },
-                        });
-                      }}
-                      disabledTooltip={
-                        "You may only edit this field in your porter.yaml."
-                      }
-                    />
+                <Container row>
+                  <Switch
+                    size="small"
+                    color="primary"
+                    checked={value.enabled.value}
+                    disabled={!clusterContainsGPUNodes}
+                    onChange={() => {
+                      onChange({
+                        ...value,
+                        enabled: {
+                          ...value.enabled,
+                          value: !value.enabled.value,
+                        },
+                        gpuCoresNvidia: {
+                          ...value.gpuCoresNvidia,
+                          value: value.enabled.value ? 0 : 1,
+                        },
+                      });
+                    }}
+                    inputProps={{ "aria-label": "controlled" }}
+                  />
+                  <Spacer inline x={0.5} />
+                  <Text>
+                    <>
+                      <span>Enable GPU</span>
+                    </>
+                  </Text>
+
+                  {!clusterContainsGPUNodes && (
+                    <>
+                      <Spacer inline x={1} />
+                      <Text color="helper">
+                        Your cluster has no GPU nodes available.
+                      </Text>
+                      <Spacer inline x={0.5} />
+                      {currentCluster.status !== "UPDATING" && (
+                        <Tag>
+                          <Link
+                            onClick={() => {
+                              setClusterModalVisible(true);
+                            }}
+                          >
+                            <TagIcon src={addCircle} />
+                            Add GPU nodes
+                          </Link>
+                        </Tag>
+                      )}
+                    </>
                   )}
-                />
+                </Container>
+
+                <Spacer y={0.5} />
+                {clusterModalVisible && (
+                  <ProvisionClusterModal
+                    closeModal={() => {
+                      setClusterModalVisible(false);
+                    }}
+                    gpuModal={true}
+                    gcp={currentCluster?.cloud_provider === "GCP"}
+                    azure={currentCluster?.cloud_provider === "Azure"}
+                  />
+                )}
               </>
             )}
-            {currentCluster.status === "UPDATING" &&
-              !clusterContainsGPUNodes && (
-                <CheckItemContainer>
-                  <CheckItemTop>
-                    <Loading offset="0px" width="20px" height="20px" />
-                    <Spacer inline x={1} />
-                    <Text>{"Cluster is updating..."}</Text>
-                    <Spacer inline x={1} />
-                    <Tag>
-                      <Link to={`/cluster-dashboard`}>
-                        <TagIcon src={infra} />
-                        View Status
-                      </Link>
-                    </Tag>
-                  </CheckItemTop>
-                </CheckItemContainer>
-              )}
-          </>
-        )}
+          />
+          {maxGPU > 1 && gpu.value && (
+            <>
+              <Spacer y={1} />
+              <Controller
+                name={`app.services.${index}.gpu`}
+                control={control}
+                render={({ field: { value, onChange } }) => (
+                  <InputSlider
+                    label="GPU"
+                    unit=""
+                    min={0}
+                    max={maxGPU}
+                    value={value?.gpuCoresNvidia.value ?? "1"}
+                    disabled={value?.readOnly}
+                    setValue={(e) => {
+                      onChange({
+                        ...value,
+                        gpuCoresNvidia: {
+                          ...value.gpuCoresNvidia,
+                          value: e,
+                        },
+                      });
+                    }}
+                    disabledTooltip={
+                      "You may only edit this field in your porter.yaml."
+                    }
+                  />
+                )}
+              />
+            </>
+          )}
+          {currentCluster.status === "UPDATING" && !clusterContainsGPUNodes && (
+            <CheckItemContainer>
+              <CheckItemTop>
+                <Loading offset="0px" width="20px" height="20px" />
+                <Spacer inline x={1} />
+                <Text>{"Cluster is updating..."}</Text>
+                <Spacer inline x={1} />
+                <Tag>
+                  <Link to={`/cluster-dashboard`}>
+                    <TagIcon src={infra} />
+                    View Status
+                  </Link>
+                </Tag>
+              </CheckItemTop>
+            </CheckItemContainer>
+          )}
+        </>
+      )}
       {match(service.config)
         .with({ type: "job" }, () => null)
         .with({ type: "predeploy" }, () => null)

+ 0 - 12
dashboard/src/main/home/app-dashboard/validate-apply/services-settings/tabs/utils.ts

@@ -139,18 +139,6 @@ export const AWS_INSTANCE_LIMITS: InstanceTypes = Object.freeze({
   },
 });
 
-// use values from Azure as base constant, convert to MB
-export const AZURE_INSTANCE_LIMITS: AzureInstanceTypes = Object.freeze({
-  Standard_B2als_v2: { vCPU: 2, RAM: 4 },
-  Standard_B2as_v2: { vCPU: 2, RAM: 8 },
-  Standard_B4als_v2: { vCPU: 4, RAM: 8 },
-  Standard_A2_v2: { vCPU: 2, RAM: 4 },
-  Standard_A4_v2: { vCPU: 4, RAM: 8 },
-  Standard_DS1_v2: { vCPU: 1, RAM: 3.5 },
-  Standard_DS2_v2: { vCPU: 2, RAM: 7 },
-  Standard_D2ads_v5: { vCPU: 2, RAM: 8 },
-});
-
 export const GPU_INSTANCE_LIMIT: InstanceTypes = Object.freeze({
   g4dn: {
     xlarge: { vCPU: 4, RAM: 16, GPU: 1 },

+ 67 - 65
dashboard/src/main/home/sidebar/ProvisionClusterModal.tsx

@@ -1,66 +1,63 @@
 import React, { useContext, useState } from "react";
 import { withRouter, type RouteComponentProps } from "react-router";
 import styled from "styled-components";
-import api from "shared/api";
+import { z } from "zod";
 
+import GCPProvisionerSettings from "components/GCPProvisionerSettings";
+import GPUCostConsent from "components/GPUCostConsent";
 import Modal from "components/porter/Modal";
 import Spacer from "components/porter/Spacer";
 import Text from "components/porter/Text";
 import ProvisionerSettings from "components/ProvisionerSettings";
-import GPUCostConsent from "components/GPUCostConsent";
+
+import api from "shared/api";
 import { Context } from "shared/Context";
-import ClusterRevisionSelector from "../cluster-dashboard/dashboard/ClusterRevisionSelector";
+import { type InfraCredentials } from "shared/types";
 
+import AzureProvisionerSettings from "../../../components/AzureProvisionerSettings";
+import ClusterRevisionSelector from "../cluster-dashboard/dashboard/ClusterRevisionSelector";
 import AWSCredentialsList from "./AddCluster/AWSCredentialList";
-import { type InfraCredentials } from "shared/types";
-import { z } from "zod";
-import GCPProvisionerSettings from "components/GCPProvisionerSettings";
 
 type Props = RouteComponentProps & {
   closeModal: () => void;
   gpuModal?: boolean;
   gcp?: boolean;
-}
-
+  azure?: boolean;
+};
 
 const ProvisionClusterModal: React.FC<Props> = ({
   closeModal,
   gpuModal,
   gcp,
+  azure,
 }) => {
-  const {
-    currentCluster,
-    currentProject
-  } = useContext(Context);
+  const { currentCluster, currentProject } = useContext(Context);
 
-  const [currentCredential, setCurrentCredential] = useState<InfraCredentials>(
-    null
-  );
+  const [currentCredential, setCurrentCredential] =
+    useState<InfraCredentials>(null);
   const [currentStep, setCurrentStep] = useState("cloud");
-  const [targetArn, setTargetARN] = useState("")
-  const [selectedClusterVersion, setSelectedClusterVersion] = useState<ContractData>();
+  const [targetArn, setTargetARN] = useState("");
+  const [selectedClusterVersion, setSelectedClusterVersion] =
+    useState<ContractData>();
   const [showProvisionerStatus, setShowProvisionerStatus] = useState(false);
   const [provisionFailureReason, setProvisionFailureReason] = useState("");
 
-
-
   return (
     <Modal closeModal={closeModal} width={"1000px"}>
-      {gpuModal ? <>
-        <Text size={16}>
-          Add A GPU workload
-        </Text>
-        <Spacer y={.5} />
-        <Text color="helper" >
-          To enable GPU workloads on this service, you need to provision new GPU nodes.
-        </Text>
-      </>
-        : <Text size={16}>
-          Provision A New Cluster
-        </Text>}
+      {gpuModal ? (
+        <>
+          <Text size={16}>Add A GPU workload</Text>
+          <Spacer y={0.5} />
+          <Text color="helper">
+            To enable GPU workloads on this service, you need to provision new
+            GPU nodes.
+          </Text>
+        </>
+      ) : (
+        <Text size={16}>Provision A New Cluster</Text>
+      )}
       <Spacer y={1} />
 
-
       <ScrollableContent>
         <>
           {gpuModal ? (
@@ -77,7 +74,19 @@ const ProvisionClusterModal: React.FC<Props> = ({
                 <GCPProvisionerSettings
                   clusterId={gpuModal ? currentCluster?.id : null}
                   gpuModal={gpuModal}
-                  credentialId={currentCluster.cloud_provider_credential_identifier}
+                  credentialId={
+                    currentCluster.cloud_provider_credential_identifier
+                  }
+                  selectedClusterVersion={selectedClusterVersion}
+                  closeModal={closeModal}
+                />
+              ) : azure ? (
+                <AzureProvisionerSettings
+                  clusterId={gpuModal ? currentCluster?.id : undefined}
+                  gpuModal={gpuModal}
+                  credentialId={
+                    currentCluster.cloud_provider_credential_identifier
+                  }
                   selectedClusterVersion={selectedClusterVersion}
                   closeModal={closeModal}
                 />
@@ -85,45 +94,38 @@ const ProvisionClusterModal: React.FC<Props> = ({
                 <ProvisionerSettings
                   clusterId={gpuModal ? currentCluster?.id : undefined}
                   gpuModal={gpuModal}
-                  credentialId={currentCluster.cloud_provider_credential_identifier}
+                  credentialId={
+                    currentCluster.cloud_provider_credential_identifier
+                  }
                   selectedClusterVersion={selectedClusterVersion}
                   closeModal={closeModal}
                 />
               )}
-
-
             </>
-          ) :
-            (
-              currentCredential && targetArn ? (
-                <>
-                  <ProvisionerSettings
-                    credentialId={targetArn}
-                    closeModal={closeModal}
-                    clusterId={gpuModal ? currentCluster?.id : null}
-                  />
-                </>
-              ) : (
-                <AWSCredentialsList
-                  setTargetARN={setTargetARN}
-                  selectCredential={
-                    (i) => {
-                      setCurrentCredential({
-                        aws_integration_id: i,
-                      });
-                    }
-                  }
-                  gpuModal={gpuModal}
-                />
-              )
-            )}
+          ) : currentCredential && targetArn ? (
+            <>
+              <ProvisionerSettings
+                credentialId={targetArn}
+                closeModal={closeModal}
+                clusterId={gpuModal ? currentCluster?.id : null}
+              />
+            </>
+          ) : (
+            <AWSCredentialsList
+              setTargetARN={setTargetARN}
+              selectCredential={(i) => {
+                setCurrentCredential({
+                  aws_integration_id: i,
+                });
+              }}
+              gpuModal={gpuModal}
+            />
+          )}
         </>
       </ScrollableContent>
-
-
-    </Modal >
-  )
-}
+    </Modal>
+  );
+};
 
 export default withRouter(ProvisionClusterModal);