UNPKG

@catladder/pipeline

Version:

Panter workflow for cloud CI/CD and DevOps

187 lines (173 loc) • 5.76 kB
import { bashEscape } from "../../../../bash"; import type { BashExpression, StringOrBashExpression, } from "../../../../bash/BashExpression"; import type { ComponentContext } from "../../../../types/context"; import { notNil } from "../../../../utils"; import type { DeployConfigCloudRunExecuteWithSchedule, DeployConfigCloudRunJobWithSchedule, } from "../../../types"; import { getCloudRunJobExecuteUrl } from "../../utils/cloudRunExecutionUrl"; import { createArgsString } from "../../utils/createArgsString"; import { getFullSchedulerName } from "../../utils/jobName"; import { getCloudRunJobsWithNames } from "../cloudRunJobs"; import { gcloudSchedulerCmd, getCloudRunDeployConfig } from "../common"; export const getDeleteSchedulesScript = (context: ComponentContext) => { const deployConfig = getCloudRunDeployConfig(context); const schedules = getSchedules(context); const argsString = createArgsString({ project: deployConfig.projectId, location: deployConfig.region, }); return schedules .map(({ fullName }) => { return [`${gcloudSchedulerCmd()} jobs delete ${fullName} ${argsString}`]; }) .flat(); }; export const getCreateScheduleScript = ( context: ComponentContext, ): string[] => { const schedules = getSchedules(context); const { region: location, projectId: project } = getCloudRunDeployConfig(context); return schedules.map(({ fullName, config }, jobIndex): string => { const { uri, ...args } = getSchedulerArgs(config, context); const argsString = createArgsString({ project, location, uri: `"$current_job_uri"`, ...args, schedule: `"${config.schedule}"`, "max-retry-attempts": config.maxRetryAttempts ?? 0, }); return [ jobIndex === 0 ? `exist_scheduler_names="$(\n ${gcloudSchedulerCmd()} jobs list --filter='httpTarget.uri ~ ${context.env}.*${context.name}' --format='value(name)' --limit=999 --location='${location}' --project='${project}'\n)"` : null, `current_job_uri="${uri}"`, `current_scheduler_name="${fullName}"`, `if echo "$exist_scheduler_names" | grep -Fx "$current_scheduler_name" >/dev/null; then`, ` ${gcloudSchedulerCmd()} jobs update http "$current_scheduler_name" ${argsString}`, `else`, ` ${gcloudSchedulerCmd()} jobs create http "$current_scheduler_name" ${argsString}`, `fi`, ] .filter(notNil) .join("\n"); }); }; const getSchedulerArgs = ( scheduler: DeployConfigCloudRunExecuteWithSchedule, context: ComponentContext, ): { uri: string; "http-method"?: string; "message-body"?: string; "oauth-service-account-email"?: string; "oidc-service-account-email"?: string; } => { if (scheduler.type === "job") { const { projectId, region } = getCloudRunDeployConfig(context); const body = scheduler.args !== undefined ? { overrides: { containerOverrides: [ scheduler.args?.length > 0 ? { args: scheduler.args, } : { args: [], clearArgs: true, // not sure why this is neeeded, but it is }, ], }, } : null; return { uri: getCloudRunJobExecuteUrl(scheduler.job, { appFullName: context.environment.fullName, projectId, region, }), "message-body": body ? '"' + bashEscape(JSON.stringify(body)) + '"' : undefined, "http-method": "POST", "oauth-service-account-email": `"$GCLOUD_PROJECT_NUMBER-compute@developer.gserviceaccount.com"`, }; } if (scheduler.type === "http") { return { uri: scheduler.url, "message-body": scheduler.body, "http-method": scheduler.method, "oidc-service-account-email": `"$GCLOUD_PROJECT_NUMBER-compute@developer.gserviceaccount.com"`, }; } throw new Error(`Unknown scheduler type: ${(scheduler as any).type}`); }; const getSchedules = ( context: ComponentContext, ): { name: string; fullName: StringOrBashExpression; config: DeployConfigCloudRunExecuteWithSchedule; }[] => { const legacyScheduleJobs = getLegacyJobSchedules(context); const schedules = getScheduledExecutes(context); return Object.entries({ ...legacyScheduleJobs, ...schedules }).map( ([name, config]) => ({ name, fullName: getFullSchedulerName(context, name), config, }), ); }; const getLegacyJobSchedules = ( context: ComponentContext, ): Record<string, DeployConfigCloudRunExecuteWithSchedule> => { const jobsWithNames = getCloudRunJobsWithNames(context); return Object.fromEntries( jobsWithNames .filter( ( entry, ): entry is { fullJobName: BashExpression; job: DeployConfigCloudRunJobWithSchedule; jobName: string; } => entry.job.when === "schedule", ) .map(({ job: { maxRetryAttempts, schedule }, jobName }) => { const schedulerName = jobName.concat("-scheduler"); return [ schedulerName, { type: "job", job: jobName, maxRetryAttempts, schedule, when: "schedule", }, ]; }), ); }; const getScheduledExecutes = ( context: ComponentContext, ): Record<string, DeployConfigCloudRunExecuteWithSchedule> => { const deployConfig = getCloudRunDeployConfig(context); return Object.fromEntries( Object.entries(deployConfig.execute ?? {}).flatMap(([key, value]) => { if (!value || value.when !== "schedule") { return []; } return [[key, value]]; }), ); };