Skip to content

refactor(serverless-api): update user-agent string for better debugging #292

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

Merged
merged 5 commits into from
Jul 9, 2021
Merged
Show file tree
Hide file tree
Changes from 4 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
12 changes: 12 additions & 0 deletions packages/plugin-assets/src/client.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
const pkgJson = require('../package.json');
const { TwilioServerlessApiClient } = require('@twilio-labs/serverless-api');

function getTwilioClient(apiKey, apiSecret) {
return new TwilioServerlessApiClient({
username: apiKey,
password: apiSecret,
userAgentExtensions: [`@twilio-labs/plugin-assets/${pkgJson.version}`],
});
}

module.exports = { getTwilioClient: getTwilioClient };
7 changes: 2 additions & 5 deletions packages/plugin-assets/src/init.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
const { TwilioServerlessApiClient } = require('@twilio-labs/serverless-api');
const {
createService,
} = require('@twilio-labs/serverless-api/dist/api/services');
Expand All @@ -9,6 +8,7 @@ const {
const { TwilioCliError } = require('@twilio/cli-core').services.error;

const { couldNotGetEnvironment } = require('./errorMessages');
const { getTwilioClient } = require('./client');

async function createServiceAndEnvironment(client, serviceName) {
const serviceSid = await createService(serviceName, client);
Expand Down Expand Up @@ -36,10 +36,7 @@ async function init({
serviceName,
}) {
logger.debug('Loading config');
const client = new TwilioServerlessApiClient({
username: apiKey,
password: apiSecret,
});
const client = getTwilioClient(apiKey, apiSecret);
const config = await pluginConfig.getConfig();
if (
config[accountSid] &&
Expand Down
7 changes: 2 additions & 5 deletions packages/plugin-assets/src/list.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
const { TwilioServerlessApiClient } = require('@twilio-labs/serverless-api');
const {
getEnvironment,
} = require('@twilio-labs/serverless-api/dist/api/environments');
const { getBuild } = require('@twilio-labs/serverless-api/dist/api/builds');
const { TwilioCliError } = require('@twilio/cli-core').services.error;
const { couldNotGetEnvironment, couldNotGetBuild } = require('./errorMessages');
const { getTwilioClient } = require('./client');

async function list({ pluginConfig, apiKey, apiSecret, accountSid, logger }) {
let environment;
Expand All @@ -15,10 +15,7 @@ async function list({ pluginConfig, apiKey, apiSecret, accountSid, logger }) {
config[accountSid].environmentSid
) {
const { serviceSid, environmentSid } = config[accountSid];
const client = new TwilioServerlessApiClient({
username: apiKey,
password: apiSecret,
});
const client = getTwilioClient(apiKey, apiSecret);
try {
logger.debug(
`Fetching environment with sid ${environmentSid} from service with sid ${serviceSid}`
Expand Down
8 changes: 3 additions & 5 deletions packages/plugin-assets/src/upload.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
const ora = require('ora');
const inquirer = require('inquirer');
const { TwilioServerlessApiClient } = require('@twilio-labs/serverless-api');
const { TwilioCliError } = require('@twilio/cli-core').services.error;
const {
getEnvironment,
Expand Down Expand Up @@ -31,6 +30,8 @@ const {
debugFlagMessage,
} = require('./errorMessages');

const { getTwilioClient } = require('./client');

function getUtils(spinner, logger) {
function debug(message) {
const wasSpinning = spinner.isSpinning;
Expand Down Expand Up @@ -328,10 +329,7 @@ async function upload({
config[accountSid].environmentSid
) {
const { serviceSid, environmentSid } = config[accountSid];
const client = new TwilioServerlessApiClient({
username: apiKey,
password: apiSecret,
});
const client = getTwilioClient(apiKey, apiSecret);
const environment = await getEnvironmentWithClient(
client,
environmentSid,
Expand Down
7 changes: 7 additions & 0 deletions packages/plugin-serverless/src/utils.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
const path = require('path');
const camelCase = require('lodash.camelcase');
const { flags } = require('@oclif/command');
const pkgJson = require('../package.json');

function convertYargsOptionsToOclifFlags(options) {
const aliasMap = new Map();
Expand Down Expand Up @@ -73,6 +74,10 @@ function normalizeFlags(flags, aliasMap, argv) {

function createExternalCliOptions(flags, twilioClient) {
const profile = flags.profile;
const pluginInfo = {
version: pkgJson.version,
name: pkgJson.name,
};

if (
(typeof flags.username === 'string' && flags.username.length > 0) ||
Expand All @@ -85,6 +90,7 @@ function createExternalCliOptions(flags, twilioClient) {
profile: undefined,
logLevel: undefined,
outputFormat: undefined,
pluginInfo,
};
}

Expand All @@ -95,6 +101,7 @@ function createExternalCliOptions(flags, twilioClient) {
profile,
logLevel: undefined,
outputFormat: undefined,
pluginInfo,
};
}

Expand Down
14 changes: 11 additions & 3 deletions packages/serverless-api/src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ import {
import { DeployStatus } from './types/consts';
import { ClientApiError, convertApiErrorsAndThrow } from './utils/error';
import { getListOfFunctionsAndAssets, SearchConfig } from './utils/fs';
import getUserAgent from './utils/user-agent';

const log = debug('twilio-serverless-api:client');

Expand All @@ -87,7 +88,7 @@ export function createGotClient(config: ClientConfig): GotClient {
username: username,
password: password,
headers: {
'User-Agent': 'twilio-serverless-api',
'User-Agent': getUserAgent(config.userAgentExtensions),
},
}) as GotClient;
if (process.env.HTTP_PROXY) {
Expand Down Expand Up @@ -137,6 +138,7 @@ export class TwilioServerlessApiClient extends events.EventEmitter {
debug.enable(process.env.DEBUG || '');
super();
this.config = config;

this.client = createGotClient(config);
this.limit = pLimit(config.concurrency || CONCURRENCY);
}
Expand Down Expand Up @@ -343,8 +345,13 @@ export class TwilioServerlessApiClient extends events.EventEmitter {
*/
async activateBuild(activateConfig: ActivateConfig): Promise<ActivateResult> {
try {
let { buildSid, targetEnvironment, serviceSid, sourceEnvironment, env } =
activateConfig;
let {
buildSid,
targetEnvironment,
serviceSid,
sourceEnvironment,
env,
} = activateConfig;

if (!buildSid && !sourceEnvironment) {
const error = new Error(
Expand Down Expand Up @@ -685,6 +692,7 @@ export class TwilioServerlessApiClient extends events.EventEmitter {
statusCodes: [429],
errorCodes: [],
};

return this.limit(() => this.client[method](path, options));
}
}
Expand Down
4 changes: 4 additions & 0 deletions packages/serverless-api/src/types/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ type BaseClientConfig = {
* Number of retry attempts the client will make on a failure
*/
retryLimit?: number;
/**
* Additional information to pass to the User-Agent. !!!Should not contain sensitive information
*/
userAgentExtensions?: string[];
};

export type AccountSidConfig = BaseClientConfig & {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import pkgJson from '../package-info';

test('imports package.json information', () => {
const pkgJsonSource = require('../../../package.json');
expect(pkgJson).toEqual(pkgJsonSource);
});
39 changes: 39 additions & 0 deletions packages/serverless-api/src/utils/__tests__/user-agent.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { getUserAgent } from '../user-agent';

jest.mock('../package-info', () => {
return {
name: '@twilio-labs/serverless-api-test',
version: '1.0.0-test',
};
});

jest.mock('os', () => {
return {
platform: () => 'darwin',
arch: () => 'x64',
};
});

const nodeVersion = process.version;

describe('getUserAgent', () => {
test('should return the right base information', () => {
expect(getUserAgent()).toEqual(
`@twilio-labs/serverless-api-test/1.0.0-test (darwin x64) node/${nodeVersion}`
);
});

test('adds extensions and correctly resets extensions', () => {
expect(
getUserAgent([
'twilio-run/2.0.0-test',
'@twilio-labs/plugin-serverless/1.1.0-test',
])
).toEqual(
`@twilio-labs/serverless-api-test/1.0.0-test (darwin x64) node/${nodeVersion} twilio-run/2.0.0-test @twilio-labs/plugin-serverless/1.1.0-test`
);
expect(getUserAgent()).toEqual(
`@twilio-labs/serverless-api-test/1.0.0-test (darwin x64) node/${nodeVersion}`
);
});
});
9 changes: 9 additions & 0 deletions packages/serverless-api/src/utils/package-info.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import fs from 'fs';
import path from 'path';
import { PackageJson } from 'type-fest';

const pkgJson: PackageJson = JSON.parse(
fs.readFileSync(path.resolve(__dirname, '../../package.json'), 'utf8')
);

export default pkgJson;
15 changes: 15 additions & 0 deletions packages/serverless-api/src/utils/user-agent.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import os from 'os';
import pkgJson from './package-info';

export function getUserAgent(extensions: string[] = []) {
const name = pkgJson.name || '@twilio-labs/serverless-api';
const version = pkgJson.version || '0.0.0';
const osName = os.platform() || 'unknown';
const osArch = os.arch() || 'unknown';
const nodeVersion = process.version || '0.0.0';
const extensionString =
extensions.length > 0 ? ' ' + extensions.join(' ') : '';
return `${name}/${version} (${osName} ${osArch}) node/${nodeVersion}${extensionString}`;
}

export default getUserAgent;
20 changes: 12 additions & 8 deletions packages/serverless-twilio-runtime/util/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@

const {
TwilioServerlessApiClient,
utils
utils,
} = require('@twilio-labs/serverless-api');
const path = require('path');
const { readFile } = utils;
const { logMessage } = require('./log');
const pkgJson = require('../package.json');

/**
* Initialize the Twilio client and attach serverless logging to it
Expand All @@ -19,10 +20,13 @@ function getTwilioClient(serverless) {

const client = new TwilioServerlessApiClient({
accountSid,
authToken
authToken,
userAgentExtensions: [
`@twilio-labs/serverless-twilio-runtime/${pkgJson.version}`,
],
});

client.on('status-update', evt => {
client.on('status-update', (evt) => {
logMessage(serverless, evt.message);
});

Expand All @@ -40,13 +44,13 @@ async function getTwilioDeployConfig(serverless, options = {}) {
const config = {
env: serverless.service.provider.environmentVars || {},
pkgJson: {
dependencies: serverless.service.provider.dependencies
dependencies: serverless.service.provider.dependencies,
},
serviceName: serverless.service.service,
functionsEnv: serverless.service.provider.environment || 'dev',
assets: [],
functions: [],
overrideExistingService: true
overrideExistingService: true,
};

if (serverless.service.functions) {
Expand Down Expand Up @@ -134,11 +138,11 @@ async function getEnvironment(
) {
const { environments } = await twilioServerlessClient.list({
types: ['environments'],
serviceName
serviceName,
});

const environment = environments.find(
env => env.domain_suffix === environmentName
(env) => env.domain_suffix === environmentName
);

if (!environment) {
Expand All @@ -154,5 +158,5 @@ module.exports = {
getEnvironment,
getTwilioClient,
getTwilioDeployConfig,
readFile
readFile,
};
4 changes: 4 additions & 0 deletions packages/twilio-run/src/commands/shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,8 @@ export type ExternalCliOptions = {
project?: string;
logLevel?: string;
outputFormat?: string;
pluginInfo?: {
name: string;
version: string;
};
};
2 changes: 2 additions & 0 deletions packages/twilio-run/src/config/deploy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
readPackageJsonContent,
} from './utils';
import { mergeFlagsAndConfig } from './utils/mergeFlagsAndConfig';
import { getUserAgentExtensions } from './utils/userAgentExtensions';

export type DeployLocalProjectConfig = ApiDeployLocalProjectConfig & {
username: string;
Expand Down Expand Up @@ -131,5 +132,6 @@ export async function getConfigFromFlags(
region,
edge,
runtime,
userAgentExtensions: getUserAgentExtensions('deploy', externalCliOptions),
};
}
4 changes: 3 additions & 1 deletion packages/twilio-run/src/config/list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
readLocalEnvFile,
} from './utils';
import { mergeFlagsAndConfig } from './utils/mergeFlagsAndConfig';
import { getUserAgentExtensions } from './utils/userAgentExtensions';

export type ListConfig = ApiListConfig & {
username: string;
Expand Down Expand Up @@ -99,11 +100,12 @@ export async function getConfigFromFlags(
serviceName,
environment: flags.environment,
properties: flags.properties
? flags.properties.split(',').map(x => x.trim())
? flags.properties.split(',').map((x) => x.trim())
: undefined,
extendedOutput: flags.extendedOutput,
types,
region,
edge,
userAgentExtensions: getUserAgentExtensions('list', externalCliOptions),
};
}
2 changes: 2 additions & 0 deletions packages/twilio-run/src/config/logs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { getFunctionServiceSid } from '../serverless-api/utils';
import { readSpecializedConfig } from './global';
import { getCredentialsFromFlags, readLocalEnvFile } from './utils';
import { mergeFlagsAndConfig } from './utils/mergeFlagsAndConfig';
import { getUserAgentExtensions } from './utils/userAgentExtensions';

export type LogsConfig = ClientConfig &
ApiLogsConfig & {
Expand Down Expand Up @@ -104,5 +105,6 @@ export async function getConfigFromFlags(
region,
edge,
logCacheSize: flags.logCacheSize,
userAgentExtensions: getUserAgentExtensions('logs', externalCliOptions),
};
}
Loading