From 84d482c2c133a4a2e01ce0801017806b3649799b Mon Sep 17 00:00:00 2001 From: Feroze Mohideen Date: Wed, 21 Feb 2024 18:24:54 -0500 Subject: [PATCH] Add gpu + instance types (#4310) --- .../project_integration/preflight_check.go | 3 + dashboard/src/lib/clusters/constants.ts | 163 ++++++++++++++- dashboard/src/lib/clusters/types.ts | 9 + .../app-dashboard/create-app/CreateApp.tsx | 12 +- .../ClusterStatus.tsx | 31 ++- .../modals/PreflightChecksModal.tsx | 14 +- .../ResolutionStepsModalContents.tsx | 5 + .../shared/NodeGroups.tsx | 193 ++++++++++++++++-- .../src/main/home/sidebar/ClusterList.tsx | 43 +++- dashboard/src/shared/types.tsx | 2 +- 10 files changed, 424 insertions(+), 51 deletions(-) diff --git a/api/server/handlers/project_integration/preflight_check.go b/api/server/handlers/project_integration/preflight_check.go index 986f895750..d65bc98e92 100644 --- a/api/server/handlers/project_integration/preflight_check.go +++ b/api/server/handlers/project_integration/preflight_check.go @@ -1,6 +1,7 @@ package project_integration import ( + "fmt" "net/http" "connectrpc.com/connect" @@ -109,6 +110,8 @@ func (p *CreatePreflightCheckHandler) ServeHTTP(w http.ResponseWriter, r *http.R return } + fmt.Printf("here is the checkResp: %v\n", checkResp.Msg.PreflightChecks) + errors := []PreflightCheckError{} for key, val := range checkResp.Msg.PreflightChecks { if val.Message == "" || !contains(recognizedPreflightCheckKeys, key) { diff --git a/dashboard/src/lib/clusters/constants.ts b/dashboard/src/lib/clusters/constants.ts index f5f37c4cc5..1feb7f934b 100644 --- a/dashboard/src/lib/clusters/constants.ts +++ b/dashboard/src/lib/clusters/constants.ts @@ -99,336 +99,451 @@ const SUPPORTED_AWS_MACHINE_TYPES: ClientMachineType[] = [ name: "t3.medium", displayName: "t3.medium", supportedRegions: SUPPORTED_AWS_REGIONS.map((r) => r.name), + isGPU: false, }, { name: "t3.large", displayName: "t3.large", supportedRegions: SUPPORTED_AWS_REGIONS.map((r) => r.name), + isGPU: false, }, { name: "t3.xlarge", displayName: "t3.xlarge", supportedRegions: SUPPORTED_AWS_REGIONS.map((r) => r.name), + isGPU: false, }, { name: "t3.2xlarge", displayName: "t3.2xlarge", supportedRegions: SUPPORTED_AWS_REGIONS.map((r) => r.name), + isGPU: false, }, { name: "t3a.medium", displayName: "t3a.medium", supportedRegions: SUPPORTED_AWS_REGIONS.map((r) => r.name), + isGPU: false, }, { name: "t3a.large", displayName: "t3a.large", supportedRegions: SUPPORTED_AWS_REGIONS.map((r) => r.name), + isGPU: false, }, { name: "t3a.xlarge", displayName: "t3a.xlarge", supportedRegions: SUPPORTED_AWS_REGIONS.map((r) => r.name), + isGPU: false, }, { name: "t3a.2xlarge", displayName: "t3a.2xlarge", supportedRegions: SUPPORTED_AWS_REGIONS.map((r) => r.name), + isGPU: false, }, { name: "t4g.medium", displayName: "t4g.medium", supportedRegions: SUPPORTED_AWS_REGIONS.map((r) => r.name), + isGPU: false, }, { name: "t4g.large", displayName: "t4g.large", supportedRegions: SUPPORTED_AWS_REGIONS.map((r) => r.name), + isGPU: false, }, { name: "t4g.xlarge", displayName: "t4g.xlarge", supportedRegions: SUPPORTED_AWS_REGIONS.map((r) => r.name), + isGPU: false, }, { name: "t4g.2xlarge", displayName: "t4g.2xlarge", supportedRegions: SUPPORTED_AWS_REGIONS.map((r) => r.name), + isGPU: false, }, { name: "c6i.large", displayName: "c6i.large", supportedRegions: SUPPORTED_AWS_REGIONS.map((r) => r.name), + isGPU: false, }, { name: "c6i.xlarge", displayName: "c6i.xlarge", supportedRegions: SUPPORTED_AWS_REGIONS.map((r) => r.name), + isGPU: false, }, { name: "c6i.2xlarge", displayName: "c6i.2xlarge", supportedRegions: SUPPORTED_AWS_REGIONS.map((r) => r.name), + isGPU: false, }, { name: "c6i.4xlarge", displayName: "c6i.4xlarge", supportedRegions: SUPPORTED_AWS_REGIONS.map((r) => r.name), + isGPU: false, }, { name: "c6i.8xlarge", displayName: "c6i.8xlarge", supportedRegions: SUPPORTED_AWS_REGIONS.map((r) => r.name), + isGPU: false, }, { name: "c6a.large", displayName: "c6a.large", supportedRegions: SUPPORTED_AWS_REGIONS.map((r) => r.name), + isGPU: false, }, { name: "c6a.2xlarge", displayName: "c6a.2xlarge", supportedRegions: SUPPORTED_AWS_REGIONS.map((r) => r.name), + isGPU: false, }, { name: "c6a.4xlarge", displayName: "c6a.4xlarge", supportedRegions: SUPPORTED_AWS_REGIONS.map((r) => r.name), + isGPU: false, }, { name: "c6a.8xlarge", displayName: "c6a.8xlarge", supportedRegions: SUPPORTED_AWS_REGIONS.map((r) => r.name), + isGPU: false, }, { name: "r6i.large", displayName: "r6i.large", supportedRegions: SUPPORTED_AWS_REGIONS.map((r) => r.name), + isGPU: false, }, { name: "r6i.xlarge", displayName: "r6i.xlarge", supportedRegions: SUPPORTED_AWS_REGIONS.map((r) => r.name), + isGPU: false, }, { name: "r6i.2xlarge", displayName: "r6i.2xlarge", supportedRegions: SUPPORTED_AWS_REGIONS.map((r) => r.name), + isGPU: false, }, { name: "r6i.4xlarge", displayName: "r6i.4xlarge", supportedRegions: SUPPORTED_AWS_REGIONS.map((r) => r.name), + isGPU: false, }, { name: "r6i.8xlarge", displayName: "r6i.8xlarge", supportedRegions: SUPPORTED_AWS_REGIONS.map((r) => r.name), + isGPU: false, }, { name: "r6i.12xlarge", displayName: "r6i.12xlarge", supportedRegions: SUPPORTED_AWS_REGIONS.map((r) => r.name), + isGPU: false, }, { name: "r6i.16xlarge", displayName: "r6i.16xlarge", supportedRegions: SUPPORTED_AWS_REGIONS.map((r) => r.name), + isGPU: false, }, { name: "r6i.24xlarge", displayName: "r6i.24xlarge", supportedRegions: SUPPORTED_AWS_REGIONS.map((r) => r.name), + isGPU: false, }, { name: "r6i.32xlarge", displayName: "r6i.32xlarge", supportedRegions: SUPPORTED_AWS_REGIONS.map((r) => r.name), + isGPU: false, }, { name: "m5n.large", displayName: "m5n.large", supportedRegions: SUPPORTED_AWS_REGIONS.map((r) => r.name), + isGPU: false, }, { name: "m5n.xlarge", displayName: "m5n.xlarge", supportedRegions: SUPPORTED_AWS_REGIONS.map((r) => r.name), + isGPU: false, }, { name: "m5n.2xlarge", displayName: "m5n.2xlarge", supportedRegions: SUPPORTED_AWS_REGIONS.map((r) => r.name), + isGPU: false, }, { name: "m6a.large", displayName: "m6a.large", supportedRegions: SUPPORTED_AWS_REGIONS.map((r) => r.name), + isGPU: false, }, { name: "m6a.xlarge", displayName: "m6a.xlarge", supportedRegions: SUPPORTED_AWS_REGIONS.map((r) => r.name), + isGPU: false, }, { name: "m6a.2xlarge", displayName: "m6a.2xlarge", supportedRegions: SUPPORTED_AWS_REGIONS.map((r) => r.name), + isGPU: false, }, { name: "m6a.4xlarge", displayName: "m6a.4xlarge", supportedRegions: SUPPORTED_AWS_REGIONS.map((r) => r.name), + isGPU: false, }, { name: "m6a.8xlarge", displayName: "m6a.8xlarge", supportedRegions: SUPPORTED_AWS_REGIONS.map((r) => r.name), + isGPU: false, }, { name: "m6a.12xlarge", displayName: "m6a.12xlarge", supportedRegions: SUPPORTED_AWS_REGIONS.map((r) => r.name), + isGPU: false, }, { name: "m7a.medium", displayName: "m7a.medium", supportedRegions: SUPPORTED_AWS_REGIONS.map((r) => r.name), + isGPU: false, }, { name: "m7a.large", displayName: "m7a.large", supportedRegions: SUPPORTED_AWS_REGIONS.map((r) => r.name), + isGPU: false, }, { name: "m7a.xlarge", displayName: "m7a.xlarge", supportedRegions: SUPPORTED_AWS_REGIONS.map((r) => r.name), + isGPU: false, }, { name: "m7a.2xlarge", displayName: "m7a.2xlarge", supportedRegions: SUPPORTED_AWS_REGIONS.map((r) => r.name), + isGPU: false, }, { name: "m7a.4xlarge", displayName: "m7a.4xlarge", supportedRegions: SUPPORTED_AWS_REGIONS.map((r) => r.name), + isGPU: false, }, { name: "m7a.8xlarge", displayName: "m7a.8xlarge", supportedRegions: SUPPORTED_AWS_REGIONS.map((r) => r.name), + isGPU: false, }, { name: "m7a.12xlarge", displayName: "m7a.12xlarge", supportedRegions: SUPPORTED_AWS_REGIONS.map((r) => r.name), + isGPU: false, }, { name: "m7a.16xlarge", displayName: "m7a.16xlarge", supportedRegions: SUPPORTED_AWS_REGIONS.map((r) => r.name), + isGPU: false, }, { name: "m7a.24xlarge", displayName: "m7a.24xlarge", supportedRegions: SUPPORTED_AWS_REGIONS.map((r) => r.name), + isGPU: false, }, { name: "m7i.large", displayName: "m7i.large", supportedRegions: SUPPORTED_AWS_REGIONS.map((r) => r.name), + isGPU: false, }, { name: "m7i.xlarge", displayName: "m7i.xlarge", supportedRegions: SUPPORTED_AWS_REGIONS.map((r) => r.name), + isGPU: false, }, { name: "m7i.2xlarge", displayName: "m7i.2xlarge", supportedRegions: SUPPORTED_AWS_REGIONS.map((r) => r.name), + isGPU: false, }, { name: "m7i.4xlarge", displayName: "m7i.4xlarge", supportedRegions: SUPPORTED_AWS_REGIONS.map((r) => r.name), + isGPU: false, }, { name: "m7i.8xlarge", displayName: "m7i.8xlarge", supportedRegions: SUPPORTED_AWS_REGIONS.map((r) => r.name), + isGPU: false, }, { name: "m7i.12xlarge", displayName: "m7i.12xlarge", supportedRegions: SUPPORTED_AWS_REGIONS.map((r) => r.name), + isGPU: false, }, { name: "c7a.medium", displayName: "c7a.medium", supportedRegions: SUPPORTED_AWS_REGIONS.map((r) => r.name), + isGPU: false, }, { name: "c7a.large", displayName: "c7a.large", supportedRegions: SUPPORTED_AWS_REGIONS.map((r) => r.name), + isGPU: false, }, { name: "c7a.xlarge", displayName: "c7a.xlarge", supportedRegions: SUPPORTED_AWS_REGIONS.map((r) => r.name), + isGPU: false, }, { name: "c7a.2xlarge", displayName: "c7a.2xlarge", supportedRegions: SUPPORTED_AWS_REGIONS.map((r) => r.name), + isGPU: false, }, { name: "c7a.4xlarge", displayName: "c7a.4xlarge", supportedRegions: SUPPORTED_AWS_REGIONS.map((r) => r.name), + isGPU: false, }, { name: "c7a.8xlarge", displayName: "c7a.8xlarge", supportedRegions: SUPPORTED_AWS_REGIONS.map((r) => r.name), + isGPU: false, }, { name: "c7a.12xlarge", displayName: "c7a.12xlarge", supportedRegions: SUPPORTED_AWS_REGIONS.map((r) => r.name), + isGPU: false, }, { name: "c7a.16xlarge", displayName: "c7a.16xlarge", supportedRegions: SUPPORTED_AWS_REGIONS.map((r) => r.name), + isGPU: false, }, { name: "c7a.24xlarge", displayName: "c7a.24xlarge", supportedRegions: SUPPORTED_AWS_REGIONS.map((r) => r.name), + isGPU: false, + }, + { + name: "c7g.medium", + displayName: "c7g.medium", + supportedRegions: SUPPORTED_AWS_REGIONS.map((r) => r.name), + isGPU: false, + }, + { + name: "c7g.large", + displayName: "c7g.large", + supportedRegions: SUPPORTED_AWS_REGIONS.map((r) => r.name), + isGPU: false, + }, + { + name: "c7g.xlarge", + displayName: "c7g.xlarge", + supportedRegions: SUPPORTED_AWS_REGIONS.map((r) => r.name), + isGPU: false, + }, + { + name: "c7g.2xlarge", + displayName: "c7g.2xlarge", + supportedRegions: SUPPORTED_AWS_REGIONS.map((r) => r.name), + isGPU: false, + }, + { + name: "c7g.4xlarge", + displayName: "c7g.4xlarge", + supportedRegions: SUPPORTED_AWS_REGIONS.map((r) => r.name), + isGPU: false, + }, + { + name: "c7g.8xlarge", + displayName: "c7g.8xlarge", + supportedRegions: SUPPORTED_AWS_REGIONS.map((r) => r.name), + isGPU: false, + }, + { + name: "c7g.12xlarge", + displayName: "c7g.12xlarge", + supportedRegions: SUPPORTED_AWS_REGIONS.map((r) => r.name), + isGPU: false, + }, + { + name: "c7g.16xlarge", + displayName: "c7g.16xlarge", + supportedRegions: SUPPORTED_AWS_REGIONS.map((r) => r.name), + isGPU: false, }, { name: "g4dn.xlarge", displayName: "g4dn.xlarge", supportedRegions: SUPPORTED_AWS_REGIONS.map((r) => r.name), + isGPU: true, }, { name: "g4dn.2xlarge", displayName: "g4dn.2xlarge", supportedRegions: SUPPORTED_AWS_REGIONS.map((r) => r.name), + isGPU: true, }, { name: "g4dn.4xlarge", displayName: "g4dn.4xlarge", supportedRegions: SUPPORTED_AWS_REGIONS.map((r) => r.name), + isGPU: true, }, { name: "p4d.24xlarge", displayName: "p4d.24xlarge", supportedRegions: SUPPORTED_AWS_REGIONS.map((r) => r.name), + isGPU: true, }, ]; @@ -437,156 +552,187 @@ const SUPPORTED_GCP_MACHINE_TYPES: ClientMachineType[] = [ name: "e2-standard-2", displayName: "e2-standard-2", supportedRegions: SUPPORTED_GCP_REGIONS.map((r) => r.name), + isGPU: false, }, { name: "e2-standard-4", displayName: "e2-standard-4", supportedRegions: SUPPORTED_GCP_REGIONS.map((r) => r.name), + isGPU: false, }, { name: "e2-standard-8", displayName: "e2-standard-8", supportedRegions: SUPPORTED_GCP_REGIONS.map((r) => r.name), + isGPU: false, }, { name: "e2-standard-16", displayName: "e2-standard-16", supportedRegions: SUPPORTED_GCP_REGIONS.map((r) => r.name), + isGPU: false, }, { name: "e2-standard-32", displayName: "e2-standard-32", supportedRegions: SUPPORTED_GCP_REGIONS.map((r) => r.name), + isGPU: false, }, { name: "c3-standard-4", displayName: "c3-standard-4", supportedRegions: SUPPORTED_GCP_REGIONS.map((r) => r.name), + isGPU: false, }, { name: "c3-standard-8", displayName: "c3-standard-8", supportedRegions: SUPPORTED_GCP_REGIONS.map((r) => r.name), + isGPU: false, }, { name: "c3-standard-22", displayName: "c3-standard-22", supportedRegions: SUPPORTED_GCP_REGIONS.map((r) => r.name), + isGPU: false, }, { name: "c3-standard-44", displayName: "c3-standard-44", supportedRegions: SUPPORTED_GCP_REGIONS.map((r) => r.name), + isGPU: false, }, { name: "c3-highcpu-4", displayName: "c3-highcpu-4", supportedRegions: SUPPORTED_GCP_REGIONS.map((r) => r.name), + isGPU: false, }, { name: "c3-highcpu-8", displayName: "c3-highcpu-8", supportedRegions: SUPPORTED_GCP_REGIONS.map((r) => r.name), + isGPU: false, }, { name: "c3-highcpu-22", displayName: "c3-highcpu-22", supportedRegions: SUPPORTED_GCP_REGIONS.map((r) => r.name), + isGPU: false, }, { name: "c3-highcpu-44", displayName: "c3-highcpu-44", supportedRegions: SUPPORTED_GCP_REGIONS.map((r) => r.name), + isGPU: false, }, { name: "c3-highmem-4", displayName: "c3-highmem-4", supportedRegions: SUPPORTED_GCP_REGIONS.map((r) => r.name), + isGPU: false, }, { name: "c3-highmem-8", displayName: "c3-highmem-8", supportedRegions: SUPPORTED_GCP_REGIONS.map((r) => r.name), + isGPU: false, }, { name: "c3-highmem-22", displayName: "c3-highmem-22", supportedRegions: SUPPORTED_GCP_REGIONS.map((r) => r.name), + isGPU: false, }, { name: "c3-highmem-44", displayName: "c3-highmem-44", supportedRegions: SUPPORTED_GCP_REGIONS.map((r) => r.name), + isGPU: false, }, { name: "n1-standard-1", displayName: "n1-standard-1", supportedRegions: SUPPORTED_GCP_REGIONS.map((r) => r.name), + isGPU: true, }, { name: "n1-standard-2", displayName: "n1-standard-2", supportedRegions: SUPPORTED_GCP_REGIONS.map((r) => r.name), + isGPU: true, }, { name: "n1-standard-4", displayName: "n1-standard-4", supportedRegions: SUPPORTED_GCP_REGIONS.map((r) => r.name), + isGPU: true, }, { name: "n1-standard-8", displayName: "n1-standard-8", supportedRegions: SUPPORTED_GCP_REGIONS.map((r) => r.name), + isGPU: true, }, { name: "n1-standard-16", displayName: "n1-standard-16", supportedRegions: SUPPORTED_GCP_REGIONS.map((r) => r.name), + isGPU: true, }, { name: "n1-standard-32", displayName: "n1-standard-32", supportedRegions: SUPPORTED_GCP_REGIONS.map((r) => r.name), + isGPU: false, }, { name: "n1-highmem-2", displayName: "n1-highmem-2", supportedRegions: SUPPORTED_GCP_REGIONS.map((r) => r.name), + isGPU: true, }, { name: "n1-highmem-4", displayName: "n1-highmem-4", supportedRegions: SUPPORTED_GCP_REGIONS.map((r) => r.name), + isGPU: true, }, { name: "n1-highmem-8", displayName: "n1-highmem-8", supportedRegions: SUPPORTED_GCP_REGIONS.map((r) => r.name), + isGPU: true, }, { name: "n1-highmem-16", displayName: "n1-highmem-16", supportedRegions: SUPPORTED_GCP_REGIONS.map((r) => r.name), + isGPU: true, }, { name: "n1-highmem-32", displayName: "n1-highmem-32", supportedRegions: SUPPORTED_GCP_REGIONS.map((r) => r.name), + isGPU: true, }, { name: "n1-highcpu-8", displayName: "n1-highcpu-8", supportedRegions: SUPPORTED_GCP_REGIONS.map((r) => r.name), + isGPU: true, }, { name: "n1-highcpu-16", displayName: "n1-highcpu-16", supportedRegions: SUPPORTED_GCP_REGIONS.map((r) => r.name), + isGPU: true, }, { name: "n1-highcpu-32", displayName: "n1-highcpu-32", supportedRegions: SUPPORTED_GCP_REGIONS.map((r) => r.name), + isGPU: true, }, ]; @@ -616,6 +762,7 @@ const SUPPORTED_AZURE_MACHINE_TYPES: ClientMachineType[] = [ "westus2", "westus3", ], + isGPU: false, }, { name: "Standard_B2as_v2", @@ -642,6 +789,7 @@ const SUPPORTED_AZURE_MACHINE_TYPES: ClientMachineType[] = [ "westus2", "westus3", ], + isGPU: false, }, { name: "Standard_A2_v2", @@ -662,6 +810,7 @@ const SUPPORTED_AZURE_MACHINE_TYPES: ClientMachineType[] = [ "uaenorth", "uksouth", ], + isGPU: false, }, { name: "Standard_A4_v2", @@ -682,6 +831,7 @@ const SUPPORTED_AZURE_MACHINE_TYPES: ClientMachineType[] = [ "uaenorth", "uksouth", ], + isGPU: false, }, { name: "Standard_DS1_v2", @@ -702,6 +852,7 @@ const SUPPORTED_AZURE_MACHINE_TYPES: ClientMachineType[] = [ "uaenorth", "uksouth", ], + isGPU: false, }, { name: "Standard_DS2_v2", @@ -725,6 +876,7 @@ const SUPPORTED_AZURE_MACHINE_TYPES: ClientMachineType[] = [ "switzerlandnorth", "westus3", ], + isGPU: false, }, { name: "Standard_D2ads_v5", @@ -743,6 +895,7 @@ const SUPPORTED_AZURE_MACHINE_TYPES: ClientMachineType[] = [ "uksouth", "westus3", ], + isGPU: false, }, { name: "Standard_B4als_v2", @@ -769,6 +922,7 @@ const SUPPORTED_AZURE_MACHINE_TYPES: ClientMachineType[] = [ "westus2", "westus3", ], + isGPU: false, }, { name: "Standard_NC4as_T4_v3", @@ -784,6 +938,7 @@ const SUPPORTED_AZURE_MACHINE_TYPES: ClientMachineType[] = [ "westeurope", "westus2", ], + isGPU: true, }, { name: "Standard_NC8as_T4_v3", @@ -799,6 +954,7 @@ const SUPPORTED_AZURE_MACHINE_TYPES: ClientMachineType[] = [ "westeurope", "westus2", ], + isGPU: true, }, { name: "Standard_NC16as_T4_v3", @@ -814,6 +970,7 @@ const SUPPORTED_AZURE_MACHINE_TYPES: ClientMachineType[] = [ "westeurope", "westus2", ], + isGPU: true, }, { name: "Standard_NC64as_T4_v3", @@ -829,6 +986,7 @@ const SUPPORTED_AZURE_MACHINE_TYPES: ClientMachineType[] = [ "westeurope", "westus2", ], + isGPU: true, }, { name: "Standard_D8s_v3", @@ -849,6 +1007,7 @@ const SUPPORTED_AZURE_MACHINE_TYPES: ClientMachineType[] = [ "uaenorth", "uksouth", ], + isGPU: false, }, ]; const SUPPORTED_AZURE_SKU_TIERS = [ @@ -956,10 +1115,10 @@ const AWS_VCPUS_QUOTA_RESOLUTION: PreflightCheckResolution = { "https://us-east-1.console.aws.amazon.com/servicequotas/home/services/ec2/quotas", }, { - text: 'Search for "Running On-Demand Standard (A, C, D, H, I, M, R, T, Z) instances" in the search box and click on the search result.', + text: "Input the reported quota name from the provision check error into the search box and click on the search result.", }, { - text: 'Click on "Request quota increase". In order to provision with Porter, you will need to request at least 10 vCPUs above your current quota limit.', + text: 'Click on "Request quota increase". In order to provision with Porter, the new quota value must be at least the number reported from the provision check error.', }, { text: "Once that request is approved, return to Porter and retry the provision.", diff --git a/dashboard/src/lib/clusters/types.ts b/dashboard/src/lib/clusters/types.ts index 81c1026567..66ec49c396 100644 --- a/dashboard/src/lib/clusters/types.ts +++ b/dashboard/src/lib/clusters/types.ts @@ -163,6 +163,14 @@ const awsMachineTypeValidator = z.enum([ "c7a.12xlarge", "c7a.16xlarge", "c7a.24xlarge", + "c7g.medium", + "c7g.large", + "c7g.xlarge", + "c7g.2xlarge", + "c7g.4xlarge", + "c7g.8xlarge", + "c7g.12xlarge", + "c7g.16xlarge", // gpu types "g4dn.xlarge", "g4dn.2xlarge", @@ -228,6 +236,7 @@ export type ClientMachineType = { name: AWSMachineType | GCPMachineType | AzureMachineType; displayName: string; supportedRegions: Array; + isGPU: boolean; }; type PreflightCheckResolutionStep = { text: string; diff --git a/dashboard/src/main/home/app-dashboard/create-app/CreateApp.tsx b/dashboard/src/main/home/app-dashboard/create-app/CreateApp.tsx index d8ddab84b0..94d319bedc 100644 --- a/dashboard/src/main/home/app-dashboard/create-app/CreateApp.tsx +++ b/dashboard/src/main/home/app-dashboard/create-app/CreateApp.tsx @@ -56,7 +56,6 @@ import { type PopulatedEnvGroup, } from "../validate-apply/app-settings/types"; import ServiceList from "../validate-apply/services-settings/ServiceList"; -import PorterYamlModal from "./PorterYamlModal"; import RepoSettings from "./RepoSettings"; type CreateAppProps = RouteComponentProps; @@ -69,10 +68,6 @@ const CreateApp: React.FC = ({ history }) => { count: number; }>({ detected: false, count: 0 }); const [showGHAModal, setShowGHAModal] = React.useState(false); - const [ - userHasSeenNoPorterYamlFoundModal, - setUserHasSeenNoPorterYamlFoundModal, - ] = React.useState(false); const isNameValid = (value: string): boolean => { return /^[a-z0-9-]{1,63}$/.test(value); }; @@ -195,12 +190,7 @@ const CreateApp: React.FC = ({ history }) => { const image = watch("source.image"); const services = watch("app.services"); - const { - detectedServices: servicesFromYaml, - detectedName, - porterYamlFound, - loading: isLoadingPorterYaml, - } = usePorterYaml({ + const { detectedServices: servicesFromYaml, detectedName } = usePorterYaml({ source: source?.type === "github" ? source : null, appName: "", // only want to know if porter.yaml has name set, otherwise use name from input }); diff --git a/dashboard/src/main/home/infrastructure-dashboard/ClusterStatus.tsx b/dashboard/src/main/home/infrastructure-dashboard/ClusterStatus.tsx index 857742b46d..9f90675afd 100644 --- a/dashboard/src/main/home/infrastructure-dashboard/ClusterStatus.tsx +++ b/dashboard/src/main/home/infrastructure-dashboard/ClusterStatus.tsx @@ -1,4 +1,5 @@ import React, { useMemo } from "react"; +import _ from "lodash"; import pluralize from "pluralize"; import styled from "styled-components"; @@ -12,8 +13,18 @@ import { useClusterContext } from "./ClusterContextProvider"; const ClusterStatus: React.FC = () => { const { nodes, isClusterUpdating } = useClusterContext(); - const applicationNodes = useMemo(() => { - return nodes.filter((n) => n.nodeGroupType === "APPLICATION"); + const nodeInformation = useMemo(() => { + const applicationNodes = nodes.filter( + (n) => n.nodeGroupType === "APPLICATION" + ); + const customNodes = nodes.filter((n) => n.nodeGroupType === "CUSTOM"); + if (!applicationNodes.length) { + return; + } + return { + APPLICATION: applicationNodes, + CUSTOM: customNodes, + }; }, [nodes]); return ( @@ -26,14 +37,22 @@ const ClusterStatus: React.FC = () => { Updating ) : ( - applicationNodes.length !== 0 && ( + nodeInformation && ( <> - Applications using {applicationNodes.length}{" "} - {applicationNodes[0].instanceType}{" "} - {pluralize("instance", applicationNodes.length)} + Applications running on {nodeInformation.APPLICATION.length}{" "} + {nodeInformation.APPLICATION[0].instanceType}{" "} + {pluralize("instance", nodeInformation.APPLICATION.length)} + {nodeInformation.CUSTOM.length !== 0 && ( + <> + {" and "} + {nodeInformation.CUSTOM.length}{" "} + {nodeInformation.CUSTOM[0].instanceType}{" "} + {pluralize("instance", nodeInformation.CUSTOM.length)} + + )} ) diff --git a/dashboard/src/main/home/infrastructure-dashboard/modals/PreflightChecksModal.tsx b/dashboard/src/main/home/infrastructure-dashboard/modals/PreflightChecksModal.tsx index 636e893448..0c76d8b2ee 100644 --- a/dashboard/src/main/home/infrastructure-dashboard/modals/PreflightChecksModal.tsx +++ b/dashboard/src/main/home/infrastructure-dashboard/modals/PreflightChecksModal.tsx @@ -64,12 +64,10 @@ export const CheckItem: React.FC = ({ preflightCheck }) => { {preflightCheck.error.metadata && Object.entries(preflightCheck.error.metadata).map( ([key, value]) => ( - <> -
- {key}: - {value} -
- +
+ {key}: + {value} +
) )} @@ -107,12 +105,12 @@ const PreflightChecksModal: React.FC = ({ export default PreflightChecksModal; -const AppearingDiv = styled.div<{ color?: string }>` +const AppearingDiv = styled.div` animation: floatIn 0.5s; animation-fill-mode: forwards; display: flex; flex-direction: column; - color: ${(props) => props.color || "#ffffff44"}; + color: #fff; @keyframes floatIn { from { diff --git a/dashboard/src/main/home/infrastructure-dashboard/modals/help/preflight/ResolutionStepsModalContents.tsx b/dashboard/src/main/home/infrastructure-dashboard/modals/help/preflight/ResolutionStepsModalContents.tsx index 264594c2b9..9cf1cbc2ba 100644 --- a/dashboard/src/main/home/infrastructure-dashboard/modals/help/preflight/ResolutionStepsModalContents.tsx +++ b/dashboard/src/main/home/infrastructure-dashboard/modals/help/preflight/ResolutionStepsModalContents.tsx @@ -2,6 +2,7 @@ import React from "react"; import styled from "styled-components"; import Link from "components/porter/Link"; +import ShowIntercomButton from "components/porter/ShowIntercomButton"; import Spacer from "components/porter/Spacer"; import Step from "components/porter/Step"; import Text from "components/porter/Text"; @@ -32,6 +33,10 @@ const ElasticIPQuotaModalContents: React.FC = ({ resolution }) => { ))} + + + Need help? Talk to support + ); }; diff --git a/dashboard/src/main/home/infrastructure-dashboard/shared/NodeGroups.tsx b/dashboard/src/main/home/infrastructure-dashboard/shared/NodeGroups.tsx index 69303a797e..382a0a6213 100644 --- a/dashboard/src/main/home/infrastructure-dashboard/shared/NodeGroups.tsx +++ b/dashboard/src/main/home/infrastructure-dashboard/shared/NodeGroups.tsx @@ -1,6 +1,9 @@ -import React, { useMemo } from "react"; +import React, { useContext, useMemo } from "react"; +import _ from "lodash"; import { Controller, useFieldArray, useFormContext } from "react-hook-form"; +import styled from "styled-components"; +import Button from "components/porter/Button"; import Container from "components/porter/Container"; import Expandable from "components/porter/Expandable"; import Image from "components/porter/Image"; @@ -13,6 +16,8 @@ import { type ClientMachineType, } from "lib/clusters/types"; +import { Context } from "shared/Context"; +import chip from "assets/computer-chip.svg"; import world from "assets/world.svg"; type Props = { @@ -20,25 +25,32 @@ type Props = { }; const NodeGroups: React.FC = ({ availableMachineTypes }) => { const { control } = useFormContext(); - const { fields: nodeGroups } = useFieldArray({ + const { currentProject } = useContext(Context); + const { + fields: nodeGroups, + append, + remove, + } = useFieldArray({ control, name: "cluster.config.nodeGroups", }); const displayableNodeGroups = useMemo(() => { - const dng = nodeGroups.map((ng, idx) => { - return { - nodeGroup: ng, - idx, - isIncluded: ng.nodeGroupType === "APPLICATION", - }; - }); + const dng = _.groupBy( + nodeGroups.map((ng, idx) => { + return { + nodeGroup: ng, + idx, + }; + }), + (ng) => ng.nodeGroup.nodeGroupType + ); return dng; }, [nodeGroups]); return ( - <> - {displayableNodeGroups.map((ng) => { - return ng.isIncluded ? ( + + {displayableNodeGroups.APPLICATION?.map((ng) => { + return ( = ({ availableMachineTypes }) => { - {ng.nodeGroup.nodeGroupType === "APPLICATION" && - "Default node group"} + Default node group } > @@ -58,10 +69,12 @@ const NodeGroups: React.FC = ({ availableMachineTypes }) => { <> t.isGPU) + .map((t) => ({ + value: t.name, + label: t.displayName, + }))} + value={value.instanceType} + setValue={(newInstanceType: string) => { + onChange({ + ...value, + instanceType: newInstanceType, + }); + }} + label="Machine type" + /> + + Minimum number of GPU nodes + + { + onChange({ + ...value, + minInstances: parseInt(newMinInstances), + }); + }} + placeholder="ex: 1" + /> + + Maximum number of GPU nodes + + { + onChange({ + ...value, + maxInstances: parseInt(newMaxInstances), + }); + }} + placeholder="ex: 10" + /> + + )} + /> + + ); + })} + {(displayableNodeGroups.CUSTOM ?? []).length === 0 && + currentProject?.gpu_enabled && ( + + )} + ); }; export default NodeGroups; + +const NodeGroupContainer = styled.div` + display: flex; + flex-direction: column; + gap: 10px; +`; + +const I = styled.i` + font-size: 20px; + cursor: pointer; + padding: 5px; + color: #aaaabb; + :hover { + color: white; + } +`; + +const ActionButton = styled.button` + position: relative; + border: none; + background: none; + color: white; + padding: 5px; + display: flex; + justify-content: center; + align-items: center; + border-radius: 50%; + cursor: pointer; + color: #aaaabb; + :hover { + color: white; + } + + > span { + font-size: 20px; + } + margin-right: 5px; +`; diff --git a/dashboard/src/main/home/sidebar/ClusterList.tsx b/dashboard/src/main/home/sidebar/ClusterList.tsx index e435bbf17f..5b7c38e2de 100644 --- a/dashboard/src/main/home/sidebar/ClusterList.tsx +++ b/dashboard/src/main/home/sidebar/ClusterList.tsx @@ -3,6 +3,7 @@ import { withRouter } from "react-router"; import styled from "styled-components"; import Icon from "components/porter/Icon"; +import { useClusterList } from "lib/hooks/useCluster"; import api from "shared/api"; import { Context } from "shared/Context"; @@ -30,6 +31,7 @@ const ClusterList: React.FC = (props) => { const wrapperRef = useRef(null); const [clusters, setClusters] = useState([]); const [options, setOptions] = useState([]); + const { clusters: clusterList } = useClusterList(); useEffect(() => { const handleClickOutside = (e: MouseEvent): void => { @@ -50,6 +52,19 @@ const ClusterList: React.FC = (props) => { useEffect(() => { if (currentProject) { + if ( + currentProject?.simplified_view_enabled && + currentProject?.capi_provisioner_enabled && + currentProject?.beta_features_enabled + ) { + setOptions( + clusterList.map((c) => ({ + label: c.vanity_name, + value: c.name, + })) + ); + return; + } api .getClusters("", {}, { id: currentProject?.id }) .then((res) => { @@ -90,9 +105,31 @@ const ClusterList: React.FC = (props) => { title={option.label} onClick={() => { setExpanded(false); - const cluster = clusters.find((c) => c.name === option.value); - setCurrentCluster(cluster); - pushFiltered(props, "/apps", ["project_id"], {}); + if ( + currentProject?.simplified_view_enabled && + currentProject?.capi_provisioner_enabled && + currentProject?.beta_features_enabled + ) { + const cluster = clusterList.find((c) => c.name === option.value); + if (cluster) { + // TODO: remove the need for this conversion + const clusterToOldType: ClusterType = { + id: cluster.id, + name: cluster.name, + vanity_name: cluster.vanity_name, + cloud_provider: cluster.cloud_provider.name, + status: cluster.status, + }; + setCurrentCluster?.(clusterToOldType); + pushFiltered(props, "/apps", ["project_id"], {}); + } + } else { + const cluster = clusters.find((c) => c.name === option.value); + if (cluster) { + setCurrentCluster?.(cluster); + pushFiltered(props, "/apps", ["project_id"], {}); + } + } }} > diff --git a/dashboard/src/shared/types.tsx b/dashboard/src/shared/types.tsx index 9247bdf822..f483c614dd 100644 --- a/dashboard/src/shared/types.tsx +++ b/dashboard/src/shared/types.tsx @@ -22,7 +22,7 @@ export type ClusterType = { id: number; name: string; vanity_name?: string; - server: string; + server?: string; service_account_id?: number; agent_integration_enabled?: boolean; infra_id?: number;