Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit c0fad5f

Browse files
Support setting container affinities (#10503)
1 parent 2e2b788 commit c0fad5f

File tree

12 files changed

+315
-1
lines changed

12 files changed

+315
-1
lines changed

.changeset/real-bottles-report.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"wrangler": patch
3+
---
4+
5+
Support setting container affinities

packages/containers-shared/src/client/models/ApplicationAffinities.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@
33
/* eslint-disable */
44

55
import type { ApplicationAffinityColocation } from "./ApplicationAffinityColocation";
6+
import type { ApplicationAffinityHardwareGeneration } from "./ApplicationAffinityHardwareGeneration";
67

78
/**
89
* Defines affinity in application scheduling. (This still an experimental feature, some schedulers might not work with these affinities).
910
*
1011
*/
1112
export type ApplicationAffinities = {
1213
colocation?: ApplicationAffinityColocation;
14+
hardware_generation?: ApplicationAffinityHardwareGeneration;
1315
};
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/* istanbul ignore file */
2+
/* tslint:disable */
3+
/* eslint-disable */
4+
5+
/**
6+
* To the extend possible, prefer nodes with specified characteristics when placing application instances.
7+
*
8+
*/
9+
export enum ApplicationAffinityHardwareGeneration {
10+
HIGHEST_OVERALL_PERFORMANCE = "highest-overall-performance",
11+
}

packages/containers-shared/src/types.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
1-
import type { InstanceType, SchedulingPolicy } from "./client";
1+
import type {
2+
ApplicationAffinityColocation,
3+
InstanceType,
4+
SchedulingPolicy,
5+
} from "./client";
6+
import type { ApplicationAffinityHardwareGeneration } from "./client/models/ApplicationAffinityHardwareGeneration";
27

38
export interface Logger {
49
debug: (...args: unknown[]) => void;
@@ -71,6 +76,10 @@ export type SharedContainerConfig = {
7176
cities?: string[];
7277
tier: number | undefined;
7378
};
79+
affinities?: {
80+
colocation?: ApplicationAffinityColocation;
81+
hardware_generation?: ApplicationAffinityHardwareGeneration;
82+
};
7483
observability: { logs_enabled: boolean };
7584
} & InstanceTypeOrLimits;
7685

packages/wrangler/src/__tests__/cloudchamber/apply.test.ts

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import {
2+
ApplicationAffinityColocation,
23
getCloudflareContainerRegistry,
34
SchedulingPolicy,
45
SecretAccessType,
@@ -2015,4 +2016,82 @@ describe("cloudchamber apply", () => {
20152016
const app = await applicationReqBodyPromise;
20162017
expect(app.configuration?.instance_type).toEqual("standard");
20172018
});
2019+
2020+
test("updates affinities", async () => {
2021+
setIsTTY(false);
2022+
const registry = getCloudflareContainerRegistry();
2023+
writeWranglerConfig({
2024+
name: "my-container",
2025+
containers: [
2026+
{
2027+
name: "my-container-app",
2028+
instances: 3,
2029+
class_name: "DurableObjectClass",
2030+
image: `${registry}/hello:1.0`,
2031+
instance_type: "dev",
2032+
constraints: {
2033+
tier: 1,
2034+
},
2035+
affinities: {
2036+
hardware_generation: "highest-overall-performance",
2037+
},
2038+
},
2039+
],
2040+
});
2041+
2042+
mockGetApplications([
2043+
{
2044+
id: "abc",
2045+
name: "my-container-app",
2046+
instances: 3,
2047+
created_at: new Date().toString(),
2048+
version: 1,
2049+
account_id: "1",
2050+
scheduling_policy: SchedulingPolicy.REGIONAL,
2051+
configuration: {
2052+
image: `${registry}/hello:1.0`,
2053+
disk: {
2054+
size: "2GB",
2055+
size_mb: 2000,
2056+
},
2057+
vcpu: 0.0625,
2058+
memory: "256MB",
2059+
memory_mib: 256,
2060+
},
2061+
constraints: {
2062+
tier: 1,
2063+
},
2064+
affinities: {
2065+
colocation: ApplicationAffinityColocation.DATACENTER,
2066+
},
2067+
},
2068+
]);
2069+
2070+
const applicationReqBodyPromise = mockModifyApplication();
2071+
await runWrangler("cloudchamber apply");
2072+
expect(std.stdout).toMatchInlineSnapshot(`
2073+
"╭ Deploy a container application deploy changes to your application
2074+
2075+
│ Container application changes
2076+
2077+
├ EDIT my-container-app
2078+
2079+
│ scheduling_policy = \\"regional\\"
2080+
│ [containers.affinities]
2081+
│ - colocation = \\"datacenter\\"
2082+
│ + hardware_generation = \\"highest-overall-performance\\"
2083+
│ [containers.configuration]
2084+
│ image = \\"registry.cloudflare.com/some-account-id/hello:1.0\\"
2085+
2086+
2087+
│ SUCCESS Modified application my-container-app
2088+
2089+
╰ Applied changes
2090+
2091+
"
2092+
`);
2093+
expect(std.stderr).toMatchInlineSnapshot(`""`);
2094+
const app = await applicationReqBodyPromise;
2095+
expect(app.configuration?.instance_type).toEqual("dev");
2096+
});
20182097
});

packages/wrangler/src/__tests__/containers/config.test.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,9 @@ describe("getNormalizedContainerOptions", () => {
400400
regions: ["us-east-1", "us-west-2"],
401401
cities: ["NYC", "SF"],
402402
},
403+
affinities: {
404+
hardware_generation: "highest-overall-performance",
405+
},
403406
},
404407
],
405408
durable_objects: {
@@ -429,6 +432,9 @@ describe("getNormalizedContainerOptions", () => {
429432
regions: ["US-EAST-1", "US-WEST-2"],
430433
cities: ["nyc", "sf"],
431434
},
435+
affinities: {
436+
hardware_generation: "highest-overall-performance",
437+
},
432438
observability: {
433439
logs_enabled: true,
434440
},

packages/wrangler/src/__tests__/containers/deploy.test.ts

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
InstanceType,
77
SchedulingPolicy,
88
} from "@cloudflare/containers-shared";
9+
import { ApplicationAffinityHardwareGeneration } from "@cloudflare/containers-shared/src/client/models/ApplicationAffinityHardwareGeneration";
910
import { http, HttpResponse } from "msw";
1011
import { clearCachedAccount } from "../../cloudchamber/locations";
1112
import { mockAccountV4 as mockContainersAccount } from "../cloudchamber/utils";
@@ -1497,6 +1498,143 @@ describe("wrangler deploy with containers", () => {
14971498
"
14981499
`);
14991500
});
1501+
1502+
describe("affinities", () => {
1503+
it("may be specified on creation", async () => {
1504+
mockGetVersion("Galaxy-Class");
1505+
writeWranglerConfig({
1506+
...DEFAULT_DURABLE_OBJECTS,
1507+
containers: [
1508+
{
1509+
...DEFAULT_CONTAINER_FROM_REGISTRY,
1510+
affinities: {
1511+
hardware_generation: "highest-overall-performance",
1512+
},
1513+
},
1514+
],
1515+
});
1516+
1517+
mockGetApplications([]);
1518+
1519+
mockCreateApplication();
1520+
1521+
await runWrangler("deploy index.js");
1522+
1523+
expect(cliStd.stdout).toMatchInlineSnapshot(`
1524+
"╭ Deploy a container application deploy changes to your application
1525+
1526+
│ Container application changes
1527+
1528+
├ NEW my-container
1529+
1530+
│ [[containers]]
1531+
│ name = \\"my-container\\"
1532+
│ scheduling_policy = \\"default\\"
1533+
│ instances = 0
1534+
│ max_instances = 10
1535+
│ rollout_active_grace_period = 0
1536+
1537+
│ [containers.configuration]
1538+
│ image = \\"docker.io/hello:world\\"
1539+
│ instance_type = \\"dev\\"
1540+
1541+
│ [containers.constraints]
1542+
│ tier = 1
1543+
1544+
│ [containers.affinities]
1545+
│ hardware_generation = \\"highest-overall-performance\\"
1546+
1547+
│ [containers.durable_objects]
1548+
│ namespace_id = \\"1\\"
1549+
1550+
1551+
│ SUCCESS Created application my-container (Application ID: undefined)
1552+
1553+
╰ Applied changes
1554+
1555+
"
1556+
`);
1557+
});
1558+
1559+
it("may be specified on modification", async () => {
1560+
mockGetVersion("Galaxy-Class");
1561+
writeWranglerConfig({
1562+
...DEFAULT_DURABLE_OBJECTS,
1563+
containers: [
1564+
{
1565+
...DEFAULT_CONTAINER_FROM_REGISTRY,
1566+
affinities: {
1567+
hardware_generation: "highest-overall-performance",
1568+
},
1569+
},
1570+
],
1571+
});
1572+
1573+
mockGetApplications([
1574+
{
1575+
id: "abc",
1576+
name: "my-container",
1577+
instances: 0,
1578+
max_instances: 10,
1579+
created_at: new Date().toString(),
1580+
version: 1,
1581+
account_id: "1",
1582+
scheduling_policy: SchedulingPolicy.DEFAULT,
1583+
rollout_active_grace_period: 0,
1584+
configuration: {
1585+
image: "docker.io/hello:world",
1586+
disk: {
1587+
size: "2GB",
1588+
size_mb: 2000,
1589+
},
1590+
vcpu: 0.0625,
1591+
memory: "256MB",
1592+
memory_mib: 256,
1593+
},
1594+
constraints: {
1595+
tier: 1,
1596+
},
1597+
durable_objects: {
1598+
namespace_id: "1",
1599+
},
1600+
},
1601+
]);
1602+
1603+
mockModifyApplication({
1604+
affinities: {
1605+
hardware_generation:
1606+
ApplicationAffinityHardwareGeneration.HIGHEST_OVERALL_PERFORMANCE,
1607+
},
1608+
});
1609+
mockCreateApplicationRollout({
1610+
description: "Progressive update",
1611+
strategy: "rolling",
1612+
kind: "full_auto",
1613+
});
1614+
1615+
await runWrangler("deploy index.js");
1616+
1617+
expect(cliStd.stdout).toMatchInlineSnapshot(`
1618+
"╭ Deploy a container application deploy changes to your application
1619+
1620+
│ Container application changes
1621+
1622+
├ EDIT my-container
1623+
1624+
│ [containers.constraints]
1625+
│ tier = 1
1626+
│ + [containers.affinities]
1627+
│ + hardware_generation = \\"highest-overall-performance\\"
1628+
1629+
1630+
│ SUCCESS Modified application my-container (Application ID: abc)
1631+
1632+
╰ Applied changes
1633+
1634+
"
1635+
`);
1636+
});
1637+
});
15001638
});
15011639

15021640
// This is a separate describe block because we intentionally do not mock any

packages/wrangler/src/cloudchamber/apply.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ import type {
4242
} from "../yargs-types";
4343
import type {
4444
Application,
45+
ApplicationAffinities,
46+
ApplicationAffinityColocation,
4547
ApplicationID,
4648
ApplicationName,
4749
CreateApplicationRequest,
@@ -50,6 +52,7 @@ import type {
5052
Observability as ObservabilityConfiguration,
5153
UserDeploymentConfiguration,
5254
} from "@cloudflare/containers-shared";
55+
import type { ApplicationAffinityHardwareGeneration } from "@cloudflare/containers-shared/src/client/models/ApplicationAffinityHardwareGeneration";
5356
import type { JsonMap } from "@iarna/toml";
5457

5558
function mergeDeep<T>(target: T, source: Partial<T>): T {
@@ -220,6 +223,28 @@ function containerAppToInstanceType(
220223
return configuration;
221224
}
222225

226+
/**
227+
* Perform type conversion of affinities so that they can be fed to the API.
228+
*/
229+
function convertContainerAffinitiesForApi(
230+
container: ContainerApp
231+
): ApplicationAffinities | undefined {
232+
if (container.affinities === undefined) {
233+
return undefined;
234+
}
235+
236+
const affinities: ApplicationAffinities = {
237+
colocation: container.affinities?.colocation as
238+
| ApplicationAffinityColocation
239+
| undefined,
240+
hardware_generation: container.affinities?.hardware_generation as
241+
| ApplicationAffinityHardwareGeneration
242+
| undefined,
243+
};
244+
245+
return affinities;
246+
}
247+
223248
function containerAppToCreateApplication(
224249
accountId: string,
225250
containerApp: ContainerApp,
@@ -267,6 +292,7 @@ function containerAppToCreateApplication(
267292
region.toUpperCase()
268293
),
269294
},
295+
affinities: convertContainerAffinitiesForApi(containerApp),
270296
};
271297

272298
// delete the fields that should not be sent to API

packages/wrangler/src/config/environment.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,15 @@ export type ContainerApp = {
150150
tier?: number;
151151
};
152152

153+
/**
154+
* Scheduling affinities
155+
* @hidden
156+
*/
157+
affinities?: {
158+
colocation?: "datacenter";
159+
hardware_generation?: "highest-overall-performance";
160+
};
161+
153162
// not used when deploying container with wrangler deploy
154163
/**
155164
* @deprecated use the `class_name` field instead.

packages/wrangler/src/config/validation.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2709,6 +2709,7 @@ function validateContainerApp(
27092709
"instance_type",
27102710
"configuration",
27112711
"constraints",
2712+
"affinities",
27122713
"rollout_step_percentage",
27132714
"rollout_kind",
27142715
"durable_objects",

0 commit comments

Comments
 (0)