Skip to content

Commit

Permalink
Merge branch 'main' into bobertzh/applicationautoscaling
Browse files Browse the repository at this point in the history
  • Loading branch information
mergify[bot] authored Jan 27, 2025
2 parents b84c198 + 04efe6c commit e037b98
Show file tree
Hide file tree
Showing 42 changed files with 12,810 additions and 404 deletions.
15 changes: 11 additions & 4 deletions packages/@aws-cdk-testing/cli-integ/lib/aws.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,19 @@ import { SNSClient } from '@aws-sdk/client-sns';
import { SSOClient } from '@aws-sdk/client-sso';
import { STSClient, GetCallerIdentityCommand } from '@aws-sdk/client-sts';
import { fromIni } from '@aws-sdk/credential-providers';
import type { AwsCredentialIdentityProvider } from '@smithy/types';
import type { AwsCredentialIdentity, AwsCredentialIdentityProvider } from '@smithy/types';
import { ConfiguredRetryStrategy } from '@smithy/util-retry';
interface ClientConfig {
readonly credentials?: AwsCredentialIdentityProvider;
readonly credentials?: AwsCredentialIdentityProvider | AwsCredentialIdentity;
readonly region: string;
readonly retryStrategy: ConfiguredRetryStrategy;
}

export class AwsClients {
public static async forIdentity(region: string, identity: AwsCredentialIdentity, output: NodeJS.WritableStream) {
return new AwsClients(region, output, identity);
}

public static async forRegion(region: string, output: NodeJS.WritableStream) {
return new AwsClients(region, output);
}
Expand All @@ -45,9 +49,12 @@ export class AwsClients {
public readonly lambda: LambdaClient;
public readonly sts: STSClient;

constructor(public readonly region: string, private readonly output: NodeJS.WritableStream) {
constructor(
public readonly region: string,
private readonly output: NodeJS.WritableStream,
public readonly identity?: AwsCredentialIdentity) {
this.config = {
credentials: chainableCredentials(this.region),
credentials: this.identity ?? chainableCredentials(this.region),
region: this.region,
retryStrategy: new ConfiguredRetryStrategy(9, (attempt: number) => attempt ** 500),
};
Expand Down
2 changes: 2 additions & 0 deletions packages/@aws-cdk-testing/cli-integ/lib/integ-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ if (SKIP_TESTS) {

export interface TestContext {
readonly randomString: string;
readonly name: string;
readonly output: NodeJS.WritableStream;
log(s: string): void;
};
Expand Down Expand Up @@ -51,6 +52,7 @@ export function integTest(
return await callback({
output,
randomString: randomString(),
name,
log(s: string) {
output.write(`${s}\n`);
},
Expand Down
60 changes: 55 additions & 5 deletions packages/@aws-cdk-testing/cli-integ/lib/with-aws.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,30 @@
import { AtmosphereClient } from '@cdklabs/cdk-atmosphere-client';
import { AwsClients } from './aws';
import { TestContext } from './integ-test';
import { ResourcePool } from './resource-pool';
import { DisableBootstrapContext } from './with-cdk-app';

export function atmosphereEnabled(): boolean {
const enabled = process.env.CDK_INTEG_ATMOSPHERE_ENABLED;
return enabled === 'true' || enabled === '1';
}

export function atmosphereEndpoint(): string {
const value = process.env.CDK_INTEG_ATMOSPHERE_ENDPOINT;
if (!value) {
throw new Error('CDK_INTEG_ATMOSPHERE_ENDPOINT is not defined');
}
return value;
}

export function atmospherePool() {
const value = process.env.CDK_INTEG_ATMOSPHERE_POOL;
if (!value) {
throw new Error('CDK_INTEG_ATMOSPHERE_POOL is not defined');
}
return value;
}

export type AwsContext = { readonly aws: AwsClients };

/**
Expand All @@ -14,12 +36,40 @@ export function withAws<A extends TestContext>(
block: (context: A & AwsContext & DisableBootstrapContext) => Promise<void>,
disableBootstrap: boolean = false,
): (context: A) => Promise<void> {
return (context: A) => regionPool().using(async (region) => {
const aws = await AwsClients.forRegion(region, context.output);
await sanityCheck(aws);
return async (context: A) => {

if (atmosphereEnabled()) {
const atmosphere = new AtmosphereClient(atmosphereEndpoint());
const allocation = await atmosphere.acquire({ pool: atmospherePool(), requester: context.name });
const aws = await AwsClients.forIdentity(allocation.environment.region, {
accessKeyId: allocation.credentials.accessKeyId,
secretAccessKey: allocation.credentials.secretAccessKey,
sessionToken: allocation.credentials.sessionToken,
accountId: allocation.environment.account,
}, context.output);

await sanityCheck(aws);

let outcome = 'success';
try {
return await block({ ...context, disableBootstrap, aws });
} catch (e: any) {
outcome = 'failure';
throw e;
} finally {
await atmosphere.release(allocation.id, outcome);
}

} else {
return regionPool().using(async (region) => {
const aws = await AwsClients.forRegion(region, context.output);
await sanityCheck(aws);

return block({ ...context, disableBootstrap, aws });
});
}

return block({ ...context, disableBootstrap, aws });
});
};
}

let _regionPool: undefined | ResourcePool;
Expand Down
84 changes: 52 additions & 32 deletions packages/@aws-cdk-testing/cli-integ/lib/with-cdk-app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { IPackageSource } from './package-sources/source';
import { packageSourceInSubprocess } from './package-sources/subprocess';
import { RESOURCES_DIR } from './resources';
import { shell, ShellOptions, ShellHelper, rimraf } from './shell';
import { AwsContext, withAws } from './with-aws';
import { AwsContext, atmosphereEnabled, withAws } from './with-aws';
import { withTimeout } from './with-timeout';

export const DEFAULT_TEST_TIMEOUT_S = 20 * 60;
Expand Down Expand Up @@ -498,13 +498,22 @@ export class TestFixture extends ShellHelper {

await this.packages.makeCliAvailable();

// if tests are using an explicit aws identity already (i.e creds)
// force every cdk command to use the same identity.
const awsCreds: Record<string, string> = this.aws.identity ? {
AWS_ACCESS_KEY_ID: this.aws.identity.accessKeyId,
AWS_SECRET_ACCESS_KEY: this.aws.identity.secretAccessKey,
AWS_SESSION_TOKEN: this.aws.identity.sessionToken!,
} : {};

return this.shell(['cdk', ...(verbose ? ['-v'] : []), ...args], {
...options,
modEnv: {
AWS_REGION: this.aws.region,
AWS_DEFAULT_REGION: this.aws.region,
STACK_NAME_PREFIX: this.stackNamePrefix,
PACKAGE_LAYOUT_VERSION: this.packages.majorVersion(),
...awsCreds,
...options.modEnv,
},
});
Expand Down Expand Up @@ -555,37 +564,44 @@ export class TestFixture extends ShellHelper {
* Cleanup leftover stacks and bootstrapped resources
*/
public async dispose(success: boolean) {
const stacksToDelete = await this.deleteableStacks(this.stackNamePrefix);

this.sortBootstrapStacksToTheEnd(stacksToDelete);

// Bootstrap stacks have buckets that need to be cleaned
const bucketNames = stacksToDelete.map(stack => outputFromStack('BucketName', stack)).filter(defined);
// Parallelism will be reasonable
// eslint-disable-next-line @cdklabs/promiseall-no-unbounded-parallelism
await Promise.all(bucketNames.map(b => this.aws.emptyBucket(b)));
// The bootstrap bucket has a removal policy of RETAIN by default, so add it to the buckets to be cleaned up.
this.bucketsToDelete.push(...bucketNames);

// Bootstrap stacks have ECR repositories with images which should be deleted
const imageRepositoryNames = stacksToDelete.map(stack => outputFromStack('ImageRepositoryName', stack)).filter(defined);
// Parallelism will be reasonable
// eslint-disable-next-line @cdklabs/promiseall-no-unbounded-parallelism
await Promise.all(imageRepositoryNames.map(r => this.aws.deleteImageRepository(r)));

await this.aws.deleteStacks(
...stacksToDelete.map((s) => {
if (!s.StackName) {
throw new Error('Stack name is required to delete a stack.');
}
return s.StackName;
}),
);

// We might have leaked some buckets by upgrading the bootstrap stack. Be
// sure to clean everything.
for (const bucket of this.bucketsToDelete) {
await this.aws.deleteBucket(bucket);
// when using the atmosphere service, it does resource cleanup on our behalf
// so we don't have to wait for it.
if (!atmosphereEnabled()) {

const stacksToDelete = await this.deleteableStacks(this.stackNamePrefix);

this.sortBootstrapStacksToTheEnd(stacksToDelete);

// Bootstrap stacks have buckets that need to be cleaned
const bucketNames = stacksToDelete.map(stack => outputFromStack('BucketName', stack)).filter(defined);
// Parallelism will be reasonable
// eslint-disable-next-line @cdklabs/promiseall-no-unbounded-parallelism
await Promise.all(bucketNames.map(b => this.aws.emptyBucket(b)));
// The bootstrap bucket has a removal policy of RETAIN by default, so add it to the buckets to be cleaned up.
this.bucketsToDelete.push(...bucketNames);

// Bootstrap stacks have ECR repositories with images which should be deleted
const imageRepositoryNames = stacksToDelete.map(stack => outputFromStack('ImageRepositoryName', stack)).filter(defined);
// Parallelism will be reasonable
// eslint-disable-next-line @cdklabs/promiseall-no-unbounded-parallelism
await Promise.all(imageRepositoryNames.map(r => this.aws.deleteImageRepository(r)));

await this.aws.deleteStacks(
...stacksToDelete.map((s) => {
if (!s.StackName) {
throw new Error('Stack name is required to delete a stack.');
}
return s.StackName;
}),
);

// We might have leaked some buckets by upgrading the bootstrap stack. Be
// sure to clean everything.
for (const bucket of this.bucketsToDelete) {
await this.aws.deleteBucket(bucket);
}

}

// If the tests completed successfully, happily delete the fixture
Expand Down Expand Up @@ -662,7 +678,11 @@ export async function ensureBootstrapped(fixture: TestFixture) {
},
});

ALREADY_BOOTSTRAPPED_IN_THIS_RUN.add(envSpecifier);
// when using the atmosphere service, every test needs to bootstrap
// its own environment.
if (!atmosphereEnabled()) {
ALREADY_BOOTSTRAPPED_IN_THIS_RUN.add(envSpecifier);
}
}

function defined<A>(x: A): x is NonNullable<A> {
Expand Down
3 changes: 2 additions & 1 deletion packages/@aws-cdk-testing/cli-integ/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
"@aws-sdk/client-sso": "3.632.0",
"@aws-sdk/client-sts": "3.632.0",
"@aws-sdk/credential-providers": "3.632.0",
"@cdklabs/cdk-atmosphere-client": "0.0.1",
"@smithy/util-retry": "3.0.8",
"@smithy/types": "3.6.0",
"axios": "1.7.7",
Expand Down Expand Up @@ -86,4 +87,4 @@
"publishConfig": {
"tag": "latest"
}
}
}
Loading

0 comments on commit e037b98

Please sign in to comment.