import { type RegisterTaskDefinitionCommandInput, type Tag, type TaskDefinition } from "@aws-sdk/client-ecs"; import type { AwsProvider } from "../../aws/AwsProvider.js"; import { type Result } from "@fjall/generator"; import { EcsError } from "./ecsError.js"; import { type ServiceDeploymentBriefInfo, type ServiceDeploymentsDescription, type ServiceRevisionsDescription } from "./ecsServiceDeployments.js"; export { EcsError }; export interface ECSServiceInfo { serviceArn?: string; serviceName?: string; clusterArn?: string; status?: string; desiredCount?: number; runningCount?: number; pendingCount?: number; deployments?: Array<{ id?: string; status?: string; desiredCount?: number; runningCount?: number; pendingCount?: number; failedTasks?: number; rolloutState?: string; rolloutStateReason?: string; taskDefinition?: string; createdAt?: Date; }>; events?: Array<{ id?: string; message?: string; createdAt?: Date; }>; taskDefinition?: string; } /** * Forensic snapshot of a stopped ECS task — the fields the deployment tail * narrates when a rolling update sheds tasks (`stoppedReason`, `stopCode`, * per-container exit codes). All optional because ECS omits them for tasks * stopped before placement. */ export interface StoppedTaskInfo { taskArn: string; taskDefinitionArn?: string; stoppedReason?: string; stopCode?: string; startedBy?: string; createdAt?: Date; /** * When the task went from RUNNING to STOPPING, when its execution stopped, * and when it reached STOPPED. ListTasks lists a task from when ECS sets * its desired status to STOPPED, which can be before the task reaches * STOPPED, so a task it lists can have no stoppedAt yet. */ stoppingAt?: Date; executionStoppedAt?: Date; stoppedAt?: Date; containers: Array<{ name?: string; exitCode?: number; reason?: string; }>; } export interface ECSClusterInfo { clusterArn?: string; clusterName?: string; status?: string; registeredContainerInstancesCount?: number; runningTasksCount?: number; pendingTasksCount?: number; } export interface DeploymentStatus { deploymentCompleted: boolean; deploymentFailed: boolean; runningCount: number; desiredCount: number; pendingCount: number; deploymentCount: number; message: string; percentComplete?: number; latestEvent?: string; } /** One ECS service addressed by the cluster it lives in. */ export interface EcsServiceTarget { clusterArn: string; serviceArn: string; } /** * A service ECS reported under `failures` instead of describing: `reason` * is ECS's own code (`MISSING` for a service the cluster does not hold). */ export interface EcsDescribeFailure { serviceArn: string; reason: string; } export interface EcsServicesDescription { services: ECSServiceInfo[]; failures: EcsDescribeFailure[]; } /** * How long `pollDeployment` waits on a deployment by default. The engine's * roll (`rollServiceToTaskDefinition`) spends what a failed wait leaves of * it reading ECS's verdict on the deployment. */ export declare const DEPLOYMENT_POLL_MAX_WAIT_MS = 600000; export interface ECSDeploymentOptions { clusterArn: string; serviceArn: string; waitForCompletion?: boolean; maxWaitTime?: number; pollInterval?: number; progressCallback?: (status: DeploymentStatus) => void; abortSignal?: AbortSignal; } /** * ECS service using the AwsProvider interface. * * Constructor-injected provider matches the CloudFormationService pattern: * deploy-core receives a pre-configured AwsProvider and never lazily resolves * credentials. CLI passes its AwsContext (which implements AwsProvider); * the worker passes SimpleAwsProvider. */ export declare class EcsService { private aws; constructor(aws: AwsProvider); private getClient; updateService(clusterArn: string, serviceArn: string, options?: { desiredCount?: number; taskDefinition?: string; forceNewDeployment?: boolean; }, abortSignal?: AbortSignal): Promise>; /** * DescribeServices for services that all live in ONE cluster, batched at * the API's limit of 10 per call. Rejections escape to the caller, which * owns the failure message; an abort mid-way stops the walk and reports * the ARNs it never reached in `undescribed`, which every caller turns * into a refusal rather than a short answer. */ private describeServicesInCluster; /** * Describe services that all live in `clusterArn`. A service ECS reports * under `failures` (one the cluster does not hold) is absent from the * result — callers that must know why a service is missing use * `describeServicesAcrossClusters`, which surfaces every failure. An abort * mid-walk fails rather than returning the services it reached. */ describeServices(clusterArn: string, serviceArns: string[], abortSignal?: AbortSignal): Promise>; /** * Describe services that may span clusters. DescribeServices takes one * cluster per call and rejects the whole call when any ARN belongs to * another, so the targets are grouped by cluster (first-seen order, input * order within a cluster) and each group batched at 10. Every entry ECS * reports under `failures` is surfaced; an SDK error on any cluster fails * the whole call, naming the cluster. An abort fails too, naming every * service left undescribed: a caller reading this description by target * cannot tell a row nobody asked about from one ECS answered for. */ describeServicesAcrossClusters(targets: readonly EcsServiceTarget[], abortSignal?: AbortSignal): Promise>; getDeploymentStatus(clusterArn: string, serviceArn: string, abortSignal?: AbortSignal): Promise>; isDeploying(clusterArn: string, serviceArn: string): Promise>; getServiceEvents(clusterArn: string, serviceArn: string, abortSignal?: AbortSignal): Promise, EcsError>>; pollDeployment(options: ECSDeploymentOptions): Promise>; private processDeploymentEvents; listClusters(abortSignal?: AbortSignal): Promise>; describeClusters(clusterArns: string[], abortSignal?: AbortSignal): Promise>; listServices(clusterArn: string, abortSignal?: AbortSignal): Promise>; registerTaskDefinition(taskDefinition: RegisterTaskDefinitionCommandInput, abortSignal?: AbortSignal): Promise>; /** * The tags of a task-definition revision, for a caller that registers a new * revision of it and must keep the ones Fjall's own readers need. * * The failure message is pre-masked at construction, as * `getLatestTaskDefinition`'s is. */ listTaskDefinitionTags(taskDefinitionArn: string, abortSignal?: AbortSignal): Promise>; /** * Read a task definition by family or ARN. * * The failure message is pre-masked at construction, and STRIPPED BEFORE IT * IS MASKED: the secrets-drift probe surfaces it verbatim as a service's * `unknownReason`, which reaches a terminal and the persisted CD log. An * escape sequence planted inside a credential's key splits the mask's * anchor, so a mask applied to unstripped text matches nothing and the * secret survives. Callers must not mask it again (one mask per path). */ getLatestTaskDefinition(family: string, abortSignal?: AbortSignal): Promise>; deployService(clusterArn: string, serviceArn: string, options?: { taskDefinition?: string; waitForCompletion?: boolean; progressCallback?: (status: DeploymentStatus) => void; abortSignal?: AbortSignal; }): Promise>; /** * List STOPPED task ARNs started by a specific originator (an ECS service * deployment id, e.g. `ecs-svc/9223370…`). Paginated; an abort mid-way * returns the pages gathered so far. */ listStoppedTasks(clusterArn: string, startedBy: string, abortSignal?: AbortSignal): Promise>; /** `listServiceDeployments` in `ecsServiceDeployments.ts`, over this provider's client. */ listServiceDeployments(clusterArn: string, serviceArn: string, createdAfter: Date, abortSignal?: AbortSignal): Promise>; /** `describeServiceDeployments` in `ecsServiceDeployments.ts`, over this provider's client. */ describeServiceDeployments(serviceDeploymentArns: readonly string[], abortSignal?: AbortSignal): Promise>; /** `describeServiceRevisions` in `ecsServiceDeployments.ts`, over this provider's client. */ describeServiceRevisions(serviceRevisionArns: readonly string[], abortSignal?: AbortSignal): Promise>; /** * Describe stopped tasks and extract the forensic fields (`stoppedReason`, * `stopCode`, container exit codes). Batched at the DescribeTasks limit of * 100 ARNs per call; an abort mid-way returns the batches gathered so far. */ describeTasks(clusterArn: string, taskArns: string[], abortSignal?: AbortSignal): Promise>; }