Skip to content
This repository has been archived by the owner on Jul 2, 2024. It is now read-only.

Commit

Permalink
EVG-19947: Support EC2 Fleet on provider settings page (#2050)
Browse files Browse the repository at this point in the history
  • Loading branch information
minnakt authored Sep 27, 2023
1 parent f334d03 commit 87b9d23
Show file tree
Hide file tree
Showing 8 changed files with 750 additions and 42 deletions.
79 changes: 79 additions & 0 deletions cypress/integration/distroSettings/provider_section.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,4 +83,83 @@ describe("provider section", () => {
cy.validateToast("success");
});
});

describe("ec2 fleet", () => {
beforeEach(() => {
cy.visit("/distro/ubuntu1804-workstation/settings/provider");
});

it("shows and hides fields correctly", () => {
// Fleet options.
cy.getInputByLabel("Fleet Instance Type").contains("On-demand");
cy.contains("Capacity optimization").should("not.exist");

cy.selectLGOption("Fleet Instance Type", "Spot");
cy.contains("Capacity optimization").should("exist");

// VPC options.
cy.dataCy("use-vpc").should("be.checked");
cy.contains("Default VPC Subnet ID").should("exist");
cy.contains("VPC Subnet Prefix").should("exist");

cy.dataCy("use-vpc").uncheck({ force: true });
cy.contains("Default VPC Subnet ID").should("not.exist");
cy.contains("VPC Subnet Prefix").should("not.exist");
});

it("successfully updates ec2 fleet provider fields", () => {
cy.dataCy("provider-select").contains("EC2 Fleet");

// Correct section is displayed.
cy.dataCy("ec2-fleet-provider-settings").should("exist");
cy.dataCy("region-select").contains("us-east-1");

// Change field values.
cy.selectLGOption("Region", "us-west-1");
cy.getInputByLabel("SSH Key Name").as("keyNameInput");
cy.get("@keyNameInput").clear();
cy.get("@keyNameInput").type("my ssh key");
cy.selectLGOption("Fleet Instance Type", "Spot");
cy.contains("button", "Add mount point").click();
cy.getInputByLabel("Device Name").type("device name");
cy.getInputByLabel("Size").type("200");
save();
cy.validateToast("success");

// Revert fields to original values.
cy.selectLGOption("Region", "us-east-1");
cy.get("@keyNameInput").clear();
cy.get("@keyNameInput").type("mci");
cy.selectLGOption("Fleet Instance Type", "On-demand");
cy.dataCy("mount-points").within(() => {
cy.dataCy("delete-item-button").click();
});
save();
cy.validateToast("success");
});

it("can add and delete region settings", () => {
cy.dataCy("ec2-fleet-provider-settings").should("exist");

// Add item for new region.
cy.contains("button", "Add region settings").click();
cy.contains("button", "Add region settings").should("not.exist");

// Save new region.
cy.selectLGOption("Region", "us-west-1");
cy.getInputByLabel("EC2 AMI ID").type("ami-1234");
cy.getInputByLabel("Instance Type").type("m5.xlarge");
cy.contains("button", "Add security group").click();
cy.getInputByLabel("Security Group ID").type("security-group-1234");
save();
cy.validateToast("success");

// Revert to original state by deleting the new region.
cy.dataCy("delete-item-button").first().click();
save();
cy.validateToast("success");

cy.contains("button", "Add region settings").should("exist");
});
});
});
21 changes: 19 additions & 2 deletions src/pages/distroSettings/tabs/ProviderTab/ProviderTab.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import { useMemo } from "react";
import { useQuery } from "@apollo/client";
import { AwsRegionsQuery, AwsRegionsQueryVariables } from "gql/generated/types";
import { AWS_REGIONS } from "gql/queries";
import { useSpruceConfig } from "hooks";
import { useDistroSettingsContext } from "pages/distroSettings/Context";
import { omitTypename } from "utils/string";
Expand All @@ -24,6 +27,14 @@ export const ProviderTab: React.FC<TabProps> = ({ distro, distroData }) => {
initialData: ReturnType<FormToGqlFunction<WritableDistroSettingsType>>;
} = getTab(WritableDistroSettingsTabs.Provider);

const { data: awsData } = useQuery<AwsRegionsQuery, AwsRegionsQueryVariables>(
AWS_REGIONS
);
const { awsRegions } = awsData || {};
const configuredRegions = formData?.ec2FleetProviderSettings?.map(
(p) => p.region
);

const { containerPools } = useSpruceConfig();
const { pools } = containerPools || {};

Expand All @@ -34,8 +45,14 @@ export const ProviderTab: React.FC<TabProps> = ({ distro, distroData }) => {
: "";

const formSchema = useMemo(
() => getFormSchema({ pools: pools || [], poolMappingInfo }),
[pools, poolMappingInfo]
() =>
getFormSchema({
awsRegions: awsRegions || [],
configuredRegions: configuredRegions || [],
pools: pools || [],
poolMappingInfo,
}),
[awsRegions, configuredRegions, pools, poolMappingInfo]
);

return (
Expand Down
144 changes: 141 additions & 3 deletions src/pages/distroSettings/tabs/ProviderTab/getFormSchema.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,26 @@
import { css } from "@emotion/react";
import { GetFormSchema } from "components/SpruceForm";
import { CardFieldTemplate } from "components/SpruceForm/FieldTemplates";
import {
CardFieldTemplate,
AccordionFieldTemplate,
} from "components/SpruceForm/FieldTemplates";
import { STANDARD_FIELD_WIDTH } from "components/SpruceForm/utils";
import { size } from "constants/tokens";
import { Provider, ContainerPool } from "gql/generated/types";
import { dockerProviderSettings, staticProviderSettings } from "./schemaFields";
import {
dockerProviderSettings,
staticProviderSettings,
ec2FleetProviderSettings,
} from "./schemaFields";

export const getFormSchema = ({
awsRegions,
configuredRegions,
poolMappingInfo,
pools,
}: {
awsRegions: string[];
configuredRegions: string[];
poolMappingInfo: string;
pools: ContainerPool[];
}): ReturnType<GetFormSchema> => ({
Expand Down Expand Up @@ -96,13 +108,45 @@ export const getFormSchema = ({
})),
},
poolMappingInfo: dockerProviderSettings.poolMappingInfo,
userData: dockerProviderSettings.userData,
mergeUserData: dockerProviderSettings.mergeUserData,
userData: dockerProviderSettings.userData,
securityGroups: dockerProviderSettings.securityGroups,
},
},
},
},
{
properties: {
provider: {
properties: {
providerName: {
enum: [Provider.Ec2Fleet],
},
},
},
ec2FleetProviderSettings: {
type: "array" as "array",
minItems: 1,
title: "",
items: {
type: "object" as "object",
properties: {
region: {
type: "string" as "string",
title: "Region",
default: "",
oneOf: awsRegions.map((r) => ({
type: "string" as "string",
title: r,
enum: [r],
})),
},
...ec2FleetProviderSettings,
},
},
},
},
},
],
},
},
Expand All @@ -118,6 +162,9 @@ export const getFormSchema = ({
staticProviderSettings: {
"ui:data-cy": "static-provider-settings",
"ui:ObjectFieldTemplate": CardFieldTemplate,
mergeUserData: {
"ui:elementWrapperCSS": mergeCheckboxCSS,
},
userData: {
"ui:widget": "textarea",
"ui:elementWrapperCSS": textAreaCSS,
Expand All @@ -130,6 +177,9 @@ export const getFormSchema = ({
dockerProviderSettings: {
"ui:data-cy": "docker-provider-settings",
"ui:ObjectFieldTemplate": CardFieldTemplate,
mergeUserData: {
"ui:elementWrapperCSS": mergeCheckboxCSS,
},
userData: {
"ui:widget": "textarea",
"ui:elementWrapperCSS": textAreaCSS,
Expand Down Expand Up @@ -159,12 +209,100 @@ export const getFormSchema = ({
"ui:readonly": true,
},
},
ec2FleetProviderSettings: {
"ui:data-cy": "ec2-fleet-provider-settings",
"ui:addable": awsRegions.length !== configuredRegions.length,
"ui:addButtonText": "Add region settings",
"ui:orderable": false,
"ui:useExpandableCard": true,
items: {
"ui:displayTitle": "New AWS Region",
mergeUserData: {
"ui:elementWrapperCSS": mergeCheckboxCSS,
},
userData: {
"ui:widget": "textarea",
"ui:elementWrapperCSS": textAreaCSS,
},
securityGroups: {
"ui:addButtonText": "Add security group",
"ui:orderable": false,
},
region: {
"ui:data-cy": "region-select",
"ui:allowDeselect": false,
"ui:enumDisabled": configuredRegions,
},
amiId: {
"ui:placeholder": "e.g. ami-1ecba176",
},
instanceType: {
"ui:description": "EC2 instance type for the AMI. Must be available.",
"ui:placeholder": "e.g. t1.micro",
},
fleetOptions: {
fleetInstanceType: {
"ui:allowDeselect": false,
},
useCapacityOptimization: {
"ui:data-cy": "use-capacity-optimization",
"ui:bold": true,
"ui:description":
"Use the capacity-optimized allocation strategy for spot (default: lowest-cost)",
"ui:elementWrapperCSS": capacityCheckboxCSS,
},
},
vpcOptions: {
useVpc: {
"ui:data-cy": "use-vpc",
},
subnetId: {
"ui:placeholder": "e.g. subnet-xxxx",
"ui:elementWrapperCSS": indentCSS,
},
subnetPrefix: {
"ui:description":
"Looks for subnets like <prefix>.subnet_1a, <prefix>.subnet_1b, etc.",
"ui:elementWrapperCSS": indentCSS,
},
},
mountPoints: {
"ui:data-cy": "mount-points",
"ui:addButtonText": "Add mount point",
"ui:orderable": false,
"ui:topAlignDelete": true,
items: {
"ui:ObjectFieldTemplate": AccordionFieldTemplate,
"ui:numberedTitle": "Mount Point",
},
},
},
},
},
});

const textAreaCSS = css`
box-sizing: border-box;
max-width: ${STANDARD_FIELD_WIDTH}px;
textarea {
min-height: 140px;
}
`;

const mergeCheckboxCSS = css`
max-width: ${STANDARD_FIELD_WIDTH}px;
display: flex;
justify-content: flex-end;
margin-bottom: -20px;
`;

const capacityCheckboxCSS = css`
max-width: ${STANDARD_FIELD_WIDTH}px;
`;

const indentCSS = css`
box-sizing: border-box;
padding-left: ${size.m};
`;

const poolMappingInfoCss = css`
Expand Down
Loading

0 comments on commit 87b9d23

Please sign in to comment.