Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: correctly normalize json types #147

Merged
merged 8 commits into from
Aug 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 12 additions & 12 deletions examples/cron-lambda/adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,15 @@ interface target {
}

export function remapCloudControlResource(
element: CfnElement,
_element: CfnElement,
logicalId: string,
typeName: string,
rawProps: any,
options: pulumi.ResourceOptions,
): pulumi.CustomResource | undefined {
const props = pulumicdk.interop.normalize(rawProps);
switch (typeName) {
case 'AWS::Events::Rule':
const resources: { [key: string]: pulumi.CustomResource } = {};
case 'AWS::Events::Rule': {
const rule = new aws.cloudwatch.EventRule(
logicalId,
{
Expand All @@ -43,17 +42,18 @@ export function remapCloudControlResource(
);
}
return rule;
}
case 'AWS::Lambda::Permission':
return new aws.lambda.Permission(
logicalId,
{
action: props['action'],
function: props['functionName'],
principal: props['principal'],
sourceArn: props['sourceArn'] ?? undefined,
},
options,
);
logicalId,
{
action: props['action'],
function: props['functionName'],
principal: props['principal'],
sourceArn: props['sourceArn'] ?? undefined,
},
options,
);
}

return undefined;
Expand Down
7 changes: 4 additions & 3 deletions examples/fargate/adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,12 @@ export function remapCloudControlResource(
switch (typeName) {
case 'AWS::ApplicationAutoScaling::ScalingPolicy':
debug(`AWS::ApplicationAutoScaling::ScalingPolicy props: ${JSON.stringify(props)}`);
return new aws.appautoscaling.Policy(logicalId,
return new aws.appautoscaling.Policy(
logicalId,
{
resourceId: props.resourceId ?? props.scalingTargetId,
scalableDimension: props.scalableDimension ?? "ecs:service:DesiredCount",
serviceNamespace: props.serviceNamespace ?? "ecs",
scalableDimension: props.scalableDimension ?? 'ecs:service:DesiredCount',
serviceNamespace: props.serviceNamespace ?? 'ecs',
policyType: props.policyType,
stepScalingPolicyConfiguration: props.stepScalingPolicyConfiguration,
name: props.policyName,
Expand Down
3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
"devDependencies": {
"@aws-cdk/aws-apprunner-alpha": "2.20.0-alpha.0",
"@pulumi/aws": "^6.32.0",
"@pulumi/aws-native": "^0.108.0",
"@pulumi/docker": "^4.5.0",
"@pulumi/pulumi": "^3.117.0",
"@types/archiver": "^6.0.2",
Expand All @@ -47,13 +46,13 @@
},
"peerDependencies": {
"@pulumi/aws": "^6.32.0",
"@pulumi/aws-native": "^0.108.0",
"@pulumi/docker": "^4.5.0",
"@pulumi/pulumi": "^3.117.0",
"aws-cdk-lib": "^2.20.0",
"constructs": "^10.0.111"
},
"dependencies": {
"@pulumi/aws-native": "0.121.0",
"@types/glob": "^8.1.0",
"archiver": "^7.0.1"
},
Expand Down
214,497 changes: 214,497 additions & 0 deletions schemas/aws-native-metadata.json

Large diffs are not rendered by default.

14 changes: 7 additions & 7 deletions src/aws-resource-mappings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ export function mapToAwsResource(
requestParameters: rawProps.RequestParameters,
requestTemplates: rawProps.RequestTemplates,
responseParameters: rawProps.ResponseParameters,
tlsConfig: maybe(props.tlsConfig, (_) => ({ insecureSkipVerification: true })),
tlsConfig: maybe(props.tlsConfig, () => ({ insecureSkipVerification: true })),
},
options,
);
Expand Down Expand Up @@ -450,7 +450,7 @@ export function mapToAwsResource(
);

for (let i = 0; i < (props.groups || []).length; i++) {
const attachment = new aws.iam.GroupPolicyAttachment(
new aws.iam.GroupPolicyAttachment(
`${logicalId}-${i}`,
{
group: props.groups[i],
Expand All @@ -460,7 +460,7 @@ export function mapToAwsResource(
);
}
for (let i = 0; i < (props.roles || []).length; i++) {
const attachment = new aws.iam.RolePolicyAttachment(
new aws.iam.RolePolicyAttachment(
`${logicalId}-${i}`,
{
role: props.roles[i],
Expand All @@ -470,7 +470,7 @@ export function mapToAwsResource(
);
}
for (let i = 0; i < (props.users || []).length; i++) {
const attachment = new aws.iam.UserPolicyAttachment(
new aws.iam.UserPolicyAttachment(
`${logicalId}-${i}`,
{
user: props.users[i],
Expand Down Expand Up @@ -517,10 +517,10 @@ export function mapToAwsResource(
}

function mapDynamoDBTable(
element: CfnElement,
_element: CfnElement,
logicalId: string,
typeName: string,
rawProps: any,
_typeName: string,
_rawProps: any,
props: any,
options: pulumi.ResourceOptions,
): aws.dynamodb.Table {
Expand Down
81 changes: 2 additions & 79 deletions src/cfn-resource-mappings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
// limitations under the License.

import * as pulumi from '@pulumi/pulumi';
import { ecs, iam, apprunner, lambda, s3, s3objectlambda } from '@pulumi/aws-native';
import { s3 } from '@pulumi/aws-native';
import { CfnElement, Token, Reference, Tokenization } from 'aws-cdk-lib';
import { CfnResource, ResourceMapping, normalize } from './interop';
import { debug } from '@pulumi/pulumi/log';
Expand All @@ -26,90 +26,13 @@ export function mapToCfnResource(
rawProps: any,
options: pulumi.ResourceOptions,
): ResourceMapping {
const props = normalize(rawProps);
const props = normalize(rawProps, typeName);
debug(`mapToCfnResource typeName: ${typeName} props: ${JSON.stringify(props)}`);
switch (typeName) {
case 'AWS::AppRunner::Service':
corymhall marked this conversation as resolved.
Show resolved Hide resolved
return new apprunner.Service(logicalId, props, options);
case 'AWS::ECS::Cluster':
return new ecs.Cluster(logicalId, props, options);
case 'AWS::ECS::TaskDefinition':
return new ecs.TaskDefinition(logicalId, props, options);
case 'AWS::IAM::Role': {
// policyDocument and assumeRolePolicyDocument are both Json types
// so we need the raw names
return new iam.Role(
logicalId,
{
...props,
policies:
rawProps.Policies === undefined
? undefined
: rawProps.Policies.flatMap((policy: any) => {
return {
policyName: policy.PolicyName,
policyDocument: policy.PolicyDocument,
};
}),
assumeRolePolicyDocument: rawProps.AssumeRolePolicyDocument,
},
options,
);
}
case 'AWS::Lambda::Function':
// The Environment.Variables property is a Json type so we need
// the raw names
return new lambda.Function(
logicalId,
{
...props,
environment:
rawProps.Environment === undefined ? undefined : { variables: rawProps.Environment.Variables },
},
options,
);
case 'AWS::S3::AccessPoint':
// the policy property is a Json type so we need the raw names
return new s3.AccessPoint(
logicalId,
{
...props,
policy: rawProps.Policy,
},
options,
);
case 'AWS::S3::Bucket':
// Lowercase the bucket name to comply with the Bucket resource's naming constraints, which only allow
// lowercase letters.
return new s3.Bucket(logicalId.toLowerCase(), props, options);
case 'AWS::S3ObjectLambda::AccessPoint': {
const transformations = rawProps.ObjectLambdaConfiguration.TransformationConfigurations;
return new s3objectlambda.AccessPoint(
logicalId,
{
name: props.name,
objectLambdaConfiguration: {
allowedFeatures: props.objectLambdaConfiguration.allowedFeatures,
cloudWatchMetricsEnabled: props.objectLambdaConfiguration.cloudWatchMetricsEnabled,
supportingAccessPoint: props.objectLambdaConfiguration.supportingAccessPoint,
transformationConfigurations:
transformations === undefined
? undefined
: transformations.map((config: any) => ({
actions: config.Actions,
contentTransformation: {
awsLambda: {
functionArn: config.ContentTransformation.AwsLambda.FunctionArn,
// functionPayload is a Json type so we need the raw value
functionPayload: config.ContentTransformation.AwsLambda.FunctionPayload,
},
},
})),
},
},
options,
);
}
default: {
// Scrape the attributes off of the construct.
//
Expand Down
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@ export * from './output';

import * as interop from './interop';
export { interop };
export * from './types';
47 changes: 18 additions & 29 deletions src/interop.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,25 +12,37 @@
// See the License for the specific language governing permissions and
// limitations under the License.

import * as cdk from 'aws-cdk-lib';
import * as pulumi from '@pulumi/pulumi';
import { debug } from '@pulumi/pulumi/log';
import { IConstruct } from 'constructs';
import { moduleName, toSdkName, typeToken } from './naming';
import { normalizeObject } from './pulumi-metadata';
import { toSdkName, typeToken } from './naming';
import { PulumiProvider } from './types';

export function firstToLower(str: string) {
return str.replace(/\w\S*/g, function (txt) {
return txt.charAt(0).toLowerCase() + txt.substr(1);
return txt.charAt(0).toLowerCase() + txt.substring(1);
});
}

export function normalize(value: any): any {
/**
* normalize will take the resource properties for a specific CloudFormation resource and
* will covert those properties to be compatible with Pulumi properties.
*
* @param value - The resource properties to be normalized
* @param cfnType The CloudFormation resource type being normalized (e.g. AWS::S3::Bucket). If no value
* is provided then property conversion will be done without schema knowledge
* @param pulumiProvider The pulumi provider to read the schema from. If `cfnType` is provided then this defaults
* to PulumiProvider.AWS_NATIVE
* @returns The normalized resource properties
*/
export function normalize(value: any, cfnType?: string, pulumiProvider?: PulumiProvider): any {
if (!value) return value;

if (Array.isArray(value)) {
const result: any[] = [];
for (let i = 0; i < value.length; i++) {
result[i] = normalize(value[i]);
result[i] = normalize(value[i], cfnType);
}
return result;
}
Expand All @@ -41,7 +53,7 @@ export function normalize(value: any): any {

const result: any = {};
Object.entries(value).forEach(([k, v]) => {
result[toSdkName(k)] = normalize(v);
result[toSdkName(k)] = normalizeObject([k], v, cfnType, pulumiProvider);
});
return result;
}
Expand Down Expand Up @@ -95,26 +107,3 @@ export class CdkConstruct extends pulumi.ComponentResource {
this.registerOutputs({});
}
}

export class CdkComponent extends pulumi.ComponentResource {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was unused, so removing it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice!

constructor(name: string, args: (stack: cdk.Stack) => void, opts?: pulumi.CustomResourceOptions) {
super('cdk:index:Component', name, args, opts);

const app = new cdk.App();
const stack = new cdk.Stack(app);
args(stack);

//debugger;
const template = app.synth().getStackByName(stack.stackName).template;
console.debug(`template: ${JSON.stringify(template)}`);
const resources = template.Resources;

Object.entries(resources).forEach(([key, value]) => {
const typeName = (value as any).Type;
const sourceProps = (value as any).Properties;
console.debug(`resource[${key}] Type:${typeName} props: ${sourceProps}`);
opts = opts || { parent: this };
new CfnResource(key, typeName, normalize(sourceProps), [], opts);
});
}
}
Loading
Loading