1import * as dataproc from "@distilled.cloud/gcp/dataproc_v1";
2import * as Effect from "effect/Effect";
3import * as Layer from "effect/Layer";
4import type { Cluster } from "./Cluster.ts";
5import { SubmitJob, type SubmitJobRequest } from "./SubmitJob.ts";
6import { bindGcpHost } from "../Host.ts";
7
8/**
9 * HTTP implementation of {@link SubmitJob}.
10 *
11 * Grants `roles/dataproc.editor` on the project because
12 * `dataproc.jobs.create` is checked on the project (jobs are not children
13 * of the cluster, so neither a cluster-level grant nor an IAM Condition on
14 * the cluster name applies) and no narrower predefined role contains it.
15 *
16 * @layer
17 * @provides GCP.Dataproc.SubmitJob
18 */
19export const SubmitJobHttp = Layer.effect(
20 SubmitJob,
21 Effect.gen(function* () {
22 const submitProjectsRegionsJobs = yield* dataproc.submitProjectsRegionsJobs;
23 return Effect.fn(function* <T extends Cluster>(cluster: T) {
24 yield* bindGcpHost({
25 tag: "GCP.Dataproc.SubmitJob",
26 resource: cluster,
27 // dataproc.jobs.create is checked on the project (jobs are not
28 // children of the cluster); no narrower predefined role contains it.
29 iam: [{ role: "roles/dataproc.editor" }],
30 });
31 const projectId = yield* cluster.project;
32 const region = yield* cluster.region;
33 const clusterName = yield* cluster.clusterName;
34 return Effect.fn(`GCP.Dataproc.SubmitJob(${cluster.LogicalId})`)(
35 function* (request: SubmitJobRequest) {
36 const resolvedProject = yield* projectId;
37 const resolvedRegion = yield* region;
38 const resolvedCluster = yield* clusterName;
39 const job = request.body?.job;
40 return yield* submitProjectsRegionsJobs({
41 ...request,
42 projectId: resolvedProject,
43 region: resolvedRegion,
44 body: {
45 ...request?.body,
46 job: {
47 ...job,
48 placement: {
49 ...job?.placement,
50 clusterName: job?.placement?.clusterName ?? resolvedCluster,
51 },
52 },
53 },
54 });
55 },
56 );
57 });
58 }),
59);