feat: fully functioning ALB
This commit is contained in:
@@ -15,6 +15,7 @@ export const apiEndpointKeys = {
|
||||
status: "clouds.status.get",
|
||||
serviceStatus: "clouds.services.status.get",
|
||||
schema: "clouds.services.schema.get",
|
||||
dependencies: "clouds.services.dependencies.get",
|
||||
resources: {
|
||||
list: "clouds.services.resources.list",
|
||||
get: "clouds.services.resources.get",
|
||||
@@ -113,6 +114,11 @@ export const apiEndpointKeys = {
|
||||
list: "clouds.services.childCollections.items.list",
|
||||
},
|
||||
},
|
||||
flatItems: {
|
||||
list: "clouds.services.flatItems.list",
|
||||
create: "clouds.services.flatItems.create",
|
||||
delete: "clouds.services.flatItems.delete",
|
||||
},
|
||||
configuration: {
|
||||
environments: {
|
||||
list: "clouds.services.configuration.environments.list",
|
||||
@@ -295,6 +301,14 @@ export const endpointRegistry: EndpointRegistry = new Map([
|
||||
telemetry: { service: "cloud-proxy" },
|
||||
},
|
||||
],
|
||||
[
|
||||
apiEndpointKeys.clouds.dependencies,
|
||||
{
|
||||
path: "/clouds/:cloud/services/:service/dependencies",
|
||||
method: "GET",
|
||||
telemetry: { service: "cloud-proxy" },
|
||||
},
|
||||
],
|
||||
[
|
||||
apiEndpointKeys.clouds.resources.list,
|
||||
{
|
||||
@@ -890,6 +904,30 @@ export const endpointRegistry: EndpointRegistry = new Map([
|
||||
telemetry: { service: "cloud-proxy" },
|
||||
},
|
||||
],
|
||||
[
|
||||
apiEndpointKeys.clouds.flatItems.list,
|
||||
{
|
||||
path: "/clouds/:cloud/services/:service/resources/:id/items",
|
||||
method: "GET",
|
||||
telemetry: { service: "cloud-proxy" },
|
||||
},
|
||||
],
|
||||
[
|
||||
apiEndpointKeys.clouds.flatItems.create,
|
||||
{
|
||||
path: "/clouds/:cloud/services/:service/resources/:id/items",
|
||||
method: "POST",
|
||||
telemetry: { service: "cloud-proxy" },
|
||||
},
|
||||
],
|
||||
[
|
||||
apiEndpointKeys.clouds.flatItems.delete,
|
||||
{
|
||||
path: "/clouds/:cloud/services/:service/resources/:id/items/:itemId",
|
||||
method: "DELETE",
|
||||
telemetry: { service: "cloud-proxy" },
|
||||
},
|
||||
],
|
||||
// AWS EKS
|
||||
[
|
||||
apiEndpointKeys.aws.eks.clusters.list,
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { createEc2SecurityGroup } from "./ec2.api";
|
||||
import {
|
||||
authorizeEc2SecurityGroupEgress,
|
||||
authorizeEc2SecurityGroupIngress,
|
||||
createEc2SecurityGroup,
|
||||
revokeEc2SecurityGroupEgress,
|
||||
revokeEc2SecurityGroupIngress,
|
||||
} from "./ec2.api";
|
||||
|
||||
describe("createEc2SecurityGroup", () => {
|
||||
const fetchMock = vi.fn<typeof fetch>();
|
||||
@@ -42,3 +48,39 @@ describe("createEc2SecurityGroup", () => {
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
describe("EC2 security-group rule requests", () => {
|
||||
const fetchMock = vi.fn<typeof fetch>();
|
||||
|
||||
beforeEach(() => {
|
||||
fetchMock.mockResolvedValue(
|
||||
new Response(JSON.stringify({ ok: true }), {
|
||||
status: 200,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
}),
|
||||
);
|
||||
vi.stubGlobal("fetch", fetchMock);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.unstubAllGlobals();
|
||||
fetchMock.mockReset();
|
||||
});
|
||||
|
||||
it.each([
|
||||
["authorize ingress", authorizeEc2SecurityGroupIngress],
|
||||
["revoke ingress", revokeEc2SecurityGroupIngress],
|
||||
["authorize egress", authorizeEc2SecurityGroupEgress],
|
||||
["revoke egress", revokeEc2SecurityGroupEgress],
|
||||
] as const)("sends one JSON permission object for %s", async (_action, request) => {
|
||||
const permission = { protocol: "tcp", fromPort: 8080, toPort: 8080, cidr: "0.0.0.0/0" };
|
||||
|
||||
await request("sg-web", permission);
|
||||
|
||||
expect(fetchMock).toHaveBeenCalledTimes(1);
|
||||
const [url, init] = fetchMock.mock.calls[0];
|
||||
expect(String(url)).toContain("/api/ec2/security-groups/sg-web");
|
||||
expect(JSON.parse(String(init?.body))).toEqual(permission);
|
||||
expect(new Headers(init?.headers).get("content-type")).toBe("application/json");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -12,6 +12,18 @@ export type Ec2SecurityGroupRef = {
|
||||
name?: string;
|
||||
};
|
||||
|
||||
export type Ec2NetworkInterface = {
|
||||
networkInterfaceId: string;
|
||||
deviceIndex?: number;
|
||||
status?: string;
|
||||
privateIpAddress?: string;
|
||||
publicIpAddress?: string;
|
||||
privateDnsName?: string;
|
||||
subnetId?: string;
|
||||
vpcId?: string;
|
||||
securityGroups: Ec2SecurityGroupRef[];
|
||||
};
|
||||
|
||||
export type Ec2IpPermission = {
|
||||
protocol: string;
|
||||
fromPort: number | null;
|
||||
@@ -61,6 +73,7 @@ export type Ec2Instance = {
|
||||
architecture?: string;
|
||||
platform?: string;
|
||||
securityGroups: Ec2SecurityGroupRef[];
|
||||
networkInterfaces: Ec2NetworkInterface[];
|
||||
tags: Ec2Tag[];
|
||||
};
|
||||
|
||||
@@ -391,7 +404,7 @@ export async function authorizeEc2SecurityGroupIngress(
|
||||
): Promise<void> {
|
||||
await apiClient.call(
|
||||
apiEndpointKeys.aws.ec2.securityGroups.authorize,
|
||||
{ body: JSON.stringify(permission), headers: { "content-type": "application/json" } },
|
||||
{ body: permission },
|
||||
{ groupId },
|
||||
);
|
||||
}
|
||||
@@ -402,7 +415,7 @@ export async function revokeEc2SecurityGroupIngress(
|
||||
): Promise<void> {
|
||||
await apiClient.call(
|
||||
apiEndpointKeys.aws.ec2.securityGroups.revoke,
|
||||
{ body: JSON.stringify(permission), headers: { "content-type": "application/json" } },
|
||||
{ body: permission },
|
||||
{ groupId },
|
||||
);
|
||||
}
|
||||
@@ -413,7 +426,7 @@ export async function authorizeEc2SecurityGroupEgress(
|
||||
): Promise<void> {
|
||||
await apiClient.call(
|
||||
apiEndpointKeys.aws.ec2.securityGroups.authorizeEgress,
|
||||
{ body: JSON.stringify(permission), headers: { "content-type": "application/json" } },
|
||||
{ body: permission },
|
||||
{ groupId },
|
||||
);
|
||||
}
|
||||
@@ -424,7 +437,7 @@ export async function revokeEc2SecurityGroupEgress(
|
||||
): Promise<void> {
|
||||
await apiClient.call(
|
||||
apiEndpointKeys.aws.ec2.securityGroups.revokeEgress,
|
||||
{ body: JSON.stringify(permission), headers: { "content-type": "application/json" } },
|
||||
{ body: permission },
|
||||
{ groupId },
|
||||
);
|
||||
}
|
||||
|
||||
@@ -108,15 +108,34 @@ export async function getServiceSchema(
|
||||
return res.data;
|
||||
}
|
||||
|
||||
export type LoadBalancingDependencies = {
|
||||
vpcs: Array<{id: string; cidrBlock: string}>;
|
||||
subnets: Array<{id: string; vpcId: string; availabilityZone: string; cidrBlock: string}>;
|
||||
securityGroups: Array<{id: string; vpcId: string; name: string; description: string}>;
|
||||
};
|
||||
|
||||
export async function getLoadBalancingDependencies(
|
||||
service: "loadbalancing" | "targetgroups" = "loadbalancing",
|
||||
signal?: AbortSignal,
|
||||
): Promise<LoadBalancingDependencies & {instances?: Array<{id: string; name: string; privateIp: string | null}>}> {
|
||||
const res = await apiClient.call<LoadBalancingDependencies>(
|
||||
apiEndpointKeys.clouds.dependencies,
|
||||
requestOptions("aws", service, {signal}),
|
||||
{cloud: "aws", service},
|
||||
);
|
||||
return res.data;
|
||||
}
|
||||
|
||||
export async function listCloudResources(
|
||||
cloud: CloudProvider,
|
||||
service: CloudServiceType,
|
||||
search?: string,
|
||||
signal?: AbortSignal,
|
||||
state?: string,
|
||||
): Promise<CloudResource[]> {
|
||||
const res = await apiClient.call<CloudResource[]>(
|
||||
apiEndpointKeys.clouds.resources.list,
|
||||
requestOptions(cloud, service, { signal, params: { search } }),
|
||||
requestOptions(cloud, service, { signal, params: { search, state } }),
|
||||
{ cloud, service },
|
||||
);
|
||||
return res.data;
|
||||
@@ -905,6 +924,49 @@ export async function listCollectionItems(
|
||||
return res.data;
|
||||
}
|
||||
|
||||
export async function listFlatItems(
|
||||
cloud: CloudProvider,
|
||||
service: CloudServiceType,
|
||||
resourceId: string,
|
||||
cursor?: string,
|
||||
signal?: AbortSignal,
|
||||
): Promise<CollectionPage<ChildItem>> {
|
||||
const res = await apiClient.call<CollectionPage<ChildItem>>(
|
||||
apiEndpointKeys.clouds.flatItems.list,
|
||||
requestOptions(cloud, service, { signal, params: cursor ? { cursor } : undefined }),
|
||||
{ cloud, service, id: resourceId },
|
||||
);
|
||||
return res.data;
|
||||
}
|
||||
|
||||
export async function deleteFlatItem(
|
||||
cloud: CloudProvider,
|
||||
service: CloudServiceType,
|
||||
resourceId: string,
|
||||
itemId: string,
|
||||
signal?: AbortSignal,
|
||||
): Promise<void> {
|
||||
await apiClient.call<void>(
|
||||
apiEndpointKeys.clouds.flatItems.delete,
|
||||
requestOptions(cloud, service, { signal }),
|
||||
{ cloud, service, id: resourceId, itemId },
|
||||
);
|
||||
}
|
||||
|
||||
export async function putFlatItem(
|
||||
cloud: CloudProvider,
|
||||
service: CloudServiceType,
|
||||
resourceId: string,
|
||||
body: Record<string, unknown>,
|
||||
): Promise<ChildItem> {
|
||||
const res = await apiClient.call<ChildItem, Record<string, unknown>>(
|
||||
apiEndpointKeys.clouds.flatItems.create,
|
||||
requestOptions(cloud, service, {body}),
|
||||
{cloud, service, id: resourceId},
|
||||
);
|
||||
return res.data;
|
||||
}
|
||||
|
||||
export async function listSqlDatabases(
|
||||
cloud: CloudProvider,
|
||||
serverId: string,
|
||||
|
||||
Reference in New Issue
Block a user