Skip to content

Commit 11c4a7b

Browse files
authored
feat(credential-provider-imds): accept custom logger (#3409)
* fix(types): logger interface * feat(credential-provider-imds): accept custom logger * chore: remove unused imports
1 parent b20d431 commit 11c4a7b

File tree

10 files changed

+56
-25
lines changed

10 files changed

+56
-25
lines changed

packages/credential-provider-imds/src/fromInstanceMetadata.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ const IMDS_TOKEN_PATH = "/latest/api/token";
1818
* Instance Metadata Service
1919
*/
2020
export const fromInstanceMetadata = (init: RemoteProviderInit = {}): Provider<InstanceMetadataCredentials> =>
21-
staticStabilityProvider(getInstanceImdsProvider(init));
21+
staticStabilityProvider(getInstanceImdsProvider(init), { logger: init.logger });
2222

2323
const getInstanceImdsProvider = (init: RemoteProviderInit) => {
2424
// when set to true, metadata service will not fetch token

packages/credential-provider-imds/src/remoteProvider/RemoteProviderInit.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { Logger } from "@aws-sdk/types";
2+
13
export const DEFAULT_TIMEOUT = 1000;
24

35
// The default in AWS SDK for Python and CLI (botocore) is no retry or one attempt
@@ -16,7 +18,9 @@ export interface RemoteProviderConfig {
1618
maxRetries: number;
1719
}
1820

19-
export type RemoteProviderInit = Partial<RemoteProviderConfig>;
21+
export interface RemoteProviderInit extends Partial<RemoteProviderConfig> {
22+
logger?: Logger;
23+
}
2024

2125
export const providerConfigFromInit = ({
2226
maxRetries = DEFAULT_MAX_RETRIES,

packages/credential-provider-imds/src/utils/getExtendedInstanceMetadataCredentials.spec.ts

+8-5
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { Logger } from "@aws-sdk/types";
2+
13
import { getExtendedInstanceMetadataCredentials } from "./getExtendedInstanceMetadataCredentials";
24

35
describe("getExtendedInstanceMetadataCredentials()", () => {
@@ -6,9 +8,11 @@ describe("getExtendedInstanceMetadataCredentials()", () => {
68
accessKeyId: "key",
79
secretAccessKey: "secret",
810
};
11+
const logger: Logger = {
12+
warn: jest.fn(),
13+
} as any;
914

1015
beforeEach(() => {
11-
jest.spyOn(global.console, "warn").mockImplementation(() => {});
1216
jest.spyOn(global.Math, "random");
1317
nowMock = jest.spyOn(Date, "now").mockReturnValueOnce(new Date("2022-02-22T00:00:00Z").getTime());
1418
});
@@ -20,7 +24,7 @@ describe("getExtendedInstanceMetadataCredentials()", () => {
2024
it("should extend the expiration random time(~15 mins) from now", () => {
2125
const anyDate: Date = "any date" as unknown as Date;
2226
(Math.random as jest.Mock).mockReturnValue(0.5);
23-
expect(getExtendedInstanceMetadataCredentials({ ...staticSecret, expiration: anyDate })).toEqual({
27+
expect(getExtendedInstanceMetadataCredentials({ ...staticSecret, expiration: anyDate }, logger)).toEqual({
2428
...staticSecret,
2529
originalExpiration: anyDate,
2630
expiration: new Date("2022-02-22T00:17:30Z"),
@@ -30,8 +34,7 @@ describe("getExtendedInstanceMetadataCredentials()", () => {
3034

3135
it("should print warning message when extending the credentials", () => {
3236
const anyDate: Date = "any date" as unknown as Date;
33-
getExtendedInstanceMetadataCredentials({ ...staticSecret, expiration: anyDate });
34-
// TODO: fill the doc link
35-
expect(console.warn).toBeCalledWith(expect.stringContaining("Attempting credential expiration extension"));
37+
getExtendedInstanceMetadataCredentials({ ...staticSecret, expiration: anyDate }, logger);
38+
expect(logger.warn).toBeCalledWith(expect.stringContaining("Attempting credential expiration extension"));
3639
});
3740
});

packages/credential-provider-imds/src/utils/getExtendedInstanceMetadataCredentials.ts

+5-4
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,20 @@
1+
import { Logger } from "@aws-sdk/types";
2+
13
import { InstanceMetadataCredentials } from "../types";
24

35
const STATIC_STABILITY_REFRESH_INTERVAL_SECONDS = 15 * 60;
46
const STATIC_STABILITY_REFRESH_INTERVAL_JITTER_WINDOW_SECONDS = 5 * 60;
5-
// TODO
67
const STATIC_STABILITY_DOC_URL = "https://docs.aws.amazon.com/sdkref/latest/guide/feature-static-credentials.html";
78

89
export const getExtendedInstanceMetadataCredentials = (
9-
credentials: InstanceMetadataCredentials
10+
credentials: InstanceMetadataCredentials,
11+
logger: Logger
1012
): InstanceMetadataCredentials => {
1113
const refreshInterval =
1214
STATIC_STABILITY_REFRESH_INTERVAL_SECONDS +
1315
Math.floor(Math.random() * STATIC_STABILITY_REFRESH_INTERVAL_JITTER_WINDOW_SECONDS);
1416
const newExpiration = new Date(Date.now() + refreshInterval * 1000);
15-
// ToDo: Call warn function on logger from configuration
16-
console.warn(
17+
logger.warn(
1718
"Attempting credential expiration extension due to a credential service availability issue. A refresh of these " +
1819
"credentials will be attempted after ${new Date(newExpiration)}.\nFor more information, please visit: " +
1920
STATIC_STABILITY_DOC_URL

packages/credential-provider-imds/src/utils/staticStabilityProvider.spec.ts

+12
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { Logger } from "@aws-sdk/types";
2+
13
import { getExtendedInstanceMetadataCredentials } from "./getExtendedInstanceMetadataCredentials";
24
import { staticStabilityProvider } from "./staticStabilityProvider";
35

@@ -84,4 +86,14 @@ describe("staticStabilityProvider", () => {
8486
expect(getExtendedInstanceMetadataCredentials).toBeCalledTimes(repeat);
8587
expect(console.warn).not.toBeCalled();
8688
});
89+
90+
it("should allow custom logger to print warning messages", async () => {
91+
const provider = jest.fn().mockResolvedValueOnce(mockCreds).mockRejectedValue("Error");
92+
const logger = { warn: jest.fn() } as unknown as Logger;
93+
const stableProvider = staticStabilityProvider(provider, { logger });
94+
expect(await stableProvider()).toEqual(mockCreds); // load initial creds
95+
await stableProvider();
96+
expect(logger.warn).toBeCalledTimes(1);
97+
expect(console.warn).toBeCalledTimes(0);
98+
});
8799
});

packages/credential-provider-imds/src/utils/staticStabilityProvider.ts

+11-6
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Credentials, Provider } from "@aws-sdk/types";
1+
import { Credentials, Logger, Provider } from "@aws-sdk/types";
22

33
import { InstanceMetadataCredentials } from "../types";
44
import { getExtendedInstanceMetadataCredentials } from "./getExtendedInstanceMetadataCredentials";
@@ -13,21 +13,26 @@ import { getExtendedInstanceMetadataCredentials } from "./getExtendedInstanceMet
1313
* @returns A credential provider that supports static stability
1414
*/
1515
export const staticStabilityProvider = (
16-
provider: Provider<InstanceMetadataCredentials>
16+
provider: Provider<InstanceMetadataCredentials>,
17+
options: {
18+
logger?: Logger;
19+
} = {}
1720
): Provider<InstanceMetadataCredentials> => {
21+
// Unlike normal SDK logger message, the key extension message must be transparent to users.
22+
// When customer doesn't supply a custom logger, we need to log the warnings to console.
23+
const logger = options?.logger || console;
1824
let pastCredentials: InstanceMetadataCredentials;
1925
return async () => {
2026
let credentials: InstanceMetadataCredentials;
2127
try {
2228
credentials = await provider();
2329
if (credentials.expiration && credentials.expiration.getTime() < Date.now()) {
24-
credentials = getExtendedInstanceMetadataCredentials(credentials);
30+
credentials = getExtendedInstanceMetadataCredentials(credentials, logger);
2531
}
2632
} catch (e) {
2733
if (pastCredentials) {
28-
// ToDo: Call warn function on logger from configuration
29-
console.warn("Credential renew failed: ", e);
30-
credentials = getExtendedInstanceMetadataCredentials(pastCredentials);
34+
logger.warn("Credential renew failed: ", e);
35+
credentials = getExtendedInstanceMetadataCredentials(pastCredentials, logger);
3136
} else {
3237
throw e;
3338
}

packages/middleware-logger/package.json

-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
"tslib": "^2.3.0"
2525
},
2626
"devDependencies": {
27-
"@aws-sdk/protocol-http": "*",
2827
"@tsconfig/recommended": "1.0.1",
2928
"@types/node": "^10.0.0",
3029
"concurrently": "7.0.0",

packages/middleware-logger/src/loggerMiddleware.ts

-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { HttpResponse } from "@aws-sdk/protocol-http";
21
import {
32
AbsoluteLocation,
43
HandlerExecutionContext,

packages/middleware-signing/src/configurations.ts

+10-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
11
import { memoize } from "@aws-sdk/property-provider";
22
import { SignatureV4, SignatureV4CryptoInit, SignatureV4Init } from "@aws-sdk/signature-v4";
3-
import { Credentials, HashConstructor, Provider, RegionInfo, RegionInfoProvider, RequestSigner } from "@aws-sdk/types";
4-
import { options } from "yargs";
3+
import {
4+
Credentials,
5+
HashConstructor,
6+
Logger,
7+
Provider,
8+
RegionInfo,
9+
RegionInfoProvider,
10+
RequestSigner,
11+
} from "@aws-sdk/types";
512

613
// 5 minutes buffer time the refresh the credential before it really expires
714
const CREDENTIAL_EXPIRE_WINDOW = 300000;
@@ -83,6 +90,7 @@ interface SigV4PreviouslyResolved {
8390
region: string | Provider<string>;
8491
signingName: string;
8592
sha256: HashConstructor;
93+
logger?: Logger;
8694
}
8795

8896
export interface AwsAuthResolvedConfig {

packages/types/src/logger.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ export interface LoggerOptions {
2121
* throughout the middleware stack.
2222
*/
2323
export interface Logger {
24-
debug(content: object): void;
25-
info(content: object): void;
26-
warn(content: object): void;
27-
error(content: object): void;
24+
debug(...content: any[]): void;
25+
info(...content: any[]): void;
26+
warn(...content: any[]): void;
27+
error(...content: any[]): void;
2828
}

0 commit comments

Comments
 (0)