@go-to-k/cdkd 0.63.0 → 0.65.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.
- package/dist/cli.js +1618 -1
- package/dist/cli.js.map +3 -3
- package/dist/go-to-k-cdkd-0.65.0.tgz +0 -0
- package/package.json +1 -1
- package/dist/go-to-k-cdkd-0.63.0.tgz +0 -0
package/dist/cli.js
CHANGED
|
@@ -56180,6 +56180,35 @@ import {
|
|
|
56180
56180
|
GetTableCommand,
|
|
56181
56181
|
GetTablesCommand,
|
|
56182
56182
|
GetTagsCommand,
|
|
56183
|
+
CreateWorkflowCommand,
|
|
56184
|
+
UpdateWorkflowCommand,
|
|
56185
|
+
DeleteWorkflowCommand,
|
|
56186
|
+
GetWorkflowCommand,
|
|
56187
|
+
ListWorkflowsCommand,
|
|
56188
|
+
CreateSecurityConfigurationCommand,
|
|
56189
|
+
DeleteSecurityConfigurationCommand,
|
|
56190
|
+
GetSecurityConfigurationCommand,
|
|
56191
|
+
GetSecurityConfigurationsCommand,
|
|
56192
|
+
CreateJobCommand,
|
|
56193
|
+
UpdateJobCommand,
|
|
56194
|
+
DeleteJobCommand,
|
|
56195
|
+
GetJobCommand,
|
|
56196
|
+
CreateCrawlerCommand,
|
|
56197
|
+
UpdateCrawlerCommand,
|
|
56198
|
+
DeleteCrawlerCommand,
|
|
56199
|
+
GetCrawlerCommand,
|
|
56200
|
+
StartCrawlerScheduleCommand,
|
|
56201
|
+
StopCrawlerScheduleCommand,
|
|
56202
|
+
CreateConnectionCommand,
|
|
56203
|
+
UpdateConnectionCommand,
|
|
56204
|
+
DeleteConnectionCommand,
|
|
56205
|
+
GetConnectionCommand,
|
|
56206
|
+
CreateTriggerCommand,
|
|
56207
|
+
UpdateTriggerCommand,
|
|
56208
|
+
DeleteTriggerCommand,
|
|
56209
|
+
GetTriggerCommand,
|
|
56210
|
+
StartTriggerCommand,
|
|
56211
|
+
StopTriggerCommand,
|
|
56183
56212
|
EntityNotFoundException
|
|
56184
56213
|
} from "@aws-sdk/client-glue";
|
|
56185
56214
|
import { STSClient as STSClient8, GetCallerIdentityCommand as GetCallerIdentityCommand8 } from "@aws-sdk/client-sts";
|
|
@@ -56872,6 +56901,1588 @@ var GlueProvider = class {
|
|
|
56872
56901
|
return this.cachedAccountId;
|
|
56873
56902
|
}
|
|
56874
56903
|
};
|
|
56904
|
+
var GlueWorkflowProvider = class {
|
|
56905
|
+
client;
|
|
56906
|
+
stsClient;
|
|
56907
|
+
cachedAccountId;
|
|
56908
|
+
providerRegion = process.env["AWS_REGION"];
|
|
56909
|
+
logger = getLogger().child("GlueWorkflowProvider");
|
|
56910
|
+
handledProperties = /* @__PURE__ */ new Map([
|
|
56911
|
+
[
|
|
56912
|
+
"AWS::Glue::Workflow",
|
|
56913
|
+
/* @__PURE__ */ new Set(["Name", "Description", "DefaultRunProperties", "MaxConcurrentRuns", "Tags"])
|
|
56914
|
+
]
|
|
56915
|
+
]);
|
|
56916
|
+
getClient() {
|
|
56917
|
+
if (!this.client) {
|
|
56918
|
+
this.client = new GlueClient(this.providerRegion ? { region: this.providerRegion } : {});
|
|
56919
|
+
}
|
|
56920
|
+
return this.client;
|
|
56921
|
+
}
|
|
56922
|
+
async create(logicalId, resourceType, properties) {
|
|
56923
|
+
this.logger.debug(`Creating Glue Workflow ${logicalId}`);
|
|
56924
|
+
const name = properties["Name"];
|
|
56925
|
+
if (!name) {
|
|
56926
|
+
throw new ProvisioningError(
|
|
56927
|
+
`Name is required for Glue Workflow ${logicalId}`,
|
|
56928
|
+
resourceType,
|
|
56929
|
+
logicalId
|
|
56930
|
+
);
|
|
56931
|
+
}
|
|
56932
|
+
try {
|
|
56933
|
+
const tags = workflowTagsForCreate(properties["Tags"]);
|
|
56934
|
+
await this.getClient().send(
|
|
56935
|
+
new CreateWorkflowCommand({
|
|
56936
|
+
Name: name,
|
|
56937
|
+
...properties["Description"] !== void 0 && {
|
|
56938
|
+
Description: properties["Description"]
|
|
56939
|
+
},
|
|
56940
|
+
...properties["DefaultRunProperties"] !== void 0 && {
|
|
56941
|
+
DefaultRunProperties: properties["DefaultRunProperties"]
|
|
56942
|
+
},
|
|
56943
|
+
...properties["MaxConcurrentRuns"] !== void 0 && {
|
|
56944
|
+
MaxConcurrentRuns: properties["MaxConcurrentRuns"]
|
|
56945
|
+
},
|
|
56946
|
+
...tags && { Tags: tags }
|
|
56947
|
+
})
|
|
56948
|
+
);
|
|
56949
|
+
this.logger.debug(`Successfully created Glue Workflow ${logicalId}: ${name}`);
|
|
56950
|
+
return { physicalId: name, attributes: {} };
|
|
56951
|
+
} catch (error) {
|
|
56952
|
+
const cause = error instanceof Error ? error : void 0;
|
|
56953
|
+
throw new ProvisioningError(
|
|
56954
|
+
`Failed to create Glue Workflow ${logicalId}: ${error instanceof Error ? error.message : String(error)}`,
|
|
56955
|
+
resourceType,
|
|
56956
|
+
logicalId,
|
|
56957
|
+
void 0,
|
|
56958
|
+
cause
|
|
56959
|
+
);
|
|
56960
|
+
}
|
|
56961
|
+
}
|
|
56962
|
+
async update(logicalId, physicalId, resourceType, properties, _previousProperties) {
|
|
56963
|
+
this.logger.debug(`Updating Glue Workflow ${logicalId}: ${physicalId}`);
|
|
56964
|
+
try {
|
|
56965
|
+
await this.getClient().send(
|
|
56966
|
+
new UpdateWorkflowCommand({
|
|
56967
|
+
Name: physicalId,
|
|
56968
|
+
...properties["Description"] !== void 0 && {
|
|
56969
|
+
Description: properties["Description"]
|
|
56970
|
+
},
|
|
56971
|
+
...properties["DefaultRunProperties"] !== void 0 && {
|
|
56972
|
+
DefaultRunProperties: properties["DefaultRunProperties"]
|
|
56973
|
+
},
|
|
56974
|
+
...properties["MaxConcurrentRuns"] !== void 0 && {
|
|
56975
|
+
MaxConcurrentRuns: properties["MaxConcurrentRuns"]
|
|
56976
|
+
}
|
|
56977
|
+
})
|
|
56978
|
+
);
|
|
56979
|
+
this.logger.debug(`Successfully updated Glue Workflow ${logicalId}`);
|
|
56980
|
+
return { physicalId, wasReplaced: false };
|
|
56981
|
+
} catch (error) {
|
|
56982
|
+
const cause = error instanceof Error ? error : void 0;
|
|
56983
|
+
throw new ProvisioningError(
|
|
56984
|
+
`Failed to update Glue Workflow ${logicalId}: ${error instanceof Error ? error.message : String(error)}`,
|
|
56985
|
+
resourceType,
|
|
56986
|
+
logicalId,
|
|
56987
|
+
physicalId,
|
|
56988
|
+
cause
|
|
56989
|
+
);
|
|
56990
|
+
}
|
|
56991
|
+
}
|
|
56992
|
+
async delete(logicalId, physicalId, resourceType, _properties, context) {
|
|
56993
|
+
this.logger.debug(`Deleting Glue Workflow ${logicalId}: ${physicalId}`);
|
|
56994
|
+
try {
|
|
56995
|
+
await this.getClient().send(new DeleteWorkflowCommand({ Name: physicalId }));
|
|
56996
|
+
this.logger.debug(`Successfully deleted Glue Workflow ${logicalId}`);
|
|
56997
|
+
} catch (error) {
|
|
56998
|
+
if (error instanceof EntityNotFoundException) {
|
|
56999
|
+
const clientRegion = await this.getClient().config.region();
|
|
57000
|
+
assertRegionMatch(
|
|
57001
|
+
clientRegion,
|
|
57002
|
+
context?.expectedRegion,
|
|
57003
|
+
resourceType,
|
|
57004
|
+
logicalId,
|
|
57005
|
+
physicalId
|
|
57006
|
+
);
|
|
57007
|
+
this.logger.debug(`Glue Workflow ${physicalId} does not exist, skipping deletion`);
|
|
57008
|
+
return;
|
|
57009
|
+
}
|
|
57010
|
+
const cause = error instanceof Error ? error : void 0;
|
|
57011
|
+
throw new ProvisioningError(
|
|
57012
|
+
`Failed to delete Glue Workflow ${logicalId}: ${error instanceof Error ? error.message : String(error)}`,
|
|
57013
|
+
resourceType,
|
|
57014
|
+
logicalId,
|
|
57015
|
+
physicalId,
|
|
57016
|
+
cause
|
|
57017
|
+
);
|
|
57018
|
+
}
|
|
57019
|
+
}
|
|
57020
|
+
// eslint-disable-next-line @typescript-eslint/require-await -- explicit-override-only intentionally has no AWS calls
|
|
57021
|
+
async getAttribute(physicalId, _resourceType, attributeName) {
|
|
57022
|
+
if (attributeName === "Id" || attributeName === "Ref" || attributeName === "Name") {
|
|
57023
|
+
return physicalId;
|
|
57024
|
+
}
|
|
57025
|
+
return void 0;
|
|
57026
|
+
}
|
|
57027
|
+
/**
|
|
57028
|
+
* Read AWS-current Workflow shape via `GetWorkflow`. Surfaces every
|
|
57029
|
+
* user-controllable top-level CFn key with always-emit placeholders
|
|
57030
|
+
* (PR #145):
|
|
57031
|
+
* - `Description` → `?? ''`
|
|
57032
|
+
* - `DefaultRunProperties` → `?? {}`
|
|
57033
|
+
* - `MaxConcurrentRuns` → omitted when AWS reports `undefined` (no
|
|
57034
|
+
* AWS-side default to anchor a placeholder against; cdkd state may
|
|
57035
|
+
* legitimately leave this unset)
|
|
57036
|
+
* - `Tags` → `?? []` (filtered against `aws:cdk:path` and the rest of
|
|
57037
|
+
* the `aws:`-prefixed reserved space)
|
|
57038
|
+
*/
|
|
57039
|
+
async readCurrentState(physicalId, _logicalId, _resourceType) {
|
|
57040
|
+
let workflow;
|
|
57041
|
+
try {
|
|
57042
|
+
const resp = await this.getClient().send(
|
|
57043
|
+
new GetWorkflowCommand({ Name: physicalId, IncludeGraph: false })
|
|
57044
|
+
);
|
|
57045
|
+
workflow = resp.Workflow;
|
|
57046
|
+
} catch (err) {
|
|
57047
|
+
if (err instanceof EntityNotFoundException)
|
|
57048
|
+
return void 0;
|
|
57049
|
+
throw err;
|
|
57050
|
+
}
|
|
57051
|
+
if (!workflow)
|
|
57052
|
+
return void 0;
|
|
57053
|
+
const result = {
|
|
57054
|
+
Name: workflow.Name ?? physicalId,
|
|
57055
|
+
Description: workflow.Description ?? "",
|
|
57056
|
+
DefaultRunProperties: workflow.DefaultRunProperties ?? {}
|
|
57057
|
+
};
|
|
57058
|
+
if (workflow.MaxConcurrentRuns !== void 0) {
|
|
57059
|
+
result["MaxConcurrentRuns"] = workflow.MaxConcurrentRuns;
|
|
57060
|
+
}
|
|
57061
|
+
const arn = await this.buildWorkflowArn(physicalId);
|
|
57062
|
+
let tags = [];
|
|
57063
|
+
try {
|
|
57064
|
+
const tagResp = await this.getClient().send(new GetTagsCommand({ ResourceArn: arn }));
|
|
57065
|
+
tags = normalizeAwsTagsToCfn(tagResp.Tags);
|
|
57066
|
+
} catch (err) {
|
|
57067
|
+
this.logger.debug(
|
|
57068
|
+
`GetTags failed for Glue Workflow ${physicalId}: ${err instanceof Error ? err.message : String(err)}`
|
|
57069
|
+
);
|
|
57070
|
+
}
|
|
57071
|
+
result["Tags"] = tags;
|
|
57072
|
+
return result;
|
|
57073
|
+
}
|
|
57074
|
+
async import(input) {
|
|
57075
|
+
const explicitName = input.knownPhysicalId ?? input.properties["Name"];
|
|
57076
|
+
if (explicitName) {
|
|
57077
|
+
try {
|
|
57078
|
+
await this.getClient().send(new GetWorkflowCommand({ Name: explicitName }));
|
|
57079
|
+
return { physicalId: explicitName, attributes: {} };
|
|
57080
|
+
} catch (err) {
|
|
57081
|
+
if (err instanceof EntityNotFoundException)
|
|
57082
|
+
return null;
|
|
57083
|
+
throw err;
|
|
57084
|
+
}
|
|
57085
|
+
}
|
|
57086
|
+
if (!input.cdkPath)
|
|
57087
|
+
return null;
|
|
57088
|
+
let nextToken;
|
|
57089
|
+
do {
|
|
57090
|
+
const list = await this.getClient().send(
|
|
57091
|
+
new ListWorkflowsCommand({ ...nextToken && { NextToken: nextToken } })
|
|
57092
|
+
);
|
|
57093
|
+
for (const name of list.Workflows ?? []) {
|
|
57094
|
+
const arn = await this.buildWorkflowArn(name);
|
|
57095
|
+
if (await this.tagsMatchCdkPath(arn, input.cdkPath)) {
|
|
57096
|
+
return { physicalId: name, attributes: {} };
|
|
57097
|
+
}
|
|
57098
|
+
}
|
|
57099
|
+
nextToken = list.NextToken;
|
|
57100
|
+
} while (nextToken);
|
|
57101
|
+
return null;
|
|
57102
|
+
}
|
|
57103
|
+
async tagsMatchCdkPath(arn, cdkPath) {
|
|
57104
|
+
try {
|
|
57105
|
+
const resp = await this.getClient().send(new GetTagsCommand({ ResourceArn: arn }));
|
|
57106
|
+
return resp.Tags?.[CDK_PATH_TAG] === cdkPath;
|
|
57107
|
+
} catch (err) {
|
|
57108
|
+
if (err instanceof EntityNotFoundException)
|
|
57109
|
+
return false;
|
|
57110
|
+
throw err;
|
|
57111
|
+
}
|
|
57112
|
+
}
|
|
57113
|
+
async buildWorkflowArn(workflowName) {
|
|
57114
|
+
const region = await this.getRegion();
|
|
57115
|
+
const account = await this.getAccountId();
|
|
57116
|
+
return `arn:aws:glue:${region}:${account}:workflow/${workflowName}`;
|
|
57117
|
+
}
|
|
57118
|
+
async getRegion() {
|
|
57119
|
+
const region = await this.getClient().config.region();
|
|
57120
|
+
return region || this.providerRegion || "us-east-1";
|
|
57121
|
+
}
|
|
57122
|
+
async getAccountId() {
|
|
57123
|
+
if (this.cachedAccountId)
|
|
57124
|
+
return this.cachedAccountId;
|
|
57125
|
+
if (!this.stsClient) {
|
|
57126
|
+
this.stsClient = new STSClient8(this.providerRegion ? { region: this.providerRegion } : {});
|
|
57127
|
+
}
|
|
57128
|
+
const identity = await this.stsClient.send(new GetCallerIdentityCommand8({}));
|
|
57129
|
+
if (!identity.Account) {
|
|
57130
|
+
throw new Error("Failed to resolve AWS account id from STS");
|
|
57131
|
+
}
|
|
57132
|
+
this.cachedAccountId = identity.Account;
|
|
57133
|
+
return this.cachedAccountId;
|
|
57134
|
+
}
|
|
57135
|
+
};
|
|
57136
|
+
var GlueSecurityConfigurationProvider = class {
|
|
57137
|
+
client;
|
|
57138
|
+
providerRegion = process.env["AWS_REGION"];
|
|
57139
|
+
logger = getLogger().child("GlueSecurityConfigurationProvider");
|
|
57140
|
+
handledProperties = /* @__PURE__ */ new Map([
|
|
57141
|
+
["AWS::Glue::SecurityConfiguration", /* @__PURE__ */ new Set(["Name", "EncryptionConfiguration"])]
|
|
57142
|
+
]);
|
|
57143
|
+
getClient() {
|
|
57144
|
+
if (!this.client) {
|
|
57145
|
+
this.client = new GlueClient(this.providerRegion ? { region: this.providerRegion } : {});
|
|
57146
|
+
}
|
|
57147
|
+
return this.client;
|
|
57148
|
+
}
|
|
57149
|
+
async create(logicalId, resourceType, properties) {
|
|
57150
|
+
this.logger.debug(`Creating Glue SecurityConfiguration ${logicalId}`);
|
|
57151
|
+
const name = properties["Name"];
|
|
57152
|
+
if (!name) {
|
|
57153
|
+
throw new ProvisioningError(
|
|
57154
|
+
`Name is required for Glue SecurityConfiguration ${logicalId}`,
|
|
57155
|
+
resourceType,
|
|
57156
|
+
logicalId
|
|
57157
|
+
);
|
|
57158
|
+
}
|
|
57159
|
+
const encryptionConfiguration = properties["EncryptionConfiguration"];
|
|
57160
|
+
if (!encryptionConfiguration) {
|
|
57161
|
+
throw new ProvisioningError(
|
|
57162
|
+
`EncryptionConfiguration is required for Glue SecurityConfiguration ${logicalId}`,
|
|
57163
|
+
resourceType,
|
|
57164
|
+
logicalId
|
|
57165
|
+
);
|
|
57166
|
+
}
|
|
57167
|
+
try {
|
|
57168
|
+
await this.getClient().send(
|
|
57169
|
+
new CreateSecurityConfigurationCommand({
|
|
57170
|
+
Name: name,
|
|
57171
|
+
EncryptionConfiguration: buildEncryptionConfiguration(encryptionConfiguration)
|
|
57172
|
+
})
|
|
57173
|
+
);
|
|
57174
|
+
this.logger.debug(`Successfully created Glue SecurityConfiguration ${logicalId}: ${name}`);
|
|
57175
|
+
return { physicalId: name, attributes: {} };
|
|
57176
|
+
} catch (error) {
|
|
57177
|
+
const cause = error instanceof Error ? error : void 0;
|
|
57178
|
+
throw new ProvisioningError(
|
|
57179
|
+
`Failed to create Glue SecurityConfiguration ${logicalId}: ${error instanceof Error ? error.message : String(error)}`,
|
|
57180
|
+
resourceType,
|
|
57181
|
+
logicalId,
|
|
57182
|
+
void 0,
|
|
57183
|
+
cause
|
|
57184
|
+
);
|
|
57185
|
+
}
|
|
57186
|
+
}
|
|
57187
|
+
// eslint-disable-next-line @typescript-eslint/require-await -- explicit-override-only intentionally has no AWS calls
|
|
57188
|
+
async update(logicalId, _physicalId, resourceType, _properties, _previousProperties) {
|
|
57189
|
+
throw new ResourceUpdateNotSupportedError(
|
|
57190
|
+
resourceType,
|
|
57191
|
+
logicalId,
|
|
57192
|
+
"AWS::Glue::SecurityConfiguration is immutable; AWS provides no Update API. Use cdkd deploy --replace, or destroy + redeploy with the new EncryptionConfiguration."
|
|
57193
|
+
);
|
|
57194
|
+
}
|
|
57195
|
+
async delete(logicalId, physicalId, resourceType, _properties, context) {
|
|
57196
|
+
this.logger.debug(`Deleting Glue SecurityConfiguration ${logicalId}: ${physicalId}`);
|
|
57197
|
+
try {
|
|
57198
|
+
await this.getClient().send(new DeleteSecurityConfigurationCommand({ Name: physicalId }));
|
|
57199
|
+
this.logger.debug(`Successfully deleted Glue SecurityConfiguration ${logicalId}`);
|
|
57200
|
+
} catch (error) {
|
|
57201
|
+
if (error instanceof EntityNotFoundException) {
|
|
57202
|
+
const clientRegion = await this.getClient().config.region();
|
|
57203
|
+
assertRegionMatch(
|
|
57204
|
+
clientRegion,
|
|
57205
|
+
context?.expectedRegion,
|
|
57206
|
+
resourceType,
|
|
57207
|
+
logicalId,
|
|
57208
|
+
physicalId
|
|
57209
|
+
);
|
|
57210
|
+
this.logger.debug(
|
|
57211
|
+
`Glue SecurityConfiguration ${physicalId} does not exist, skipping deletion`
|
|
57212
|
+
);
|
|
57213
|
+
return;
|
|
57214
|
+
}
|
|
57215
|
+
const cause = error instanceof Error ? error : void 0;
|
|
57216
|
+
throw new ProvisioningError(
|
|
57217
|
+
`Failed to delete Glue SecurityConfiguration ${logicalId}: ${error instanceof Error ? error.message : String(error)}`,
|
|
57218
|
+
resourceType,
|
|
57219
|
+
logicalId,
|
|
57220
|
+
physicalId,
|
|
57221
|
+
cause
|
|
57222
|
+
);
|
|
57223
|
+
}
|
|
57224
|
+
}
|
|
57225
|
+
// eslint-disable-next-line @typescript-eslint/require-await -- explicit-override-only intentionally has no AWS calls
|
|
57226
|
+
async getAttribute(physicalId, _resourceType, attributeName) {
|
|
57227
|
+
if (attributeName === "Id" || attributeName === "Ref" || attributeName === "Name") {
|
|
57228
|
+
return physicalId;
|
|
57229
|
+
}
|
|
57230
|
+
return void 0;
|
|
57231
|
+
}
|
|
57232
|
+
/**
|
|
57233
|
+
* Read AWS-current SecurityConfiguration shape via
|
|
57234
|
+
* `GetSecurityConfiguration`. Always emits the three CFn-modeled
|
|
57235
|
+
* sub-configs (`S3Encryption: []`, `CloudWatchEncryption: {}`,
|
|
57236
|
+
* `JobBookmarksEncryption: {}`) per PR #145 even when AWS reports
|
|
57237
|
+
* nothing — closes the "console-side encryption enable on a previously
|
|
57238
|
+
* default config" detection gap on the v3 baseline.
|
|
57239
|
+
*
|
|
57240
|
+
* `DataQualityEncryption` is silently dropped: the CFn schema for
|
|
57241
|
+
* `AWS::Glue::SecurityConfiguration` does not model it, so surfacing it
|
|
57242
|
+
* would fire false drift on every clean run for a key cdkd state can
|
|
57243
|
+
* never carry.
|
|
57244
|
+
*/
|
|
57245
|
+
async readCurrentState(physicalId, _logicalId, _resourceType) {
|
|
57246
|
+
let cfg;
|
|
57247
|
+
try {
|
|
57248
|
+
const resp = await this.getClient().send(
|
|
57249
|
+
new GetSecurityConfigurationCommand({ Name: physicalId })
|
|
57250
|
+
);
|
|
57251
|
+
cfg = resp.SecurityConfiguration;
|
|
57252
|
+
} catch (err) {
|
|
57253
|
+
if (err instanceof EntityNotFoundException)
|
|
57254
|
+
return void 0;
|
|
57255
|
+
throw err;
|
|
57256
|
+
}
|
|
57257
|
+
if (!cfg)
|
|
57258
|
+
return void 0;
|
|
57259
|
+
return {
|
|
57260
|
+
Name: cfg.Name ?? physicalId,
|
|
57261
|
+
EncryptionConfiguration: mapEncryptionConfigurationToCfn(cfg.EncryptionConfiguration)
|
|
57262
|
+
};
|
|
57263
|
+
}
|
|
57264
|
+
async import(input) {
|
|
57265
|
+
const explicitName = input.knownPhysicalId ?? input.properties["Name"];
|
|
57266
|
+
if (explicitName) {
|
|
57267
|
+
try {
|
|
57268
|
+
await this.getClient().send(new GetSecurityConfigurationCommand({ Name: explicitName }));
|
|
57269
|
+
return { physicalId: explicitName, attributes: {} };
|
|
57270
|
+
} catch (err) {
|
|
57271
|
+
if (err instanceof EntityNotFoundException)
|
|
57272
|
+
return null;
|
|
57273
|
+
throw err;
|
|
57274
|
+
}
|
|
57275
|
+
}
|
|
57276
|
+
if (!explicitName) {
|
|
57277
|
+
let nextToken;
|
|
57278
|
+
do {
|
|
57279
|
+
const list = await this.getClient().send(
|
|
57280
|
+
new GetSecurityConfigurationsCommand({ ...nextToken && { NextToken: nextToken } })
|
|
57281
|
+
);
|
|
57282
|
+
for (const _entry of list.SecurityConfigurations ?? []) {
|
|
57283
|
+
}
|
|
57284
|
+
nextToken = list.NextToken;
|
|
57285
|
+
} while (nextToken);
|
|
57286
|
+
return null;
|
|
57287
|
+
}
|
|
57288
|
+
return null;
|
|
57289
|
+
}
|
|
57290
|
+
};
|
|
57291
|
+
function workflowTagsForCreate(tags) {
|
|
57292
|
+
if (!Array.isArray(tags) || tags.length === 0)
|
|
57293
|
+
return void 0;
|
|
57294
|
+
const out = {};
|
|
57295
|
+
for (const t of tags) {
|
|
57296
|
+
const obj = t;
|
|
57297
|
+
const k = typeof obj["Key"] === "string" ? obj["Key"] : void 0;
|
|
57298
|
+
const v = typeof obj["Value"] === "string" ? obj["Value"] : "";
|
|
57299
|
+
if (!k)
|
|
57300
|
+
continue;
|
|
57301
|
+
out[k] = v;
|
|
57302
|
+
}
|
|
57303
|
+
return Object.keys(out).length > 0 ? out : void 0;
|
|
57304
|
+
}
|
|
57305
|
+
function buildEncryptionConfiguration(input) {
|
|
57306
|
+
const result = {};
|
|
57307
|
+
if (Array.isArray(input["S3Encryption"])) {
|
|
57308
|
+
result.S3Encryption = input["S3Encryption"].map((entry) => {
|
|
57309
|
+
const e = entry;
|
|
57310
|
+
const item = {};
|
|
57311
|
+
if (typeof e["S3EncryptionMode"] === "string") {
|
|
57312
|
+
item.S3EncryptionMode = e["S3EncryptionMode"];
|
|
57313
|
+
}
|
|
57314
|
+
if (typeof e["KmsKeyArn"] === "string") {
|
|
57315
|
+
item.KmsKeyArn = e["KmsKeyArn"];
|
|
57316
|
+
}
|
|
57317
|
+
return item;
|
|
57318
|
+
});
|
|
57319
|
+
}
|
|
57320
|
+
if (input["CloudWatchEncryption"] !== void 0) {
|
|
57321
|
+
const cw = input["CloudWatchEncryption"];
|
|
57322
|
+
const item = {};
|
|
57323
|
+
if (typeof cw["CloudWatchEncryptionMode"] === "string") {
|
|
57324
|
+
item.CloudWatchEncryptionMode = cw["CloudWatchEncryptionMode"];
|
|
57325
|
+
}
|
|
57326
|
+
if (typeof cw["KmsKeyArn"] === "string") {
|
|
57327
|
+
item.KmsKeyArn = cw["KmsKeyArn"];
|
|
57328
|
+
}
|
|
57329
|
+
result.CloudWatchEncryption = item;
|
|
57330
|
+
}
|
|
57331
|
+
if (input["JobBookmarksEncryption"] !== void 0) {
|
|
57332
|
+
const jb = input["JobBookmarksEncryption"];
|
|
57333
|
+
const item = {};
|
|
57334
|
+
if (typeof jb["JobBookmarksEncryptionMode"] === "string") {
|
|
57335
|
+
item.JobBookmarksEncryptionMode = jb["JobBookmarksEncryptionMode"];
|
|
57336
|
+
}
|
|
57337
|
+
if (typeof jb["KmsKeyArn"] === "string") {
|
|
57338
|
+
item.KmsKeyArn = jb["KmsKeyArn"];
|
|
57339
|
+
}
|
|
57340
|
+
result.JobBookmarksEncryption = item;
|
|
57341
|
+
}
|
|
57342
|
+
return result;
|
|
57343
|
+
}
|
|
57344
|
+
function mapEncryptionConfigurationToCfn(cfg) {
|
|
57345
|
+
const c = cfg ?? {};
|
|
57346
|
+
return {
|
|
57347
|
+
S3Encryption: (c.S3Encryption ?? []).map((entry) => {
|
|
57348
|
+
const out = {};
|
|
57349
|
+
if (entry.S3EncryptionMode !== void 0)
|
|
57350
|
+
out["S3EncryptionMode"] = entry.S3EncryptionMode;
|
|
57351
|
+
if (entry.KmsKeyArn !== void 0)
|
|
57352
|
+
out["KmsKeyArn"] = entry.KmsKeyArn;
|
|
57353
|
+
return out;
|
|
57354
|
+
}),
|
|
57355
|
+
CloudWatchEncryption: c.CloudWatchEncryption ? cleanCfnObject({
|
|
57356
|
+
CloudWatchEncryptionMode: c.CloudWatchEncryption.CloudWatchEncryptionMode,
|
|
57357
|
+
KmsKeyArn: c.CloudWatchEncryption.KmsKeyArn
|
|
57358
|
+
}) : {},
|
|
57359
|
+
JobBookmarksEncryption: c.JobBookmarksEncryption ? cleanCfnObject({
|
|
57360
|
+
JobBookmarksEncryptionMode: c.JobBookmarksEncryption.JobBookmarksEncryptionMode,
|
|
57361
|
+
KmsKeyArn: c.JobBookmarksEncryption.KmsKeyArn
|
|
57362
|
+
}) : {}
|
|
57363
|
+
};
|
|
57364
|
+
}
|
|
57365
|
+
function cleanCfnObject(obj) {
|
|
57366
|
+
const out = {};
|
|
57367
|
+
for (const [k, v] of Object.entries(obj)) {
|
|
57368
|
+
if (v !== void 0)
|
|
57369
|
+
out[k] = v;
|
|
57370
|
+
}
|
|
57371
|
+
return out;
|
|
57372
|
+
}
|
|
57373
|
+
async function buildGlueResourceArn(client, stsClient, resource, name, accountId) {
|
|
57374
|
+
const region = await client.config.region() || process.env["AWS_REGION"] || "us-east-1";
|
|
57375
|
+
const account = accountId ?? await resolveAccountId(stsClient);
|
|
57376
|
+
return `arn:aws:glue:${region}:${account}:${resource}/${name}`;
|
|
57377
|
+
}
|
|
57378
|
+
async function resolveAccountId(stsClient) {
|
|
57379
|
+
const identity = await stsClient.send(new GetCallerIdentityCommand8({}));
|
|
57380
|
+
if (!identity.Account) {
|
|
57381
|
+
throw new Error("Failed to resolve AWS account id from STS");
|
|
57382
|
+
}
|
|
57383
|
+
return identity.Account;
|
|
57384
|
+
}
|
|
57385
|
+
async function fetchGlueTags(client, stsClient, resource, name, accountId, logger) {
|
|
57386
|
+
try {
|
|
57387
|
+
const arn = await buildGlueResourceArn(client, stsClient, resource, name, accountId);
|
|
57388
|
+
const resp = await client.send(new GetTagsCommand({ ResourceArn: arn }));
|
|
57389
|
+
return normalizeAwsTagsToCfn(resp.Tags);
|
|
57390
|
+
} catch (err) {
|
|
57391
|
+
logger.debug(
|
|
57392
|
+
`GetTags failed for ${resource}/${name}: ${err instanceof Error ? err.message : String(err)}`
|
|
57393
|
+
);
|
|
57394
|
+
return [];
|
|
57395
|
+
}
|
|
57396
|
+
}
|
|
57397
|
+
var GlueJobProvider = class {
|
|
57398
|
+
client;
|
|
57399
|
+
stsClient;
|
|
57400
|
+
cachedAccountId;
|
|
57401
|
+
providerRegion = process.env["AWS_REGION"];
|
|
57402
|
+
logger = getLogger().child("GlueJobProvider");
|
|
57403
|
+
handledProperties = /* @__PURE__ */ new Map([
|
|
57404
|
+
[
|
|
57405
|
+
"AWS::Glue::Job",
|
|
57406
|
+
/* @__PURE__ */ new Set([
|
|
57407
|
+
"Name",
|
|
57408
|
+
"Role",
|
|
57409
|
+
"Command",
|
|
57410
|
+
"Description",
|
|
57411
|
+
"MaxCapacity",
|
|
57412
|
+
"MaxRetries",
|
|
57413
|
+
"Timeout",
|
|
57414
|
+
"ExecutionProperty",
|
|
57415
|
+
"GlueVersion",
|
|
57416
|
+
"NumberOfWorkers",
|
|
57417
|
+
"WorkerType",
|
|
57418
|
+
"DefaultArguments",
|
|
57419
|
+
"NonOverridableArguments",
|
|
57420
|
+
"Connections",
|
|
57421
|
+
"LogUri",
|
|
57422
|
+
"SecurityConfiguration",
|
|
57423
|
+
"NotificationProperty",
|
|
57424
|
+
"ExecutionClass",
|
|
57425
|
+
"JobMode",
|
|
57426
|
+
"JobRunQueuingEnabled",
|
|
57427
|
+
"MaintenanceWindow",
|
|
57428
|
+
"AllocatedCapacity",
|
|
57429
|
+
"SourceControlDetails",
|
|
57430
|
+
"Tags"
|
|
57431
|
+
])
|
|
57432
|
+
]
|
|
57433
|
+
]);
|
|
57434
|
+
getClient() {
|
|
57435
|
+
if (!this.client) {
|
|
57436
|
+
this.client = new GlueClient(this.providerRegion ? { region: this.providerRegion } : {});
|
|
57437
|
+
}
|
|
57438
|
+
return this.client;
|
|
57439
|
+
}
|
|
57440
|
+
getStsClient() {
|
|
57441
|
+
if (!this.stsClient) {
|
|
57442
|
+
this.stsClient = new STSClient8(this.providerRegion ? { region: this.providerRegion } : {});
|
|
57443
|
+
}
|
|
57444
|
+
return this.stsClient;
|
|
57445
|
+
}
|
|
57446
|
+
async create(logicalId, resourceType, properties) {
|
|
57447
|
+
this.logger.debug(`Creating Glue Job ${logicalId}`);
|
|
57448
|
+
const name = properties["Name"] ?? logicalId;
|
|
57449
|
+
const role = properties["Role"];
|
|
57450
|
+
const command = properties["Command"];
|
|
57451
|
+
if (!role) {
|
|
57452
|
+
throw new ProvisioningError(
|
|
57453
|
+
`Role is required for Glue Job ${logicalId}`,
|
|
57454
|
+
resourceType,
|
|
57455
|
+
logicalId
|
|
57456
|
+
);
|
|
57457
|
+
}
|
|
57458
|
+
if (!command) {
|
|
57459
|
+
throw new ProvisioningError(
|
|
57460
|
+
`Command is required for Glue Job ${logicalId}`,
|
|
57461
|
+
resourceType,
|
|
57462
|
+
logicalId
|
|
57463
|
+
);
|
|
57464
|
+
}
|
|
57465
|
+
try {
|
|
57466
|
+
const tags = cfnTagsToMap(properties["Tags"]);
|
|
57467
|
+
await this.getClient().send(
|
|
57468
|
+
new CreateJobCommand({
|
|
57469
|
+
Name: name,
|
|
57470
|
+
Role: role,
|
|
57471
|
+
Command: buildJobCommand(command),
|
|
57472
|
+
...buildJobCommonFields(properties),
|
|
57473
|
+
...tags && { Tags: tags }
|
|
57474
|
+
})
|
|
57475
|
+
);
|
|
57476
|
+
this.logger.debug(`Successfully created Glue Job ${logicalId}: ${name}`);
|
|
57477
|
+
return { physicalId: name, attributes: {} };
|
|
57478
|
+
} catch (error) {
|
|
57479
|
+
const cause = error instanceof Error ? error : void 0;
|
|
57480
|
+
throw new ProvisioningError(
|
|
57481
|
+
`Failed to create Glue Job ${logicalId}: ${error instanceof Error ? error.message : String(error)}`,
|
|
57482
|
+
resourceType,
|
|
57483
|
+
logicalId,
|
|
57484
|
+
void 0,
|
|
57485
|
+
cause
|
|
57486
|
+
);
|
|
57487
|
+
}
|
|
57488
|
+
}
|
|
57489
|
+
async update(logicalId, physicalId, resourceType, properties, previousProperties) {
|
|
57490
|
+
this.logger.debug(`Updating Glue Job ${logicalId}: ${physicalId}`);
|
|
57491
|
+
try {
|
|
57492
|
+
const command = properties["Command"];
|
|
57493
|
+
const update = {
|
|
57494
|
+
...command !== void 0 && { Command: buildJobCommand(command) },
|
|
57495
|
+
...buildJobCommonFields(properties),
|
|
57496
|
+
// Role is required at create but mutable on update; include only when defined
|
|
57497
|
+
...properties["Role"] !== void 0 && { Role: properties["Role"] }
|
|
57498
|
+
};
|
|
57499
|
+
await this.getClient().send(new UpdateJobCommand({ JobName: physicalId, JobUpdate: update }));
|
|
57500
|
+
const oldTags = cfnTagsToMap(previousProperties["Tags"]) ?? {};
|
|
57501
|
+
const newTags = cfnTagsToMap(properties["Tags"]) ?? {};
|
|
57502
|
+
await this.applyTagDiff(physicalId, oldTags, newTags);
|
|
57503
|
+
return { physicalId, wasReplaced: false };
|
|
57504
|
+
} catch (error) {
|
|
57505
|
+
const cause = error instanceof Error ? error : void 0;
|
|
57506
|
+
throw new ProvisioningError(
|
|
57507
|
+
`Failed to update Glue Job ${logicalId}: ${error instanceof Error ? error.message : String(error)}`,
|
|
57508
|
+
resourceType,
|
|
57509
|
+
logicalId,
|
|
57510
|
+
physicalId,
|
|
57511
|
+
cause
|
|
57512
|
+
);
|
|
57513
|
+
}
|
|
57514
|
+
}
|
|
57515
|
+
async delete(logicalId, physicalId, resourceType, _properties, context) {
|
|
57516
|
+
this.logger.debug(`Deleting Glue Job ${logicalId}: ${physicalId}`);
|
|
57517
|
+
try {
|
|
57518
|
+
await this.getClient().send(new DeleteJobCommand({ JobName: physicalId }));
|
|
57519
|
+
} catch (error) {
|
|
57520
|
+
if (error instanceof EntityNotFoundException) {
|
|
57521
|
+
const clientRegion = await this.getClient().config.region();
|
|
57522
|
+
assertRegionMatch(
|
|
57523
|
+
clientRegion,
|
|
57524
|
+
context?.expectedRegion,
|
|
57525
|
+
resourceType,
|
|
57526
|
+
logicalId,
|
|
57527
|
+
physicalId
|
|
57528
|
+
);
|
|
57529
|
+
this.logger.debug(`Glue Job ${physicalId} does not exist, skipping deletion`);
|
|
57530
|
+
return;
|
|
57531
|
+
}
|
|
57532
|
+
const cause = error instanceof Error ? error : void 0;
|
|
57533
|
+
throw new ProvisioningError(
|
|
57534
|
+
`Failed to delete Glue Job ${logicalId}: ${error instanceof Error ? error.message : String(error)}`,
|
|
57535
|
+
resourceType,
|
|
57536
|
+
logicalId,
|
|
57537
|
+
physicalId,
|
|
57538
|
+
cause
|
|
57539
|
+
);
|
|
57540
|
+
}
|
|
57541
|
+
}
|
|
57542
|
+
// eslint-disable-next-line @typescript-eslint/require-await -- explicit-override-only intentionally has no AWS calls
|
|
57543
|
+
async getAttribute(physicalId, _resourceType, attributeName) {
|
|
57544
|
+
if (attributeName === "Id" || attributeName === "Ref" || attributeName === "Name") {
|
|
57545
|
+
return physicalId;
|
|
57546
|
+
}
|
|
57547
|
+
return void 0;
|
|
57548
|
+
}
|
|
57549
|
+
/**
|
|
57550
|
+
* Read the AWS-current Glue Job in CFn-property shape.
|
|
57551
|
+
*
|
|
57552
|
+
* Always-emit placeholders for user-controllable top-level keys per
|
|
57553
|
+
* PR #145 (`?? '' | [] | {}`) so the v3 `observedProperties` baseline
|
|
57554
|
+
* detects console-side ADDs to fields that weren't templated. Tags
|
|
57555
|
+
* always emit `[]` (PR H pattern).
|
|
57556
|
+
*/
|
|
57557
|
+
async readCurrentState(physicalId, _logicalId, _resourceType) {
|
|
57558
|
+
let job;
|
|
57559
|
+
try {
|
|
57560
|
+
const resp = await this.getClient().send(new GetJobCommand({ JobName: physicalId }));
|
|
57561
|
+
job = resp.Job;
|
|
57562
|
+
} catch (err) {
|
|
57563
|
+
if (err instanceof EntityNotFoundException)
|
|
57564
|
+
return void 0;
|
|
57565
|
+
throw err;
|
|
57566
|
+
}
|
|
57567
|
+
if (!job)
|
|
57568
|
+
return void 0;
|
|
57569
|
+
const result = {
|
|
57570
|
+
Name: job.Name ?? physicalId,
|
|
57571
|
+
Role: job.Role ?? "",
|
|
57572
|
+
Command: pickDefined({
|
|
57573
|
+
Name: job.Command?.Name,
|
|
57574
|
+
ScriptLocation: job.Command?.ScriptLocation,
|
|
57575
|
+
PythonVersion: job.Command?.PythonVersion,
|
|
57576
|
+
Runtime: job.Command?.Runtime
|
|
57577
|
+
}),
|
|
57578
|
+
Description: job.Description ?? "",
|
|
57579
|
+
LogUri: job.LogUri ?? "",
|
|
57580
|
+
DefaultArguments: job.DefaultArguments ?? {},
|
|
57581
|
+
NonOverridableArguments: job.NonOverridableArguments ?? {},
|
|
57582
|
+
Connections: { Connections: job.Connections?.Connections ?? [] },
|
|
57583
|
+
MaxRetries: job.MaxRetries ?? 0,
|
|
57584
|
+
Timeout: job.Timeout ?? 0,
|
|
57585
|
+
ExecutionProperty: { MaxConcurrentRuns: job.ExecutionProperty?.MaxConcurrentRuns ?? 1 },
|
|
57586
|
+
NotificationProperty: { NotifyDelayAfter: job.NotificationProperty?.NotifyDelayAfter ?? 0 },
|
|
57587
|
+
GlueVersion: job.GlueVersion ?? "",
|
|
57588
|
+
NumberOfWorkers: job.NumberOfWorkers ?? 0,
|
|
57589
|
+
WorkerType: job.WorkerType ?? "",
|
|
57590
|
+
MaxCapacity: job.MaxCapacity ?? 0,
|
|
57591
|
+
AllocatedCapacity: job.AllocatedCapacity ?? 0,
|
|
57592
|
+
SecurityConfiguration: job.SecurityConfiguration ?? "",
|
|
57593
|
+
ExecutionClass: job.ExecutionClass ?? "",
|
|
57594
|
+
JobMode: job.JobMode ?? "",
|
|
57595
|
+
JobRunQueuingEnabled: job.JobRunQueuingEnabled ?? false,
|
|
57596
|
+
MaintenanceWindow: job.MaintenanceWindow ?? "",
|
|
57597
|
+
SourceControlDetails: job.SourceControlDetails ? pickDefined(job.SourceControlDetails) : {}
|
|
57598
|
+
};
|
|
57599
|
+
result["Tags"] = await fetchGlueTags(
|
|
57600
|
+
this.getClient(),
|
|
57601
|
+
this.getStsClient(),
|
|
57602
|
+
"job",
|
|
57603
|
+
job.Name ?? physicalId,
|
|
57604
|
+
this.cachedAccountId,
|
|
57605
|
+
this.logger
|
|
57606
|
+
);
|
|
57607
|
+
return result;
|
|
57608
|
+
}
|
|
57609
|
+
async applyTagDiff(physicalId, oldTags, newTags) {
|
|
57610
|
+
const arn = await buildGlueResourceArn(
|
|
57611
|
+
this.getClient(),
|
|
57612
|
+
this.getStsClient(),
|
|
57613
|
+
"job",
|
|
57614
|
+
physicalId,
|
|
57615
|
+
this.cachedAccountId
|
|
57616
|
+
);
|
|
57617
|
+
const toAdd = {};
|
|
57618
|
+
const toRemove = [];
|
|
57619
|
+
for (const [k, v] of Object.entries(newTags)) {
|
|
57620
|
+
if (oldTags[k] !== v)
|
|
57621
|
+
toAdd[k] = v;
|
|
57622
|
+
}
|
|
57623
|
+
for (const k of Object.keys(oldTags)) {
|
|
57624
|
+
if (!(k in newTags))
|
|
57625
|
+
toRemove.push(k);
|
|
57626
|
+
}
|
|
57627
|
+
if (Object.keys(toAdd).length > 0 || toRemove.length > 0) {
|
|
57628
|
+
const { TagResourceCommand: TagResourceCommand17, UntagResourceCommand: UntagResourceCommand16 } = await import("@aws-sdk/client-glue");
|
|
57629
|
+
if (Object.keys(toAdd).length > 0) {
|
|
57630
|
+
await this.getClient().send(new TagResourceCommand17({ ResourceArn: arn, TagsToAdd: toAdd }));
|
|
57631
|
+
}
|
|
57632
|
+
if (toRemove.length > 0) {
|
|
57633
|
+
await this.getClient().send(
|
|
57634
|
+
new UntagResourceCommand16({ ResourceArn: arn, TagsToRemove: toRemove })
|
|
57635
|
+
);
|
|
57636
|
+
}
|
|
57637
|
+
}
|
|
57638
|
+
}
|
|
57639
|
+
async import(input) {
|
|
57640
|
+
const explicitName = input.knownPhysicalId ?? input.properties["Name"];
|
|
57641
|
+
if (!explicitName)
|
|
57642
|
+
return null;
|
|
57643
|
+
try {
|
|
57644
|
+
await this.getClient().send(new GetJobCommand({ JobName: explicitName }));
|
|
57645
|
+
return { physicalId: explicitName, attributes: {} };
|
|
57646
|
+
} catch (err) {
|
|
57647
|
+
if (err instanceof EntityNotFoundException)
|
|
57648
|
+
return null;
|
|
57649
|
+
throw err;
|
|
57650
|
+
}
|
|
57651
|
+
}
|
|
57652
|
+
};
|
|
57653
|
+
function buildJobCommand(c) {
|
|
57654
|
+
const result = {};
|
|
57655
|
+
if (c["Name"] !== void 0)
|
|
57656
|
+
result.Name = c["Name"];
|
|
57657
|
+
if (c["ScriptLocation"] !== void 0)
|
|
57658
|
+
result.ScriptLocation = c["ScriptLocation"];
|
|
57659
|
+
if (c["PythonVersion"] !== void 0)
|
|
57660
|
+
result.PythonVersion = c["PythonVersion"];
|
|
57661
|
+
if (c["Runtime"] !== void 0)
|
|
57662
|
+
result.Runtime = c["Runtime"];
|
|
57663
|
+
return result;
|
|
57664
|
+
}
|
|
57665
|
+
function buildJobCommonFields(p) {
|
|
57666
|
+
const r = {};
|
|
57667
|
+
const passThrough = [
|
|
57668
|
+
"JobMode",
|
|
57669
|
+
"JobRunQueuingEnabled",
|
|
57670
|
+
"Description",
|
|
57671
|
+
"LogUri",
|
|
57672
|
+
"DefaultArguments",
|
|
57673
|
+
"NonOverridableArguments",
|
|
57674
|
+
"MaxRetries",
|
|
57675
|
+
"AllocatedCapacity",
|
|
57676
|
+
"Timeout",
|
|
57677
|
+
"MaxCapacity",
|
|
57678
|
+
"WorkerType",
|
|
57679
|
+
"NumberOfWorkers",
|
|
57680
|
+
"SecurityConfiguration",
|
|
57681
|
+
"GlueVersion",
|
|
57682
|
+
"ExecutionClass",
|
|
57683
|
+
"MaintenanceWindow"
|
|
57684
|
+
];
|
|
57685
|
+
for (const k of passThrough) {
|
|
57686
|
+
if (p[k] !== void 0) {
|
|
57687
|
+
r[k] = p[k];
|
|
57688
|
+
}
|
|
57689
|
+
}
|
|
57690
|
+
if (p["ExecutionProperty"] !== void 0) {
|
|
57691
|
+
r.ExecutionProperty = p["ExecutionProperty"];
|
|
57692
|
+
}
|
|
57693
|
+
if (p["Connections"] !== void 0) {
|
|
57694
|
+
const conn = p["Connections"];
|
|
57695
|
+
r.Connections = { Connections: conn["Connections"] ?? [] };
|
|
57696
|
+
}
|
|
57697
|
+
if (p["NotificationProperty"] !== void 0) {
|
|
57698
|
+
r.NotificationProperty = p["NotificationProperty"];
|
|
57699
|
+
}
|
|
57700
|
+
if (p["SourceControlDetails"] !== void 0) {
|
|
57701
|
+
r.SourceControlDetails = p["SourceControlDetails"];
|
|
57702
|
+
}
|
|
57703
|
+
return r;
|
|
57704
|
+
}
|
|
57705
|
+
function cfnTagsToMap(tagsInput) {
|
|
57706
|
+
if (tagsInput === void 0)
|
|
57707
|
+
return void 0;
|
|
57708
|
+
const out = {};
|
|
57709
|
+
if (Array.isArray(tagsInput)) {
|
|
57710
|
+
for (const entry of tagsInput) {
|
|
57711
|
+
const e = entry;
|
|
57712
|
+
const k = e["Key"];
|
|
57713
|
+
const v = e["Value"];
|
|
57714
|
+
if (typeof k === "string")
|
|
57715
|
+
out[k] = typeof v === "string" ? v : "";
|
|
57716
|
+
}
|
|
57717
|
+
return out;
|
|
57718
|
+
}
|
|
57719
|
+
if (typeof tagsInput === "object" && tagsInput !== null) {
|
|
57720
|
+
for (const [k, v] of Object.entries(tagsInput)) {
|
|
57721
|
+
out[k] = typeof v === "string" ? v : "";
|
|
57722
|
+
}
|
|
57723
|
+
return out;
|
|
57724
|
+
}
|
|
57725
|
+
return out;
|
|
57726
|
+
}
|
|
57727
|
+
function pickDefined(obj) {
|
|
57728
|
+
const out = {};
|
|
57729
|
+
for (const [k, v] of Object.entries(obj)) {
|
|
57730
|
+
if (v === void 0 || v === null)
|
|
57731
|
+
continue;
|
|
57732
|
+
if (typeof v === "object" && !Array.isArray(v)) {
|
|
57733
|
+
const inner = pickDefined(v);
|
|
57734
|
+
out[k] = inner;
|
|
57735
|
+
} else {
|
|
57736
|
+
out[k] = v;
|
|
57737
|
+
}
|
|
57738
|
+
}
|
|
57739
|
+
return out;
|
|
57740
|
+
}
|
|
57741
|
+
var GlueCrawlerProvider = class {
|
|
57742
|
+
client;
|
|
57743
|
+
stsClient;
|
|
57744
|
+
cachedAccountId;
|
|
57745
|
+
providerRegion = process.env["AWS_REGION"];
|
|
57746
|
+
logger = getLogger().child("GlueCrawlerProvider");
|
|
57747
|
+
handledProperties = /* @__PURE__ */ new Map([
|
|
57748
|
+
[
|
|
57749
|
+
"AWS::Glue::Crawler",
|
|
57750
|
+
/* @__PURE__ */ new Set([
|
|
57751
|
+
"Name",
|
|
57752
|
+
"Role",
|
|
57753
|
+
"Targets",
|
|
57754
|
+
"DatabaseName",
|
|
57755
|
+
"Description",
|
|
57756
|
+
"Schedule",
|
|
57757
|
+
"Classifiers",
|
|
57758
|
+
"TablePrefix",
|
|
57759
|
+
"SchemaChangePolicy",
|
|
57760
|
+
"RecrawlPolicy",
|
|
57761
|
+
"LineageConfiguration",
|
|
57762
|
+
"LakeFormationConfiguration",
|
|
57763
|
+
"Configuration",
|
|
57764
|
+
"CrawlerSecurityConfiguration",
|
|
57765
|
+
"Tags"
|
|
57766
|
+
])
|
|
57767
|
+
]
|
|
57768
|
+
]);
|
|
57769
|
+
getClient() {
|
|
57770
|
+
if (!this.client) {
|
|
57771
|
+
this.client = new GlueClient(this.providerRegion ? { region: this.providerRegion } : {});
|
|
57772
|
+
}
|
|
57773
|
+
return this.client;
|
|
57774
|
+
}
|
|
57775
|
+
getStsClient() {
|
|
57776
|
+
if (!this.stsClient) {
|
|
57777
|
+
this.stsClient = new STSClient8(this.providerRegion ? { region: this.providerRegion } : {});
|
|
57778
|
+
}
|
|
57779
|
+
return this.stsClient;
|
|
57780
|
+
}
|
|
57781
|
+
async create(logicalId, resourceType, properties) {
|
|
57782
|
+
this.logger.debug(`Creating Glue Crawler ${logicalId}`);
|
|
57783
|
+
const name = properties["Name"] ?? logicalId;
|
|
57784
|
+
const role = properties["Role"];
|
|
57785
|
+
const targets = properties["Targets"];
|
|
57786
|
+
if (!role) {
|
|
57787
|
+
throw new ProvisioningError(
|
|
57788
|
+
`Role is required for Glue Crawler ${logicalId}`,
|
|
57789
|
+
resourceType,
|
|
57790
|
+
logicalId
|
|
57791
|
+
);
|
|
57792
|
+
}
|
|
57793
|
+
if (!targets) {
|
|
57794
|
+
throw new ProvisioningError(
|
|
57795
|
+
`Targets is required for Glue Crawler ${logicalId}`,
|
|
57796
|
+
resourceType,
|
|
57797
|
+
logicalId
|
|
57798
|
+
);
|
|
57799
|
+
}
|
|
57800
|
+
try {
|
|
57801
|
+
const tags = cfnTagsToMap(properties["Tags"]);
|
|
57802
|
+
await this.getClient().send(
|
|
57803
|
+
new CreateCrawlerCommand({
|
|
57804
|
+
Name: name,
|
|
57805
|
+
Role: role,
|
|
57806
|
+
Targets: targets,
|
|
57807
|
+
...buildCrawlerCommonFields(properties),
|
|
57808
|
+
...tags && { Tags: tags }
|
|
57809
|
+
})
|
|
57810
|
+
);
|
|
57811
|
+
this.logger.debug(`Successfully created Glue Crawler ${logicalId}: ${name}`);
|
|
57812
|
+
return { physicalId: name, attributes: {} };
|
|
57813
|
+
} catch (error) {
|
|
57814
|
+
const cause = error instanceof Error ? error : void 0;
|
|
57815
|
+
throw new ProvisioningError(
|
|
57816
|
+
`Failed to create Glue Crawler ${logicalId}: ${error instanceof Error ? error.message : String(error)}`,
|
|
57817
|
+
resourceType,
|
|
57818
|
+
logicalId,
|
|
57819
|
+
void 0,
|
|
57820
|
+
cause
|
|
57821
|
+
);
|
|
57822
|
+
}
|
|
57823
|
+
}
|
|
57824
|
+
async update(logicalId, physicalId, resourceType, properties, previousProperties) {
|
|
57825
|
+
this.logger.debug(`Updating Glue Crawler ${logicalId}: ${physicalId}`);
|
|
57826
|
+
try {
|
|
57827
|
+
await this.getClient().send(
|
|
57828
|
+
new UpdateCrawlerCommand({
|
|
57829
|
+
Name: physicalId,
|
|
57830
|
+
...properties["Role"] !== void 0 && { Role: properties["Role"] },
|
|
57831
|
+
...properties["Targets"] !== void 0 && {
|
|
57832
|
+
Targets: properties["Targets"]
|
|
57833
|
+
},
|
|
57834
|
+
...buildCrawlerCommonFields(properties)
|
|
57835
|
+
})
|
|
57836
|
+
);
|
|
57837
|
+
const oldTags = cfnTagsToMap(previousProperties["Tags"]) ?? {};
|
|
57838
|
+
const newTags = cfnTagsToMap(properties["Tags"]) ?? {};
|
|
57839
|
+
await this.applyTagDiff(physicalId, oldTags, newTags);
|
|
57840
|
+
return { physicalId, wasReplaced: false };
|
|
57841
|
+
} catch (error) {
|
|
57842
|
+
const cause = error instanceof Error ? error : void 0;
|
|
57843
|
+
throw new ProvisioningError(
|
|
57844
|
+
`Failed to update Glue Crawler ${logicalId}: ${error instanceof Error ? error.message : String(error)}`,
|
|
57845
|
+
resourceType,
|
|
57846
|
+
logicalId,
|
|
57847
|
+
physicalId,
|
|
57848
|
+
cause
|
|
57849
|
+
);
|
|
57850
|
+
}
|
|
57851
|
+
}
|
|
57852
|
+
async delete(logicalId, physicalId, resourceType, _properties, context) {
|
|
57853
|
+
this.logger.debug(`Deleting Glue Crawler ${logicalId}: ${physicalId}`);
|
|
57854
|
+
try {
|
|
57855
|
+
await this.getClient().send(new DeleteCrawlerCommand({ Name: physicalId }));
|
|
57856
|
+
} catch (error) {
|
|
57857
|
+
if (error instanceof EntityNotFoundException) {
|
|
57858
|
+
const clientRegion = await this.getClient().config.region();
|
|
57859
|
+
assertRegionMatch(
|
|
57860
|
+
clientRegion,
|
|
57861
|
+
context?.expectedRegion,
|
|
57862
|
+
resourceType,
|
|
57863
|
+
logicalId,
|
|
57864
|
+
physicalId
|
|
57865
|
+
);
|
|
57866
|
+
this.logger.debug(`Glue Crawler ${physicalId} does not exist, skipping deletion`);
|
|
57867
|
+
return;
|
|
57868
|
+
}
|
|
57869
|
+
const cause = error instanceof Error ? error : void 0;
|
|
57870
|
+
throw new ProvisioningError(
|
|
57871
|
+
`Failed to delete Glue Crawler ${logicalId}: ${error instanceof Error ? error.message : String(error)}`,
|
|
57872
|
+
resourceType,
|
|
57873
|
+
logicalId,
|
|
57874
|
+
physicalId,
|
|
57875
|
+
cause
|
|
57876
|
+
);
|
|
57877
|
+
}
|
|
57878
|
+
}
|
|
57879
|
+
// eslint-disable-next-line @typescript-eslint/require-await -- explicit-override-only intentionally has no AWS calls
|
|
57880
|
+
async getAttribute(physicalId, _resourceType, attributeName) {
|
|
57881
|
+
if (attributeName === "Id" || attributeName === "Ref" || attributeName === "Name") {
|
|
57882
|
+
return physicalId;
|
|
57883
|
+
}
|
|
57884
|
+
return void 0;
|
|
57885
|
+
}
|
|
57886
|
+
async readCurrentState(physicalId, _logicalId, _resourceType) {
|
|
57887
|
+
let crawler;
|
|
57888
|
+
try {
|
|
57889
|
+
const resp = await this.getClient().send(new GetCrawlerCommand({ Name: physicalId }));
|
|
57890
|
+
crawler = resp.Crawler;
|
|
57891
|
+
} catch (err) {
|
|
57892
|
+
if (err instanceof EntityNotFoundException)
|
|
57893
|
+
return void 0;
|
|
57894
|
+
throw err;
|
|
57895
|
+
}
|
|
57896
|
+
if (!crawler)
|
|
57897
|
+
return void 0;
|
|
57898
|
+
const result = {
|
|
57899
|
+
Name: crawler.Name ?? physicalId,
|
|
57900
|
+
Role: crawler.Role ?? "",
|
|
57901
|
+
Targets: crawler.Targets ? pickDefined(crawler.Targets) : {},
|
|
57902
|
+
DatabaseName: crawler.DatabaseName ?? "",
|
|
57903
|
+
Description: crawler.Description ?? "",
|
|
57904
|
+
// CFn `Schedule` is the structured wrapper; reverse-map from the
|
|
57905
|
+
// SDK's `Schedule { ScheduleExpression, State }` Description shape.
|
|
57906
|
+
Schedule: crawler.Schedule?.ScheduleExpression ? { ScheduleExpression: crawler.Schedule.ScheduleExpression } : {},
|
|
57907
|
+
Classifiers: crawler.Classifiers ?? [],
|
|
57908
|
+
TablePrefix: crawler.TablePrefix ?? "",
|
|
57909
|
+
SchemaChangePolicy: crawler.SchemaChangePolicy ? pickDefined(crawler.SchemaChangePolicy) : {},
|
|
57910
|
+
RecrawlPolicy: crawler.RecrawlPolicy ? pickDefined(crawler.RecrawlPolicy) : {},
|
|
57911
|
+
LineageConfiguration: crawler.LineageConfiguration ? pickDefined(crawler.LineageConfiguration) : {},
|
|
57912
|
+
LakeFormationConfiguration: crawler.LakeFormationConfiguration ? pickDefined(crawler.LakeFormationConfiguration) : {},
|
|
57913
|
+
Configuration: crawler.Configuration ?? "",
|
|
57914
|
+
CrawlerSecurityConfiguration: crawler.CrawlerSecurityConfiguration ?? ""
|
|
57915
|
+
};
|
|
57916
|
+
result["Tags"] = await fetchGlueTags(
|
|
57917
|
+
this.getClient(),
|
|
57918
|
+
this.getStsClient(),
|
|
57919
|
+
"crawler",
|
|
57920
|
+
crawler.Name ?? physicalId,
|
|
57921
|
+
this.cachedAccountId,
|
|
57922
|
+
this.logger
|
|
57923
|
+
);
|
|
57924
|
+
return result;
|
|
57925
|
+
}
|
|
57926
|
+
/**
|
|
57927
|
+
* Start (or stop) a crawler's schedule. Exposed for downstream tooling
|
|
57928
|
+
* — not part of `update()` because AWS treats schedule activation as a
|
|
57929
|
+
* separate side-effect from crawler config update.
|
|
57930
|
+
*/
|
|
57931
|
+
async startSchedule(physicalId) {
|
|
57932
|
+
await this.getClient().send(new StartCrawlerScheduleCommand({ CrawlerName: physicalId }));
|
|
57933
|
+
}
|
|
57934
|
+
async stopSchedule(physicalId) {
|
|
57935
|
+
await this.getClient().send(new StopCrawlerScheduleCommand({ CrawlerName: physicalId }));
|
|
57936
|
+
}
|
|
57937
|
+
async applyTagDiff(physicalId, oldTags, newTags) {
|
|
57938
|
+
const arn = await buildGlueResourceArn(
|
|
57939
|
+
this.getClient(),
|
|
57940
|
+
this.getStsClient(),
|
|
57941
|
+
"crawler",
|
|
57942
|
+
physicalId,
|
|
57943
|
+
this.cachedAccountId
|
|
57944
|
+
);
|
|
57945
|
+
const toAdd = {};
|
|
57946
|
+
const toRemove = [];
|
|
57947
|
+
for (const [k, v] of Object.entries(newTags)) {
|
|
57948
|
+
if (oldTags[k] !== v)
|
|
57949
|
+
toAdd[k] = v;
|
|
57950
|
+
}
|
|
57951
|
+
for (const k of Object.keys(oldTags)) {
|
|
57952
|
+
if (!(k in newTags))
|
|
57953
|
+
toRemove.push(k);
|
|
57954
|
+
}
|
|
57955
|
+
if (Object.keys(toAdd).length > 0 || toRemove.length > 0) {
|
|
57956
|
+
const { TagResourceCommand: TagResourceCommand17, UntagResourceCommand: UntagResourceCommand16 } = await import("@aws-sdk/client-glue");
|
|
57957
|
+
if (Object.keys(toAdd).length > 0) {
|
|
57958
|
+
await this.getClient().send(new TagResourceCommand17({ ResourceArn: arn, TagsToAdd: toAdd }));
|
|
57959
|
+
}
|
|
57960
|
+
if (toRemove.length > 0) {
|
|
57961
|
+
await this.getClient().send(
|
|
57962
|
+
new UntagResourceCommand16({ ResourceArn: arn, TagsToRemove: toRemove })
|
|
57963
|
+
);
|
|
57964
|
+
}
|
|
57965
|
+
}
|
|
57966
|
+
}
|
|
57967
|
+
async import(input) {
|
|
57968
|
+
const explicitName = input.knownPhysicalId ?? input.properties["Name"];
|
|
57969
|
+
if (!explicitName)
|
|
57970
|
+
return null;
|
|
57971
|
+
try {
|
|
57972
|
+
await this.getClient().send(new GetCrawlerCommand({ Name: explicitName }));
|
|
57973
|
+
return { physicalId: explicitName, attributes: {} };
|
|
57974
|
+
} catch (err) {
|
|
57975
|
+
if (err instanceof EntityNotFoundException)
|
|
57976
|
+
return null;
|
|
57977
|
+
throw err;
|
|
57978
|
+
}
|
|
57979
|
+
}
|
|
57980
|
+
};
|
|
57981
|
+
function buildCrawlerCommonFields(p) {
|
|
57982
|
+
const r = {};
|
|
57983
|
+
if (p["DatabaseName"] !== void 0)
|
|
57984
|
+
r["DatabaseName"] = p["DatabaseName"];
|
|
57985
|
+
if (p["Description"] !== void 0)
|
|
57986
|
+
r["Description"] = p["Description"];
|
|
57987
|
+
if (p["Classifiers"] !== void 0)
|
|
57988
|
+
r["Classifiers"] = p["Classifiers"];
|
|
57989
|
+
if (p["TablePrefix"] !== void 0)
|
|
57990
|
+
r["TablePrefix"] = p["TablePrefix"];
|
|
57991
|
+
if (p["Schedule"] !== void 0) {
|
|
57992
|
+
const sched = p["Schedule"];
|
|
57993
|
+
if (typeof sched === "string") {
|
|
57994
|
+
r["Schedule"] = sched;
|
|
57995
|
+
} else if (typeof sched === "object" && sched !== null) {
|
|
57996
|
+
const wrap = sched;
|
|
57997
|
+
if (wrap["ScheduleExpression"] !== void 0) {
|
|
57998
|
+
r["Schedule"] = wrap["ScheduleExpression"];
|
|
57999
|
+
}
|
|
58000
|
+
}
|
|
58001
|
+
}
|
|
58002
|
+
if (p["SchemaChangePolicy"] !== void 0) {
|
|
58003
|
+
r["SchemaChangePolicy"] = p["SchemaChangePolicy"];
|
|
58004
|
+
}
|
|
58005
|
+
if (p["RecrawlPolicy"] !== void 0) {
|
|
58006
|
+
r["RecrawlPolicy"] = p["RecrawlPolicy"];
|
|
58007
|
+
}
|
|
58008
|
+
if (p["LineageConfiguration"] !== void 0) {
|
|
58009
|
+
r["LineageConfiguration"] = p["LineageConfiguration"];
|
|
58010
|
+
}
|
|
58011
|
+
if (p["LakeFormationConfiguration"] !== void 0) {
|
|
58012
|
+
r["LakeFormationConfiguration"] = p["LakeFormationConfiguration"];
|
|
58013
|
+
}
|
|
58014
|
+
if (p["Configuration"] !== void 0)
|
|
58015
|
+
r["Configuration"] = p["Configuration"];
|
|
58016
|
+
if (p["CrawlerSecurityConfiguration"] !== void 0) {
|
|
58017
|
+
r["CrawlerSecurityConfiguration"] = p["CrawlerSecurityConfiguration"];
|
|
58018
|
+
}
|
|
58019
|
+
return r;
|
|
58020
|
+
}
|
|
58021
|
+
var GlueConnectionProvider = class {
|
|
58022
|
+
client;
|
|
58023
|
+
providerRegion = process.env["AWS_REGION"];
|
|
58024
|
+
logger = getLogger().child("GlueConnectionProvider");
|
|
58025
|
+
handledProperties = /* @__PURE__ */ new Map([
|
|
58026
|
+
["AWS::Glue::Connection", /* @__PURE__ */ new Set(["ConnectionInput", "CatalogId"])]
|
|
58027
|
+
]);
|
|
58028
|
+
getClient() {
|
|
58029
|
+
if (!this.client) {
|
|
58030
|
+
this.client = new GlueClient(this.providerRegion ? { region: this.providerRegion } : {});
|
|
58031
|
+
}
|
|
58032
|
+
return this.client;
|
|
58033
|
+
}
|
|
58034
|
+
async create(logicalId, resourceType, properties) {
|
|
58035
|
+
this.logger.debug(`Creating Glue Connection ${logicalId}`);
|
|
58036
|
+
const connectionInput = properties["ConnectionInput"];
|
|
58037
|
+
if (!connectionInput) {
|
|
58038
|
+
throw new ProvisioningError(
|
|
58039
|
+
`ConnectionInput is required for Glue Connection ${logicalId}`,
|
|
58040
|
+
resourceType,
|
|
58041
|
+
logicalId
|
|
58042
|
+
);
|
|
58043
|
+
}
|
|
58044
|
+
const name = connectionInput["Name"] ?? logicalId;
|
|
58045
|
+
const catalogId = properties["CatalogId"];
|
|
58046
|
+
try {
|
|
58047
|
+
await this.getClient().send(
|
|
58048
|
+
new CreateConnectionCommand({
|
|
58049
|
+
...catalogId && { CatalogId: catalogId },
|
|
58050
|
+
ConnectionInput: buildConnectionInput(connectionInput, name)
|
|
58051
|
+
})
|
|
58052
|
+
);
|
|
58053
|
+
this.logger.debug(`Successfully created Glue Connection ${logicalId}: ${name}`);
|
|
58054
|
+
return { physicalId: name, attributes: {} };
|
|
58055
|
+
} catch (error) {
|
|
58056
|
+
const cause = error instanceof Error ? error : void 0;
|
|
58057
|
+
throw new ProvisioningError(
|
|
58058
|
+
`Failed to create Glue Connection ${logicalId}: ${error instanceof Error ? error.message : String(error)}`,
|
|
58059
|
+
resourceType,
|
|
58060
|
+
logicalId,
|
|
58061
|
+
void 0,
|
|
58062
|
+
cause
|
|
58063
|
+
);
|
|
58064
|
+
}
|
|
58065
|
+
}
|
|
58066
|
+
async update(logicalId, physicalId, resourceType, properties, _previousProperties) {
|
|
58067
|
+
this.logger.debug(`Updating Glue Connection ${logicalId}: ${physicalId}`);
|
|
58068
|
+
const connectionInput = properties["ConnectionInput"];
|
|
58069
|
+
if (!connectionInput) {
|
|
58070
|
+
throw new ProvisioningError(
|
|
58071
|
+
`ConnectionInput is required for Glue Connection update ${logicalId}`,
|
|
58072
|
+
resourceType,
|
|
58073
|
+
logicalId,
|
|
58074
|
+
physicalId
|
|
58075
|
+
);
|
|
58076
|
+
}
|
|
58077
|
+
const catalogId = properties["CatalogId"];
|
|
58078
|
+
try {
|
|
58079
|
+
await this.getClient().send(
|
|
58080
|
+
new UpdateConnectionCommand({
|
|
58081
|
+
...catalogId && { CatalogId: catalogId },
|
|
58082
|
+
Name: physicalId,
|
|
58083
|
+
ConnectionInput: buildConnectionInput(connectionInput, physicalId)
|
|
58084
|
+
})
|
|
58085
|
+
);
|
|
58086
|
+
return { physicalId, wasReplaced: false };
|
|
58087
|
+
} catch (error) {
|
|
58088
|
+
const cause = error instanceof Error ? error : void 0;
|
|
58089
|
+
throw new ProvisioningError(
|
|
58090
|
+
`Failed to update Glue Connection ${logicalId}: ${error instanceof Error ? error.message : String(error)}`,
|
|
58091
|
+
resourceType,
|
|
58092
|
+
logicalId,
|
|
58093
|
+
physicalId,
|
|
58094
|
+
cause
|
|
58095
|
+
);
|
|
58096
|
+
}
|
|
58097
|
+
}
|
|
58098
|
+
async delete(logicalId, physicalId, resourceType, properties, context) {
|
|
58099
|
+
this.logger.debug(`Deleting Glue Connection ${logicalId}: ${physicalId}`);
|
|
58100
|
+
const catalogId = properties?.["CatalogId"];
|
|
58101
|
+
try {
|
|
58102
|
+
await this.getClient().send(
|
|
58103
|
+
new DeleteConnectionCommand({
|
|
58104
|
+
ConnectionName: physicalId,
|
|
58105
|
+
...catalogId && { CatalogId: catalogId }
|
|
58106
|
+
})
|
|
58107
|
+
);
|
|
58108
|
+
} catch (error) {
|
|
58109
|
+
if (error instanceof EntityNotFoundException) {
|
|
58110
|
+
const clientRegion = await this.getClient().config.region();
|
|
58111
|
+
assertRegionMatch(
|
|
58112
|
+
clientRegion,
|
|
58113
|
+
context?.expectedRegion,
|
|
58114
|
+
resourceType,
|
|
58115
|
+
logicalId,
|
|
58116
|
+
physicalId
|
|
58117
|
+
);
|
|
58118
|
+
this.logger.debug(`Glue Connection ${physicalId} does not exist, skipping deletion`);
|
|
58119
|
+
return;
|
|
58120
|
+
}
|
|
58121
|
+
const cause = error instanceof Error ? error : void 0;
|
|
58122
|
+
throw new ProvisioningError(
|
|
58123
|
+
`Failed to delete Glue Connection ${logicalId}: ${error instanceof Error ? error.message : String(error)}`,
|
|
58124
|
+
resourceType,
|
|
58125
|
+
logicalId,
|
|
58126
|
+
physicalId,
|
|
58127
|
+
cause
|
|
58128
|
+
);
|
|
58129
|
+
}
|
|
58130
|
+
}
|
|
58131
|
+
// eslint-disable-next-line @typescript-eslint/require-await -- explicit-override-only intentionally has no AWS calls
|
|
58132
|
+
async getAttribute(physicalId, _resourceType, attributeName) {
|
|
58133
|
+
if (attributeName === "Id" || attributeName === "Ref" || attributeName === "Name") {
|
|
58134
|
+
return physicalId;
|
|
58135
|
+
}
|
|
58136
|
+
return void 0;
|
|
58137
|
+
}
|
|
58138
|
+
async readCurrentState(physicalId, _logicalId, _resourceType, properties) {
|
|
58139
|
+
const catalogId = properties?.["CatalogId"];
|
|
58140
|
+
let conn;
|
|
58141
|
+
try {
|
|
58142
|
+
const resp = await this.getClient().send(
|
|
58143
|
+
new GetConnectionCommand({ Name: physicalId, ...catalogId && { CatalogId: catalogId } })
|
|
58144
|
+
);
|
|
58145
|
+
conn = resp.Connection;
|
|
58146
|
+
} catch (err) {
|
|
58147
|
+
if (err instanceof EntityNotFoundException)
|
|
58148
|
+
return void 0;
|
|
58149
|
+
throw err;
|
|
58150
|
+
}
|
|
58151
|
+
if (!conn)
|
|
58152
|
+
return void 0;
|
|
58153
|
+
const ci = {
|
|
58154
|
+
Name: conn.Name ?? physicalId,
|
|
58155
|
+
ConnectionType: conn.ConnectionType ?? "",
|
|
58156
|
+
Description: conn.Description ?? "",
|
|
58157
|
+
MatchCriteria: conn.MatchCriteria ?? [],
|
|
58158
|
+
ConnectionProperties: conn.ConnectionProperties ?? {},
|
|
58159
|
+
SparkProperties: conn.SparkProperties ?? {},
|
|
58160
|
+
AthenaProperties: conn.AthenaProperties ?? {},
|
|
58161
|
+
PythonProperties: conn.PythonProperties ?? {},
|
|
58162
|
+
PhysicalConnectionRequirements: conn.PhysicalConnectionRequirements ? pickDefined(conn.PhysicalConnectionRequirements) : {}
|
|
58163
|
+
};
|
|
58164
|
+
return { ConnectionInput: ci };
|
|
58165
|
+
}
|
|
58166
|
+
async import(input) {
|
|
58167
|
+
const explicitName = input.knownPhysicalId ?? input.properties["ConnectionInput"]?.["Name"];
|
|
58168
|
+
if (!explicitName)
|
|
58169
|
+
return null;
|
|
58170
|
+
const catalogId = input.properties["CatalogId"];
|
|
58171
|
+
try {
|
|
58172
|
+
await this.getClient().send(
|
|
58173
|
+
new GetConnectionCommand({
|
|
58174
|
+
Name: explicitName,
|
|
58175
|
+
...catalogId && { CatalogId: catalogId }
|
|
58176
|
+
})
|
|
58177
|
+
);
|
|
58178
|
+
return { physicalId: explicitName, attributes: {} };
|
|
58179
|
+
} catch (err) {
|
|
58180
|
+
if (err instanceof EntityNotFoundException)
|
|
58181
|
+
return null;
|
|
58182
|
+
throw err;
|
|
58183
|
+
}
|
|
58184
|
+
}
|
|
58185
|
+
};
|
|
58186
|
+
function buildConnectionInput(ci, fallbackName) {
|
|
58187
|
+
const result = {
|
|
58188
|
+
Name: ci["Name"] ?? fallbackName,
|
|
58189
|
+
ConnectionType: ci["ConnectionType"],
|
|
58190
|
+
ConnectionProperties: ci["ConnectionProperties"] ?? {}
|
|
58191
|
+
};
|
|
58192
|
+
if (ci["Description"] !== void 0)
|
|
58193
|
+
result.Description = ci["Description"];
|
|
58194
|
+
if (ci["MatchCriteria"] !== void 0)
|
|
58195
|
+
result.MatchCriteria = ci["MatchCriteria"];
|
|
58196
|
+
if (ci["SparkProperties"] !== void 0) {
|
|
58197
|
+
result.SparkProperties = ci["SparkProperties"];
|
|
58198
|
+
}
|
|
58199
|
+
if (ci["AthenaProperties"] !== void 0) {
|
|
58200
|
+
result.AthenaProperties = ci["AthenaProperties"];
|
|
58201
|
+
}
|
|
58202
|
+
if (ci["PythonProperties"] !== void 0) {
|
|
58203
|
+
result.PythonProperties = ci["PythonProperties"];
|
|
58204
|
+
}
|
|
58205
|
+
if (ci["PhysicalConnectionRequirements"] !== void 0) {
|
|
58206
|
+
result.PhysicalConnectionRequirements = ci["PhysicalConnectionRequirements"];
|
|
58207
|
+
}
|
|
58208
|
+
if (ci["AuthenticationConfiguration"] !== void 0) {
|
|
58209
|
+
result.AuthenticationConfiguration = ci["AuthenticationConfiguration"];
|
|
58210
|
+
}
|
|
58211
|
+
if (ci["ValidateCredentials"] !== void 0) {
|
|
58212
|
+
result.ValidateCredentials = ci["ValidateCredentials"];
|
|
58213
|
+
}
|
|
58214
|
+
if (ci["ValidateForComputeEnvironments"] !== void 0) {
|
|
58215
|
+
result.ValidateForComputeEnvironments = ci["ValidateForComputeEnvironments"];
|
|
58216
|
+
}
|
|
58217
|
+
return result;
|
|
58218
|
+
}
|
|
58219
|
+
var GlueTriggerProvider = class {
|
|
58220
|
+
client;
|
|
58221
|
+
stsClient;
|
|
58222
|
+
cachedAccountId;
|
|
58223
|
+
providerRegion = process.env["AWS_REGION"];
|
|
58224
|
+
logger = getLogger().child("GlueTriggerProvider");
|
|
58225
|
+
handledProperties = /* @__PURE__ */ new Map([
|
|
58226
|
+
[
|
|
58227
|
+
"AWS::Glue::Trigger",
|
|
58228
|
+
/* @__PURE__ */ new Set([
|
|
58229
|
+
"Name",
|
|
58230
|
+
"Type",
|
|
58231
|
+
"Schedule",
|
|
58232
|
+
"Actions",
|
|
58233
|
+
"Predicate",
|
|
58234
|
+
"Description",
|
|
58235
|
+
"StartOnCreation",
|
|
58236
|
+
"EventBatchingCondition",
|
|
58237
|
+
"WorkflowName",
|
|
58238
|
+
"Tags"
|
|
58239
|
+
])
|
|
58240
|
+
]
|
|
58241
|
+
]);
|
|
58242
|
+
getClient() {
|
|
58243
|
+
if (!this.client) {
|
|
58244
|
+
this.client = new GlueClient(this.providerRegion ? { region: this.providerRegion } : {});
|
|
58245
|
+
}
|
|
58246
|
+
return this.client;
|
|
58247
|
+
}
|
|
58248
|
+
getStsClient() {
|
|
58249
|
+
if (!this.stsClient) {
|
|
58250
|
+
this.stsClient = new STSClient8(this.providerRegion ? { region: this.providerRegion } : {});
|
|
58251
|
+
}
|
|
58252
|
+
return this.stsClient;
|
|
58253
|
+
}
|
|
58254
|
+
async create(logicalId, resourceType, properties) {
|
|
58255
|
+
this.logger.debug(`Creating Glue Trigger ${logicalId}`);
|
|
58256
|
+
const name = properties["Name"] ?? logicalId;
|
|
58257
|
+
const type = properties["Type"];
|
|
58258
|
+
const actions = properties["Actions"];
|
|
58259
|
+
if (!type) {
|
|
58260
|
+
throw new ProvisioningError(
|
|
58261
|
+
`Type is required for Glue Trigger ${logicalId}`,
|
|
58262
|
+
resourceType,
|
|
58263
|
+
logicalId
|
|
58264
|
+
);
|
|
58265
|
+
}
|
|
58266
|
+
if (!actions) {
|
|
58267
|
+
throw new ProvisioningError(
|
|
58268
|
+
`Actions is required for Glue Trigger ${logicalId}`,
|
|
58269
|
+
resourceType,
|
|
58270
|
+
logicalId
|
|
58271
|
+
);
|
|
58272
|
+
}
|
|
58273
|
+
try {
|
|
58274
|
+
const tags = cfnTagsToMap(properties["Tags"]);
|
|
58275
|
+
await this.getClient().send(
|
|
58276
|
+
new CreateTriggerCommand({
|
|
58277
|
+
Name: name,
|
|
58278
|
+
Type: type,
|
|
58279
|
+
Actions: actions,
|
|
58280
|
+
...properties["Schedule"] !== void 0 && {
|
|
58281
|
+
Schedule: properties["Schedule"]
|
|
58282
|
+
},
|
|
58283
|
+
...properties["Predicate"] !== void 0 && {
|
|
58284
|
+
Predicate: properties["Predicate"]
|
|
58285
|
+
},
|
|
58286
|
+
...properties["Description"] !== void 0 && {
|
|
58287
|
+
Description: properties["Description"]
|
|
58288
|
+
},
|
|
58289
|
+
...properties["StartOnCreation"] !== void 0 && {
|
|
58290
|
+
StartOnCreation: properties["StartOnCreation"]
|
|
58291
|
+
},
|
|
58292
|
+
...properties["WorkflowName"] !== void 0 && {
|
|
58293
|
+
WorkflowName: properties["WorkflowName"]
|
|
58294
|
+
},
|
|
58295
|
+
...properties["EventBatchingCondition"] !== void 0 && {
|
|
58296
|
+
EventBatchingCondition: properties["EventBatchingCondition"]
|
|
58297
|
+
},
|
|
58298
|
+
...tags && { Tags: tags }
|
|
58299
|
+
})
|
|
58300
|
+
);
|
|
58301
|
+
this.logger.debug(`Successfully created Glue Trigger ${logicalId}: ${name}`);
|
|
58302
|
+
return { physicalId: name, attributes: {} };
|
|
58303
|
+
} catch (error) {
|
|
58304
|
+
const cause = error instanceof Error ? error : void 0;
|
|
58305
|
+
throw new ProvisioningError(
|
|
58306
|
+
`Failed to create Glue Trigger ${logicalId}: ${error instanceof Error ? error.message : String(error)}`,
|
|
58307
|
+
resourceType,
|
|
58308
|
+
logicalId,
|
|
58309
|
+
void 0,
|
|
58310
|
+
cause
|
|
58311
|
+
);
|
|
58312
|
+
}
|
|
58313
|
+
}
|
|
58314
|
+
async update(logicalId, physicalId, resourceType, properties, previousProperties) {
|
|
58315
|
+
this.logger.debug(`Updating Glue Trigger ${logicalId}: ${physicalId}`);
|
|
58316
|
+
try {
|
|
58317
|
+
let restart = false;
|
|
58318
|
+
try {
|
|
58319
|
+
const cur = await this.getClient().send(new GetTriggerCommand({ Name: physicalId }));
|
|
58320
|
+
if (cur.Trigger?.State === "ACTIVATED") {
|
|
58321
|
+
restart = true;
|
|
58322
|
+
await this.getClient().send(new StopTriggerCommand({ Name: physicalId }));
|
|
58323
|
+
}
|
|
58324
|
+
} catch (err) {
|
|
58325
|
+
if (!(err instanceof EntityNotFoundException)) {
|
|
58326
|
+
this.logger.debug(
|
|
58327
|
+
`GetTrigger pre-check failed for ${physicalId}; continuing anyway: ${err instanceof Error ? err.message : String(err)}`
|
|
58328
|
+
);
|
|
58329
|
+
}
|
|
58330
|
+
}
|
|
58331
|
+
const update = {
|
|
58332
|
+
...properties["Description"] !== void 0 && {
|
|
58333
|
+
Description: properties["Description"]
|
|
58334
|
+
},
|
|
58335
|
+
...properties["Schedule"] !== void 0 && {
|
|
58336
|
+
Schedule: properties["Schedule"]
|
|
58337
|
+
},
|
|
58338
|
+
...properties["Actions"] !== void 0 && {
|
|
58339
|
+
Actions: properties["Actions"]
|
|
58340
|
+
},
|
|
58341
|
+
...properties["Predicate"] !== void 0 && {
|
|
58342
|
+
Predicate: properties["Predicate"]
|
|
58343
|
+
},
|
|
58344
|
+
...properties["EventBatchingCondition"] !== void 0 && {
|
|
58345
|
+
EventBatchingCondition: properties["EventBatchingCondition"]
|
|
58346
|
+
}
|
|
58347
|
+
};
|
|
58348
|
+
await this.getClient().send(
|
|
58349
|
+
new UpdateTriggerCommand({ Name: physicalId, TriggerUpdate: update })
|
|
58350
|
+
);
|
|
58351
|
+
if (restart) {
|
|
58352
|
+
await this.getClient().send(new StartTriggerCommand({ Name: physicalId }));
|
|
58353
|
+
}
|
|
58354
|
+
const oldTags = cfnTagsToMap(previousProperties["Tags"]) ?? {};
|
|
58355
|
+
const newTags = cfnTagsToMap(properties["Tags"]) ?? {};
|
|
58356
|
+
await this.applyTagDiff(physicalId, oldTags, newTags);
|
|
58357
|
+
return { physicalId, wasReplaced: false };
|
|
58358
|
+
} catch (error) {
|
|
58359
|
+
const cause = error instanceof Error ? error : void 0;
|
|
58360
|
+
throw new ProvisioningError(
|
|
58361
|
+
`Failed to update Glue Trigger ${logicalId}: ${error instanceof Error ? error.message : String(error)}`,
|
|
58362
|
+
resourceType,
|
|
58363
|
+
logicalId,
|
|
58364
|
+
physicalId,
|
|
58365
|
+
cause
|
|
58366
|
+
);
|
|
58367
|
+
}
|
|
58368
|
+
}
|
|
58369
|
+
async delete(logicalId, physicalId, resourceType, _properties, context) {
|
|
58370
|
+
this.logger.debug(`Deleting Glue Trigger ${logicalId}: ${physicalId}`);
|
|
58371
|
+
try {
|
|
58372
|
+
await this.getClient().send(new DeleteTriggerCommand({ Name: physicalId }));
|
|
58373
|
+
} catch (error) {
|
|
58374
|
+
if (error instanceof EntityNotFoundException) {
|
|
58375
|
+
const clientRegion = await this.getClient().config.region();
|
|
58376
|
+
assertRegionMatch(
|
|
58377
|
+
clientRegion,
|
|
58378
|
+
context?.expectedRegion,
|
|
58379
|
+
resourceType,
|
|
58380
|
+
logicalId,
|
|
58381
|
+
physicalId
|
|
58382
|
+
);
|
|
58383
|
+
this.logger.debug(`Glue Trigger ${physicalId} does not exist, skipping deletion`);
|
|
58384
|
+
return;
|
|
58385
|
+
}
|
|
58386
|
+
const cause = error instanceof Error ? error : void 0;
|
|
58387
|
+
throw new ProvisioningError(
|
|
58388
|
+
`Failed to delete Glue Trigger ${logicalId}: ${error instanceof Error ? error.message : String(error)}`,
|
|
58389
|
+
resourceType,
|
|
58390
|
+
logicalId,
|
|
58391
|
+
physicalId,
|
|
58392
|
+
cause
|
|
58393
|
+
);
|
|
58394
|
+
}
|
|
58395
|
+
}
|
|
58396
|
+
// eslint-disable-next-line @typescript-eslint/require-await -- explicit-override-only intentionally has no AWS calls
|
|
58397
|
+
async getAttribute(physicalId, _resourceType, attributeName) {
|
|
58398
|
+
if (attributeName === "Id" || attributeName === "Ref" || attributeName === "Name") {
|
|
58399
|
+
return physicalId;
|
|
58400
|
+
}
|
|
58401
|
+
return void 0;
|
|
58402
|
+
}
|
|
58403
|
+
async readCurrentState(physicalId, _logicalId, _resourceType) {
|
|
58404
|
+
let trig;
|
|
58405
|
+
try {
|
|
58406
|
+
const resp = await this.getClient().send(new GetTriggerCommand({ Name: physicalId }));
|
|
58407
|
+
trig = resp.Trigger;
|
|
58408
|
+
} catch (err) {
|
|
58409
|
+
if (err instanceof EntityNotFoundException)
|
|
58410
|
+
return void 0;
|
|
58411
|
+
throw err;
|
|
58412
|
+
}
|
|
58413
|
+
if (!trig)
|
|
58414
|
+
return void 0;
|
|
58415
|
+
const result = {
|
|
58416
|
+
Name: trig.Name ?? physicalId,
|
|
58417
|
+
Type: trig.Type ?? "",
|
|
58418
|
+
Schedule: trig.Schedule ?? "",
|
|
58419
|
+
Description: trig.Description ?? "",
|
|
58420
|
+
WorkflowName: trig.WorkflowName ?? "",
|
|
58421
|
+
Actions: (trig.Actions ?? []).map(
|
|
58422
|
+
(a) => pickDefined(a)
|
|
58423
|
+
),
|
|
58424
|
+
Predicate: trig.Predicate ? {
|
|
58425
|
+
Logical: trig.Predicate.Logical ?? "",
|
|
58426
|
+
Conditions: (trig.Predicate.Conditions ?? []).map(
|
|
58427
|
+
(c) => pickDefined(c)
|
|
58428
|
+
)
|
|
58429
|
+
} : {},
|
|
58430
|
+
EventBatchingCondition: trig.EventBatchingCondition ? pickDefined(trig.EventBatchingCondition) : {}
|
|
58431
|
+
};
|
|
58432
|
+
result["Tags"] = await fetchGlueTags(
|
|
58433
|
+
this.getClient(),
|
|
58434
|
+
this.getStsClient(),
|
|
58435
|
+
"trigger",
|
|
58436
|
+
trig.Name ?? physicalId,
|
|
58437
|
+
this.cachedAccountId,
|
|
58438
|
+
this.logger
|
|
58439
|
+
);
|
|
58440
|
+
return result;
|
|
58441
|
+
}
|
|
58442
|
+
async applyTagDiff(physicalId, oldTags, newTags) {
|
|
58443
|
+
const arn = await buildGlueResourceArn(
|
|
58444
|
+
this.getClient(),
|
|
58445
|
+
this.getStsClient(),
|
|
58446
|
+
"trigger",
|
|
58447
|
+
physicalId,
|
|
58448
|
+
this.cachedAccountId
|
|
58449
|
+
);
|
|
58450
|
+
const toAdd = {};
|
|
58451
|
+
const toRemove = [];
|
|
58452
|
+
for (const [k, v] of Object.entries(newTags)) {
|
|
58453
|
+
if (oldTags[k] !== v)
|
|
58454
|
+
toAdd[k] = v;
|
|
58455
|
+
}
|
|
58456
|
+
for (const k of Object.keys(oldTags)) {
|
|
58457
|
+
if (!(k in newTags))
|
|
58458
|
+
toRemove.push(k);
|
|
58459
|
+
}
|
|
58460
|
+
if (Object.keys(toAdd).length > 0 || toRemove.length > 0) {
|
|
58461
|
+
const { TagResourceCommand: TagResourceCommand17, UntagResourceCommand: UntagResourceCommand16 } = await import("@aws-sdk/client-glue");
|
|
58462
|
+
if (Object.keys(toAdd).length > 0) {
|
|
58463
|
+
await this.getClient().send(new TagResourceCommand17({ ResourceArn: arn, TagsToAdd: toAdd }));
|
|
58464
|
+
}
|
|
58465
|
+
if (toRemove.length > 0) {
|
|
58466
|
+
await this.getClient().send(
|
|
58467
|
+
new UntagResourceCommand16({ ResourceArn: arn, TagsToRemove: toRemove })
|
|
58468
|
+
);
|
|
58469
|
+
}
|
|
58470
|
+
}
|
|
58471
|
+
}
|
|
58472
|
+
async import(input) {
|
|
58473
|
+
const explicitName = input.knownPhysicalId ?? input.properties["Name"];
|
|
58474
|
+
if (!explicitName)
|
|
58475
|
+
return null;
|
|
58476
|
+
try {
|
|
58477
|
+
await this.getClient().send(new GetTriggerCommand({ Name: explicitName }));
|
|
58478
|
+
return { physicalId: explicitName, attributes: {} };
|
|
58479
|
+
} catch (err) {
|
|
58480
|
+
if (err instanceof EntityNotFoundException)
|
|
58481
|
+
return null;
|
|
58482
|
+
throw err;
|
|
58483
|
+
}
|
|
58484
|
+
}
|
|
58485
|
+
};
|
|
56875
58486
|
|
|
56876
58487
|
// src/provisioning/providers/kms-provider.ts
|
|
56877
58488
|
import {
|
|
@@ -63553,6 +65164,12 @@ function registerAllProviders(registry) {
|
|
|
63553
65164
|
const glueProvider = new GlueProvider();
|
|
63554
65165
|
registry.register("AWS::Glue::Database", glueProvider);
|
|
63555
65166
|
registry.register("AWS::Glue::Table", glueProvider);
|
|
65167
|
+
registry.register("AWS::Glue::Workflow", new GlueWorkflowProvider());
|
|
65168
|
+
registry.register("AWS::Glue::SecurityConfiguration", new GlueSecurityConfigurationProvider());
|
|
65169
|
+
registry.register("AWS::Glue::Job", new GlueJobProvider());
|
|
65170
|
+
registry.register("AWS::Glue::Crawler", new GlueCrawlerProvider());
|
|
65171
|
+
registry.register("AWS::Glue::Connection", new GlueConnectionProvider());
|
|
65172
|
+
registry.register("AWS::Glue::Trigger", new GlueTriggerProvider());
|
|
63556
65173
|
const kmsProvider = new KMSProvider();
|
|
63557
65174
|
registry.register("AWS::KMS::Key", kmsProvider);
|
|
63558
65175
|
registry.register("AWS::KMS::Alias", kmsProvider);
|
|
@@ -68373,7 +69990,7 @@ function reorderArgs(argv) {
|
|
|
68373
69990
|
}
|
|
68374
69991
|
async function main() {
|
|
68375
69992
|
const program = new Command14();
|
|
68376
|
-
program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.
|
|
69993
|
+
program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.65.0");
|
|
68377
69994
|
program.addCommand(createBootstrapCommand());
|
|
68378
69995
|
program.addCommand(createSynthCommand());
|
|
68379
69996
|
program.addCommand(createListCommand());
|