Skip to content

Commit

Permalink
Update to version 6.3.1 (#576)
Browse files Browse the repository at this point in the history
  • Loading branch information
simonkrol authored Oct 2, 2024
1 parent 55d24fe commit afc0fb5
Show file tree
Hide file tree
Showing 23 changed files with 132 additions and 48 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [6.3.1] - 2024-10-02

### Fixed

- Base-64 encoded overlayWith call requiring strings in top/left options rather than numbers
- CloudFront anonymized metrics missing for deployments outside of us-east-1

## [6.3.0] - 2024-09-09

### Added
Expand Down
2 changes: 1 addition & 1 deletion VERSION.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
6.3.0
6.3.1
4 changes: 2 additions & 2 deletions source/constructs/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion source/constructs/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "constructs",
"version": "6.3.0",
"version": "6.3.1",
"description": "Serverless Image Handler Constructs",
"license": "Apache-2.0",
"author": {
Expand Down
14 changes: 7 additions & 7 deletions source/constructs/test/__snapshots__/constructs.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ exports[`Serverless Image Handler Stack Snapshot 1`] = `
"Config": {
"AnonymousUsage": "Yes",
"SolutionId": "S0ABC",
"Version": "v6.3.0",
"Version": "v6.3.1",
},
},
},
Expand Down Expand Up @@ -408,7 +408,7 @@ exports[`Serverless Image Handler Stack Snapshot 1`] = `
"Solutions:ApplicationType": "AWS-Solutions",
"Solutions:SolutionID": "S0ABC",
"Solutions:SolutionName": "sih",
"Solutions:SolutionVersion": "v6.3.0",
"Solutions:SolutionVersion": "v6.3.1",
},
},
"Type": "AWS::ServiceCatalogAppRegistry::Application",
Expand Down Expand Up @@ -1277,7 +1277,7 @@ exports[`Serverless Image Handler Stack Snapshot 1`] = `
},
"S3Key": "Omitted to remove snapshot dependency on hash",
},
"Description": "sih (v6.3.0): Performs image edits and manipulations",
"Description": "sih (v6.3.1): Performs image edits and manipulations",
"Environment": {
"Variables": {
"AUTO_WEBP": {
Expand Down Expand Up @@ -1492,7 +1492,7 @@ exports[`Serverless Image Handler Stack Snapshot 1`] = `
{
"Ref": "BackEndImageHandlerCloudFrontApiGatewayLambdaCloudFrontToApiGatewayCloudFrontDistribution03AA31B2",
},
""},{"Name":"Region","Value":"Global"}],"MetricName":"Requests"},"Stat":"Sum","Period":604800},"Id":"id_",
""},{"Name":"Region","Value":"Global"}],"MetricName":"Requests"},"Stat":"Sum","Period":604800},"region":"us-east-1","Id":"id_",
{
"Fn::Join": [
"_",
Expand All @@ -1510,7 +1510,7 @@ exports[`Serverless Image Handler Stack Snapshot 1`] = `
{
"Ref": "BackEndImageHandlerCloudFrontApiGatewayLambdaCloudFrontToApiGatewayCloudFrontDistribution03AA31B2",
},
""},{"Name":"Region","Value":"Global"}],"MetricName":"BytesDownloaded"},"Stat":"Sum","Period":604800},"Id":"id_",
""},{"Name":"Region","Value":"Global"}],"MetricName":"BytesDownloaded"},"Stat":"Sum","Period":604800},"region":"us-east-1","Id":"id_",
{
"Fn::Join": [
"_",
Expand Down Expand Up @@ -1977,7 +1977,7 @@ exports[`Serverless Image Handler Stack Snapshot 1`] = `
},
"S3Key": "Omitted to remove snapshot dependency on hash",
},
"Description": "sih (v6.3.0): Custom resource",
"Description": "sih (v6.3.1): Custom resource",
"Environment": {
"Variables": {
"RETRY_SECONDS": "5",
Expand Down Expand Up @@ -2583,7 +2583,7 @@ exports[`Serverless Image Handler Stack Snapshot 1`] = `
"applicationType": "AWS-Solutions",
"solutionID": "S0ABC",
"solutionName": "sih",
"version": "v6.3.0",
"version": "v6.3.1",
},
"Description": "Attribute group for solution information",
"Name": {
Expand Down
4 changes: 2 additions & 2 deletions source/constructs/test/constructs.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@ test("Serverless Image Handler Stack Snapshot", () => {
context: {
solutionId: "SO0023",
solutionName: "serverless-image-handler",
solutionVersion: "v6.3.0",
solutionVersion: "v6.3.1",
},
});

const stack = new ServerlessImageHandlerStack(app, "TestStack", {
solutionId: "S0ABC",
solutionName: "sih",
solutionVersion: "v6.3.0",
solutionVersion: "v6.3.1",
});

const template = Template.fromStack(stack);
Expand Down
4 changes: 2 additions & 2 deletions source/custom-resource/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion source/custom-resource/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "custom-resource",
"version": "6.3.0",
"version": "6.3.1",
"private": true,
"description": "Serverless Image Handler custom resource",
"license": "Apache-2.0",
Expand Down
4 changes: 2 additions & 2 deletions source/demo-ui/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion source/demo-ui/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "demo-ui",
"version": "6.3.0",
"version": "6.3.1",
"private": true,
"description": "Serverless Image Handler demo ui",
"license": "Apache-2.0",
Expand Down
7 changes: 6 additions & 1 deletion source/image-handler/image-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -223,10 +223,15 @@ export class ImageHandler {
* @param overlaySize the size of the overlay
* @returns the calculated size
*/
private calcOverlaySizeOption = (editSize: string | undefined, imageSize: number, overlaySize: number): number => {
private calcOverlaySizeOption = (
editSize: string | number | undefined,
imageSize: number,
overlaySize: number
): number => {
let resultSize = NaN;

if (editSize !== undefined) {
editSize = `${editSize}`;
// if ends with p, it is a percentage
if (editSize.endsWith("p")) {
resultSize = parseInt(editSize.replace("p", ""));
Expand Down
4 changes: 2 additions & 2 deletions source/image-handler/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion source/image-handler/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "image-handler",
"version": "6.3.0",
"version": "6.3.1",
"private": true,
"description": "A Lambda function for performing on-demand image edits and manipulations.",
"license": "Apache-2.0",
Expand Down
28 changes: 28 additions & 0 deletions source/image-handler/test/image-handler/overlay.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,34 @@ describe("calcOverlaySizeOption", () => {
expect(result).toEqual(50);
});

it("should return the specified parameter if param is a positive number and an integer", () => {
// Arrange
const imageSize = 100;
const editSize = 50;
const overlaySize = 50;
const imageHandler = new ImageHandler(s3Client, rekognitionClient);

// Act
const result = imageHandler["calcOverlaySizeOption"](editSize, imageSize, overlaySize);

// Assert
expect(result).toEqual(50);
});

it("should return the image size + specified parameter - overlay size if param is less than 0 and an integer", () => {
// Arrange
const imageSize = 100;
const editSize = -60;
const overlaySize = 50;
const imageHandler = new ImageHandler(s3Client, rekognitionClient);

// Act
const result = imageHandler["calcOverlaySizeOption"](editSize, imageSize, overlaySize);

// Assert
expect(result).toEqual(-10);
});

it("should return the image size + specified parameter - overlay size if param is less than 0", () => {
// Arrange
const imageSize = 100;
Expand Down
17 changes: 11 additions & 6 deletions source/metrics-utils/lambda/helpers/client-helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@ import { CloudWatchLogsClient } from "@aws-sdk/client-cloudwatch-logs";

export class ClientHelper {
private sqsClient: SQSClient;
private cwClient: CloudWatchClient;
private cwClients: {[key: string]: CloudWatchClient };
private cwLogsClient: CloudWatchLogsClient;

constructor() {}
constructor() {
this.cwClients = {};
}

getSqsClient(): SQSClient {
if (!this.sqsClient) {
Expand All @@ -19,11 +21,14 @@ export class ClientHelper {
return this.sqsClient;
}

getCwClient(): CloudWatchClient {
if (!this.cwClient) {
this.cwClient = new CloudWatchClient();
getCwClient(region: string = "default"): CloudWatchClient {
if (region === "default") {
region = process.env.AWS_REGION || process.env.AWS_DEFAULT_REGION || "default"
}
if (!(region in this.cwClients)) {
this.cwClients[region] = region === "default" ? new CloudWatchClient({}) : new CloudWatchClient({ region });
}
return this.cwClient;
return this.cwClients[region];
}

getCwLogsClient(): CloudWatchLogsClient {
Expand Down
33 changes: 23 additions & 10 deletions source/metrics-utils/lambda/helpers/metrics-helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import {
StartQueryCommandInput,
QueryDefinition,
} from "@aws-sdk/client-cloudwatch-logs";
import { EventBridgeQueryEvent, MetricPayload, MetricData, QueryProps, SQSEventBody, ExecutionDay } from "./types";
import { EventBridgeQueryEvent, MetricPayload, MetricData, QueryProps, SQSEventBody, ExecutionDay, MetricDataProps } from "./types";
import { SQSEvent } from "aws-lambda";
import { ClientHelper } from "./client-helper";
import axios, { RawAxiosRequestConfig } from "axios";
Expand All @@ -35,22 +35,35 @@ export class MetricsHelper {
}

async getMetricsData(event: EventBridgeQueryEvent): Promise<MetricData> {
const metricsDataProps: MetricDataQuery[] = event["metrics-data-query"];
const metricsDataProps: MetricDataProps[] = event["metrics-data-query"];
const endTime = new Date(event.time);
const input: GetMetricDataCommandInput = {
MetricDataQueries: metricsDataProps,
StartTime: new Date(endTime.getTime() - ((EXECUTION_DAY == ExecutionDay.DAILY ? 1 : 7) * 86400 * 1000)), // 7 or 1 day(s) previous
EndTime: endTime,
};
return await this.fetchMetricsData(input);
const regionedMetricProps = {};
for (const metric of metricsDataProps) {
const region = metric.region ?? "default";
if (!regionedMetricProps[region]) regionedMetricProps[region] = [];
regionedMetricProps[region].push(metric);
}
let results: MetricData = {}
for (const region in regionedMetricProps) {
const metricProps = regionedMetricProps[region];
const cloudFrontInput: GetMetricDataCommandInput = {
MetricDataQueries: metricProps,
StartTime: new Date(endTime.getTime() - ((EXECUTION_DAY == ExecutionDay.DAILY ? 1 : 7) * 86400 * 1000)), // 7 or 1 day(s) previous
EndTime: endTime,
};
results = {...results, ...await this.fetchMetricsData(cloudFrontInput, region)};
}

return results;
}

private async fetchMetricsData(input: GetMetricDataCommandInput): Promise<MetricData> {
private async fetchMetricsData(input: GetMetricDataCommandInput, region: string): Promise<MetricData> {
let command = new GetMetricDataCommand(input);

let response: GetMetricDataCommandOutput;
const results: MetricData = {};
do {
response = await this.clientHelper.getCwClient().send(command);
response = await this.clientHelper.getCwClient(region).send(command);
console.info(response);

input.MetricDataQueries?.forEach((item, index) => {
Expand Down
7 changes: 4 additions & 3 deletions source/metrics-utils/lambda/helpers/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,15 @@ import { MetricDataQuery } from "@aws-sdk/client-cloudwatch";
import { StartQueryCommandInput } from "@aws-sdk/client-cloudwatch-logs";
import { QueryDefinitionProps } from "aws-cdk-lib/aws-logs";
import { EventBridgeEvent, SQSEvent } from "aws-lambda";

export interface QueryProps extends Pick<StartQueryCommandInput, "queryString" | "logGroupNames"> {}
export interface EventBridgeQueryEvent extends Pick<EventBridgeEvent<"Scheduled Event", {}>, "detail-type" | "time"> {
"metrics-data-query": MetricDataQuery[];
"metrics-data-query": MetricDataProps[];
}

export interface MetricDataProps
extends Pick<MetricDataQuery, "MetricStat" | "Expression" | "Label" | "ReturnData" | "Period"> {}
extends Pick<MetricDataQuery, "MetricStat" | "Expression" | "Label" | "ReturnData" | "Period" | "Id"> {
region?: string
}

export enum ExecutionDay {
DAILY = "*",
Expand Down
3 changes: 3 additions & 0 deletions source/metrics-utils/lib/query-builders.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export function addLambdaInvocationCount(this: SolutionsMetrics, functionName: s
Stat: "Sum",
Period: period,
},
Id: undefined
});
}

Expand Down Expand Up @@ -48,6 +49,8 @@ export function addCloudFrontMetric(
Stat: "Sum",
Period: period,
},
region: "us-east-1",
Id: undefined
});
}

Expand Down
22 changes: 22 additions & 0 deletions source/metrics-utils/test/lambda/helpers/client-helper.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,28 @@ describe("ClientHelper", () => {
expect(CloudWatchClient).toHaveBeenCalledTimes(1);
});

it("should return different CloudWatchClient instances on different provided regions", () => {
const cwClient1 = clientHelper.getCwClient();
const cwClient2 = clientHelper.getCwClient("us-east-1");
expect(cwClient1).not.toBe(cwClient2);
expect(CloudWatchClient).toHaveBeenCalledTimes(2);
});

it("should return identical CloudWatchClient instances when AWS_REGION is set", () => {
process.env.AWS_REGION = "us-east-1";
const cwClient1 = clientHelper.getCwClient();
const cwClient2 = clientHelper.getCwClient("us-east-1");
expect(cwClient1).toBe(cwClient2);
expect(CloudWatchClient).toHaveBeenCalledTimes(1);
});

it("should return different CloudWatchClient instances when AWS_REGION is set", () => {
const cwClient1 = clientHelper.getCwClient("us-west-2");
const cwClient2 = clientHelper.getCwClient("us-east-1");
expect(cwClient1).not.toBe(cwClient2);
expect(CloudWatchClient).toHaveBeenCalledTimes(2);
});

it("should initialize and return a CloudWatchLogsClient instance", () => {
const cwLogsClient = clientHelper.getCwLogsClient();
expect(cwLogsClient).toBeInstanceOf(CloudWatchLogsClient);
Expand Down
Loading

0 comments on commit afc0fb5

Please sign in to comment.