@cyc-seattle/platform 0.4.1 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -51,6 +51,12 @@ export interface WorkloadArgs extends PodArgs {
51
51
  startupProbe?: Probe;
52
52
  /** Defaults to 1. */
53
53
  replicas?: number;
54
+ /** Annotations on each pod, such as `cluster-autoscaler.kubernetes.io/safe-to-evict`. */
55
+ podAnnotations?: Record<string, string>;
56
+ /** Prefers pods in different zones. A preference, so one zone's capacity can still schedule them all. */
57
+ spreadAcrossZones?: boolean;
58
+ /** Adds a PodDisruptionBudget that keeps this many pods up through drains. Must be below `replicas`. */
59
+ minAvailable?: number;
54
60
  }
55
61
  /** The pods' Workload Identity principal, for IAM grants. */
56
62
  export declare function workloadMember(platform: pulumi.Output<PlatformOutputs>, serviceAccountName: pulumi.Input<string>): pulumi.Output<string>;
package/dist/workload.js CHANGED
@@ -128,23 +128,43 @@ function deployment(parent, name, args, http) {
128
128
  // The API rejects two ports with one name, and only after the preview.
129
129
  throw new Error(`${name}: "ports" can't name a port "http"; a WebService's own port has that name.`);
130
130
  }
131
+ const replicas = args.replicas ?? 1;
132
+ if (args.minAvailable !== undefined && args.minAvailable >= replicas) {
133
+ // Such a budget blocks every drain, so node upgrades stall on it.
134
+ throw new Error(`${name}: "minAvailable" (${args.minAvailable}) must be below "replicas" (${replicas}).`);
135
+ }
131
136
  const ports = [...(http !== undefined ? [{ name: "http", port: http }] : []), ...(args.ports ?? [])];
132
137
  new k8s.apps.v1.Deployment(name, {
133
138
  metadata,
134
139
  spec: {
135
- replicas: args.replicas ?? 1,
140
+ replicas,
136
141
  selector: { matchLabels: labels },
137
142
  template: {
138
- metadata: { labels },
143
+ metadata: { labels, ...(args.podAnnotations && { annotations: args.podAnnotations }) },
139
144
  spec: podSpec(name, args, account.metadata.name, {
140
145
  ...(ports.length > 0 && { ports: ports.map((p) => ({ name: p.name, containerPort: p.port })) }),
141
146
  ...(args.readinessProbe && { readinessProbe: args.readinessProbe }),
142
147
  ...(args.livenessProbe && { livenessProbe: args.livenessProbe }),
143
148
  ...(args.startupProbe && { startupProbe: args.startupProbe }),
144
- }),
149
+ }).apply((spec) => ({
150
+ ...spec,
151
+ ...(args.spreadAcrossZones && {
152
+ topologySpreadConstraints: [
153
+ {
154
+ maxSkew: 1,
155
+ topologyKey: "topology.kubernetes.io/zone",
156
+ whenUnsatisfiable: "ScheduleAnyway",
157
+ labelSelector: { matchLabels: labels },
158
+ },
159
+ ],
160
+ }),
161
+ })),
145
162
  },
146
163
  },
147
164
  }, child);
165
+ if (args.minAvailable !== undefined) {
166
+ new k8s.policy.v1.PodDisruptionBudget(name, { metadata, spec: { minAvailable: args.minAvailable, selector: { matchLabels: labels } } }, child);
167
+ }
148
168
  if (ports.length === 0) {
149
169
  return { serviceAccount: account };
150
170
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cyc-seattle/platform",
3
- "version": "0.4.1",
3
+ "version": "0.5.0",
4
4
  "description": "Pulumi components for CYC's shared Google Cloud platform: WebService, the platform outputs reader, and the stacks that build the platform",
5
5
  "author": "CYC Community Sailing Center",
6
6
  "license": "Apache-2.0",