Skip to content

Commit

Permalink
Merge pull request #579 from amplify-education/fix_stage_name_handling
Browse files Browse the repository at this point in the history
Fix stage name handling
  • Loading branch information
rddimon committed Jul 18, 2023
2 parents 6642b44 + e16880f commit ebee6fd
Show file tree
Hide file tree
Showing 12 changed files with 1,671 additions and 1,322 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).

## [7.1.0] - 2023-07-18

### Fixed
- Support for the custom stages.

## [7.0.4] - 2023-05-10

### Added
Expand Down
2,879 changes: 1,601 additions & 1,278 deletions package-lock.json

Large diffs are not rendered by default.

38 changes: 20 additions & 18 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "serverless-domain-manager",
"version": "7.0.4",
"version": "7.1.0",
"engines": {
"node": ">=14"
},
Expand Down Expand Up @@ -34,7 +34,8 @@
"test:debug": "NODE_OPTIONS='--inspect-brk' mocha -j 1 -r ts-node/register --project tsconfig.json test/unit-tests/index.test.ts",
"integration-test": "npm run integration-basic && npm run integration-deploy",
"lint": "tslint --project . && tslint --project tsconfig.json",
"build": "tsc --project ."
"build": "tsc --project .",
"prepare": "npm run build"
},
"files": [
"*.js",
Expand All @@ -49,33 +50,34 @@
},
"devDependencies": {
"@types/mocha": "^10.0.1",
"@types/node": "^20.1.1",
"@types/node": "^20.4.2",
"@types/shelljs": "^0.8.12",
"aws-sdk-client-mock": "^2.1.1",
"aws-sdk-client-mock": "^3.0.0",
"chai": "^4.3.7",
"chai-spies": "^1.0.0",
"mocha": "^10.2.0",
"mocha-param": "^2.0.1",
"nyc": "^15.1.0",
"randomstring": "^1.2.3",
"serverless": "^3.30.1",
"serverless-plugin-split-stacks": "^1.12.0",
"randomstring": "^1.3.0",
"serverless": "^3.33.0",
"serverless-plugin-split-stacks": "^1.13.0",
"shelljs": "^0.8.5",
"ts-node": "^10.9.1",
"tslint": "^6.1.3",
"typescript": "^5.0.4"
"typescript": "^5.1.6"
},
"dependencies": {
"@aws-sdk/client-acm": "^3.329.0",
"@aws-sdk/client-api-gateway": "^3.329.0",
"@aws-sdk/client-apigatewayv2": "^3.329.0",
"@aws-sdk/client-cloudformation": "^3.329.0",
"@aws-sdk/client-route-53": "^3.329.0",
"@aws-sdk/client-s3": "^3.329.0",
"@aws-sdk/config-resolver": "^3.329.0",
"@aws-sdk/credential-providers": "^3.329.0",
"@aws-sdk/node-config-provider": "^3.329.0",
"@aws-sdk/smithy-client": "^3.329.0"
"@aws-sdk/client-acm": "^3.370.0",
"@aws-sdk/client-api-gateway": "^3.370.0",
"@aws-sdk/client-apigatewayv2": "^3.370.0",
"@aws-sdk/client-cloudformation": "^3.370.0",
"@aws-sdk/client-route-53": "^3.370.0",
"@aws-sdk/client-s3": "^3.370.0",
"@aws-sdk/config-resolver": "^3.370.0",
"@aws-sdk/credential-providers": "^3.370.0",
"@aws-sdk/node-config-provider": "^3.370.0",
"@aws-sdk/smithy-client": "^3.370.0",
"@aws-sdk/util-retry": "^3.370.0"
},
"peerDependencies": {
"serverless": "^2.60 || ^3.0.0"
Expand Down
5 changes: 3 additions & 2 deletions src/aws/api-gateway-v1-wrapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ class APIGatewayV1Wrapper extends APIGatewayBase {
super();
this.apiGateway = new APIGatewayClient({
credentials,
region: Globals.getRegion()
region: Globals.getRegion(),
retryStrategy: Globals.getRetryStrategy()
});
}

Expand Down Expand Up @@ -110,7 +111,7 @@ class APIGatewayV1Wrapper extends APIGatewayBase {
basePath: domain.basePath,
domainName: domain.givenDomainName,
restApiId: domain.apiId,
stage: domain.baseStage,
stage: domain.stage,
}));
Logging.logInfo(`V1 - Created API mapping '${domain.basePath}' for '${domain.givenDomainName}'`);
} catch (err) {
Expand Down
25 changes: 11 additions & 14 deletions src/aws/api-gateway-v2-wrapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ class APIGatewayV2Wrapper extends APIGatewayBase {
super();
this.apiGateway = new ApiGatewayV2Client({
credentials,
region: Globals.getRegion()
region: Globals.getRegion(),
retryStrategy: Globals.getRetryStrategy()
});
}

Expand Down Expand Up @@ -121,19 +122,21 @@ class APIGatewayV2Wrapper extends APIGatewayBase {
* @param domain: DomainConfig
*/
public async createBasePathMapping(domain: DomainConfig): Promise<void> {
let stage = domain.baseStage;
if (domain.apiType === Globals.apiTypes.http) {
// find a better way how to implement custom stage for the HTTP API type
stage = Globals.defaultStage;
if (domain.apiType === Globals.apiTypes.http && domain.stage !== Globals.defaultStage) {
Logging.logWarning(
`Using a HTTP API with a stage name other than '${Globals.defaultStage}'. ` +
`HTTP APIs require a stage named '${Globals.defaultStage}'. ` +
'Please make sure that stage exists in the API Gateway. ' +
'See https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-stages.html'
)
}

try {
await this.apiGateway.send(
new CreateApiMappingCommand({
ApiId: domain.apiId,
ApiMappingKey: domain.basePath,
DomainName: domain.givenDomainName,
Stage: stage,
Stage: domain.stage,
})
);
Logging.logInfo(`V2 - Created API mapping '${domain.basePath}' for '${domain.givenDomainName}'`);
Expand Down Expand Up @@ -171,20 +174,14 @@ class APIGatewayV2Wrapper extends APIGatewayBase {
* @param domain: DomainConfig
*/
public async updateBasePathMapping(domain: DomainConfig): Promise<void> {
let stage = domain.baseStage;
if (domain.apiType === Globals.apiTypes.http) {
// find a better way how to implement custom stage for the HTTP API type
stage = Globals.defaultStage;
}

try {
await this.apiGateway.send(
new UpdateApiMappingCommand({
ApiId: domain.apiId,
ApiMappingId: domain.apiMapping.apiMappingId,
ApiMappingKey: domain.basePath,
DomainName: domain.givenDomainName,
Stage: stage,
Stage: domain.stage,
})
);
Logging.logInfo(`V2 - Updated API mapping to '${domain.basePath}' for '${domain.givenDomainName}'`);
Expand Down
1 change: 1 addition & 0 deletions src/aws/cloud-formation-wrapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ class CloudFormationWrapper {
public stackName: string;

constructor(credentials?: any) {
// for the CloudFormation stack we should use the `base` stage not the plugin custom stage
const defaultStackName = Globals.serverless.service.service + "-" + Globals.getBaseStage();
this.stackName = Globals.serverless.service.provider.stackName || defaultStackName;
this.cloudFormation = new CloudFormationClient({
Expand Down
10 changes: 10 additions & 0 deletions src/globals.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {ServerlessInstance, ServerlessOptions, ServerlessUtils} from "./types";
import {fromIni} from "@aws-sdk/credential-providers";
import {ConfiguredRetryStrategy} from "@aws-sdk/util-retry";

export default class Globals {

Expand Down Expand Up @@ -73,4 +74,13 @@ export default class Globals {
public static async getProfileCreds(profile: string) {
return await fromIni({profile})();
}

public static getRetryStrategy(attempts: number = 3, delay: number = 3000, backoff: number = 500) {
return new ConfiguredRetryStrategy(
attempts, // max attempts.
// This example sets the backoff at 500ms plus 3s per attempt.
// https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/modules/_aws_sdk_util_retry.html#aws-sdkutil-retry
(attempt: number) => backoff + attempt * delay // backoff function.
)
}
}
2 changes: 1 addition & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -464,7 +464,7 @@ class ServerlessCustomDomain {
}

// Remove all special characters
const safeStage = domain.baseStage.replace(/[^a-zA-Z0-9]/g, "");
const safeStage = domain.stage.replace(/[^a-zA-Z\d]/g, "");
service.provider.compiledCloudFormationTemplate.Outputs[domainNameOutputKey] = {
Value: domain.givenDomainName,
Export: {
Expand Down
14 changes: 10 additions & 4 deletions src/models/domain-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import Logging from "../logging";
class DomainConfig {
public givenDomainName: string;
public basePath: string | undefined;
public baseStage: string | undefined;
public stage: string | undefined;
public certificateName: string | undefined;
public certificateArn: string | undefined;
Expand Down Expand Up @@ -55,17 +54,24 @@ class DomainConfig {
this.autoDomainWaitFor = config.autoDomainWaitFor;
this.preserveExternalPathMappings = evaluateBoolean(config.preserveExternalPathMappings, false);
this.basePath = this._getBasePath(config.basePath);
this.baseStage = Globals.getBaseStage();
this.stage = config.stage || Globals.getBaseStage();
this.endpointType = this._getEndpointType(config.endpointType);
this.apiType = this._getApiType(config.apiType);
// apiType should be defined before stage
this.stage = this._getStage(config.stage, this.apiType);
this.endpointType = this._getEndpointType(config.endpointType);
this.tlsTruststoreUri = this._getTLSTruststoreUri(config.tlsTruststoreUri, this.endpointType);
this.tlsTruststoreVersion = config.tlsTruststoreVersion;
this.securityPolicy = this._getSecurityPolicy(config.securityPolicy);
this.route53Params = this._getRoute53Params(config.route53Params, this.endpointType);
this.splitHorizonDns = !this.hostedZoneId && !this.hostedZonePrivate && evaluateBoolean(config.splitHorizonDns, false);
}

private _getStage(stage: string, apiType: string) {
if (apiType === Globals.apiTypes.http && !stage) {
return Globals.defaultStage;
}
return stage || Globals.getBaseStage()
}

private _getBasePath(basePath: string | undefined) {
if (!basePath || basePath.trim() === "") {
basePath = Globals.defaultBasePath;
Expand Down
6 changes: 5 additions & 1 deletion test/integration-tests/apigateway.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,16 @@ import {
GetResourcesCommand,
GetResourcesCommandOutput
} from "@aws-sdk/client-api-gateway";
import Globals from "../../src/globals";

export default class APIGatewayWrap {
private client: APIGatewayClient;

constructor(region: string) {
this.client = new APIGatewayClient({region});
this.client = new APIGatewayClient({
region,
retryStrategy: Globals.getRetryStrategy()
});
}

/**
Expand Down
2 changes: 1 addition & 1 deletion test/unit-tests/aws/api-gateway-v1-wrapper.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,7 @@ describe("API Gateway V1 wrapper checks", () => {
basePath: dc.basePath,
domainName: dc.givenDomainName,
restApiId: dc.apiId,
stage: dc.baseStage,
stage: dc.stage,
}
const commandCalls = APIGatewayMock.commandCalls(CreateBasePathMappingCommand, expectedParams, true);

Expand Down
6 changes: 3 additions & 3 deletions test/unit-tests/aws/api-gateway-v2-wrapper.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,7 @@ describe("API Gateway V2 wrapper checks", () => {
ApiMappingKey: dc.basePath,
DomainName: dc.givenDomainName,
ApiId: dc.apiId,
Stage: dc.baseStage,
Stage: dc.stage,
}
const commandCalls = APIGatewayMock.commandCalls(CreateApiMappingCommand, expectedParams, true);

Expand All @@ -336,7 +336,7 @@ describe("API Gateway V2 wrapper checks", () => {
ApiMappingKey: dc.basePath,
DomainName: dc.givenDomainName,
ApiId: dc.apiId,
Stage: Globals.defaultStage,
Stage: dc.stage,
}
const commandCalls = APIGatewayMock.commandCalls(CreateApiMappingCommand, expectedParams, true);

Expand Down Expand Up @@ -472,7 +472,7 @@ describe("API Gateway V2 wrapper checks", () => {
ApiMappingId: dc.apiMapping.apiMappingId,
ApiMappingKey: dc.basePath,
DomainName: dc.givenDomainName,
Stage: Globals.defaultStage
Stage: dc.stage
}
const commandCalls = APIGatewayMock.commandCalls(UpdateApiMappingCommand, expectedParams, true);

Expand Down

0 comments on commit ebee6fd

Please sign in to comment.