serverless-newrelic-lambda-layers
Advanced tools
Comparing version 0.4.1 to 1.0.0
@@ -15,3 +15,3 @@ "use strict"; | ||
exports.nerdgraphFetch = (apiKey, region, query) => __awaiter(void 0, void 0, void 0, function* () { | ||
const gqlUrl = region.includes("eu") | ||
const gqlUrl = region === "eu" | ||
? "https://api.eu.newrelic.com/graphql" | ||
@@ -18,0 +18,0 @@ : "https://api.newrelic.com/graphql"; |
@@ -34,2 +34,3 @@ "use strict"; | ||
this.managedSecretConfigured = false; | ||
this.mgdPolicyArns = []; // old | ||
this.hooks = this.shouldSkipPlugin() | ||
@@ -48,4 +49,13 @@ ? {} | ||
get config() { | ||
return _.get(this.serverless, "service.custom.newRelic", {}); | ||
return _.get(this.serverless, "service.custom.newRelic", { | ||
nrRegion: "us" | ||
}); | ||
} | ||
get managedPolicyArns() { | ||
const managedPolicyArns = _.get(this.serverless, "service.provider.managedPolicyArns", false); | ||
return managedPolicyArns || []; | ||
} | ||
get resources() { | ||
return _.get(this.serverless, "service.provider.compiledCloudFormationTemplate.Resources", {}); | ||
} | ||
get stage() { | ||
@@ -71,2 +81,14 @@ return ((this.options && this.options.stage) || | ||
} | ||
checkForSecretPolicy() { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
return new integration_1.default(this).checkForManagedSecretPolicy(); | ||
}); | ||
} | ||
regionPolicyValid(current) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
return (current.currentRegionPolicy && | ||
current.currentRegionPolicy[0] && | ||
current.currentRegionPolicy[0].Arn); | ||
}); | ||
} | ||
configureLicenseForExtension() { | ||
@@ -77,8 +99,31 @@ return __awaiter(this, void 0, void 0, function* () { | ||
} | ||
const managedSecret = yield new integration_1.default(this).createManagedSecret(); | ||
if (managedSecret) { | ||
// If the managed secret has already been created, | ||
// there should be policies for it. | ||
const secretAccess = yield this.checkForSecretPolicy(); | ||
let managedSecret; | ||
if (secretAccess.secretExists) { | ||
this.managedSecretConfigured = true; | ||
} | ||
else { | ||
// Secret doesn't exist, so create it | ||
managedSecret = yield new integration_1.default(this).createManagedSecret(); | ||
if (managedSecret && managedSecret.policyArn) { | ||
this.managedSecretConfigured = true; | ||
} | ||
} | ||
if (secretAccess.currentRegionPolicy.length > 0) { | ||
const policyArn = secretAccess.currentRegionPolicy[0].Arn; | ||
this.mgdPolicyArns = [...this.managedPolicyArns, policyArn]; | ||
} | ||
else if (this.managedSecretConfigured) { | ||
this.mgdPolicyArns = [...this.managedPolicyArns, managedSecret.policyArn]; | ||
} | ||
return; | ||
}); | ||
} | ||
applyPolicies(role) { | ||
const existingPolicyArns = role.ManagedPolicyArns || []; | ||
const nrManagedPolicyArns = this.mgdPolicyArns || []; | ||
role.ManagedPolicyArns = [...existingPolicyArns, ...nrManagedPolicyArns]; | ||
} | ||
run() { | ||
@@ -112,2 +157,8 @@ return __awaiter(this, void 0, void 0, function* () { | ||
} | ||
// before adding layer, attach secret access policy | ||
// to each function's execution role: | ||
const resources = this.resources; | ||
Object.keys(resources) | ||
.filter(resourceName => resources[resourceName].Type === `AWS::IAM::Role`) | ||
.forEach(roleResource => this.applyPolicies(resources[roleResource].Properties)); | ||
const funcs = this.functions; | ||
@@ -370,3 +421,3 @@ const promises = []; | ||
this.serverless.cli.log(`creating required newrelic-log-ingestion function in region ${this.region}`); | ||
this.addLogIngestionFunction(); | ||
yield this.addLogIngestionFunction(); | ||
return; | ||
@@ -435,3 +486,3 @@ } | ||
this.serverless.cli.log("Waiting for change set creation to complete, this may take a minute..."); | ||
utils_1.waitForStatus({ | ||
yield utils_1.waitForStatus({ | ||
awsMethod: "describeChangeSet", | ||
@@ -450,4 +501,4 @@ callbackMethod: () => this.executeChangeSet(Id, StackId), | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const { apiKey, accountId } = this.config; | ||
const userData = yield api_1.nerdgraphFetch(apiKey, this.region, api_1.fetchLicenseKey(accountId)); | ||
const { apiKey, accountId, nrRegion } = this.config; | ||
const userData = yield api_1.nerdgraphFetch(apiKey, nrRegion, api_1.fetchLicenseKey(accountId)); | ||
this.licenseKey = _.get(userData, "data.actor.account.licenseKey", null); | ||
@@ -497,3 +548,3 @@ return this.licenseKey; | ||
this.serverless.cli.log("Waiting for newrelic-log-ingestion install to complete, this may take a minute..."); | ||
utils_1.waitForStatus({ | ||
yield utils_1.waitForStatus({ | ||
awsMethod: "describeStacks", | ||
@@ -500,0 +551,0 @@ callbackMethod: () => this.addLogSubscriptions(), |
@@ -25,5 +25,5 @@ "use strict"; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const { accountId, enableIntegration, apiKey } = this.config; | ||
const { accountId, enableIntegration, apiKey, nrRegion } = this.config; | ||
const { linkedAccount = `New Relic Lambda Integration - ${accountId}` } = this.config; | ||
const integrationData = yield api_1.nerdgraphFetch(apiKey, this.region, api_1.fetchLinkedAccounts(accountId)); | ||
const integrationData = yield api_1.nerdgraphFetch(apiKey, nrRegion, api_1.fetchLinkedAccounts(accountId)); | ||
const linkedAccounts = _.get(integrationData, "data.actor.account.cloud.linkedAccounts", []); | ||
@@ -48,5 +48,28 @@ const externalId = yield this.getCallerIdentity(); | ||
} | ||
checkForManagedSecretPolicy() { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const thisRegionPolicy = `NewRelic-ViewLicenseKey-${this.region}`; | ||
const regionFilter = policy => policy.PolicyName.match(thisRegionPolicy); | ||
try { | ||
const params = { | ||
Scope: `Local` | ||
}; | ||
const results = yield this.awsProvider.request("IAM", "listPolicies", params); | ||
const currentRegionPolicy = results.Policies.filter(regionFilter); | ||
return { | ||
currentRegionPolicy, | ||
secretExists: currentRegionPolicy.length > 0 | ||
}; | ||
} | ||
catch (err) { | ||
this.serverless.cli.log(`Problem getting list of current policies. ${JSON.stringify(err)}`); | ||
} | ||
}); | ||
} | ||
createManagedSecret() { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const stackName = `NewRelicLicenseKeySecret`; | ||
const policyName = `NewRelic-ViewLicenseKey`; | ||
const externalId = yield this.getCallerIdentity(); | ||
const policyArn = `arn:aws:iam::${externalId}:policy/${policyName}-${this.region}`; | ||
try { | ||
@@ -64,2 +87,6 @@ const policy = yield utils_1.fetchPolicy("nr-license-key-secret.yaml"); | ||
ParameterValue: this.region | ||
}, | ||
{ | ||
ParameterKey: "PolicyName", | ||
ParameterValue: policyName | ||
} | ||
@@ -71,3 +98,3 @@ ], | ||
const { StackId } = yield this.awsProvider.request("CloudFormation", "createStack", params); | ||
return StackId; | ||
return { stackId: StackId, stackName, policyName, policyArn }; | ||
} | ||
@@ -79,3 +106,4 @@ catch (err) { | ||
`${err}`.indexOf("already exists") > -1) { | ||
return "Already created"; | ||
this.serverless.cli.log(JSON.stringify(err)); | ||
return { stackId: "already created", stackName, policyName }; | ||
} | ||
@@ -94,6 +122,6 @@ this.serverless.cli.log(`Something went wrong while creating NewRelicLicenseKeySecret: ${err}`); | ||
} | ||
const { accountId, apiKey } = this.config; | ||
const { accountId, apiKey, nrRegion } = this.config; | ||
const { linkedAccount = `New Relic Lambda Integration - ${accountId}` } = this.config; | ||
this.serverless.cli.log(`Enabling New Relic integration for linked account: ${linkedAccount} and aws account: ${externalId}.`); | ||
const res = yield api_1.nerdgraphFetch(apiKey, this.region, api_1.cloudLinkAccountMutation(accountId, roleArn, linkedAccount)); | ||
const res = yield api_1.nerdgraphFetch(apiKey, nrRegion, api_1.cloudLinkAccountMutation(accountId, roleArn, linkedAccount)); | ||
const { linkedAccounts, errors } = _.get(res, "data.cloudLinkAccount", { | ||
@@ -103,6 +131,6 @@ errors: ["data.cloudLinkAccount missing in response"] | ||
if (errors && errors.length) { | ||
throw new Error(errors); | ||
throw new Error(JSON.stringify(errors)); | ||
} | ||
const linkedAccountId = _.get(linkedAccounts, "[0].id"); | ||
const integrationRes = yield api_1.nerdgraphFetch(apiKey, this.region, api_1.cloudServiceIntegrationMutation(accountId, "aws", "lambda", linkedAccountId)); | ||
const integrationRes = yield api_1.nerdgraphFetch(apiKey, nrRegion, api_1.cloudServiceIntegrationMutation(accountId, "aws", "lambda", linkedAccountId)); | ||
const { errors: integrationErrors } = _.get(integrationRes, "data.cloudConfigureIntegration", { | ||
@@ -112,3 +140,3 @@ errors: ["data.cloudConfigureIntegration missing in response"] | ||
if (integrationErrors && integrationErrors.length) { | ||
throw new Error(integrationErrors); | ||
throw new Error(JSON.stringify(integrationErrors)); | ||
} | ||
@@ -118,3 +146,3 @@ this.serverless.cli.log(`New Relic AWS Lambda cloud integration created successfully.`); | ||
catch (err) { | ||
this.serverless.cli.log(`Error while creating the New Relic AWS Lambda cloud integration: ${err}.`); | ||
this.serverless.cli.log(`Error while creating the New Relic AWS Lambda cloud integration: ${JSON.stringify(err)}.`); | ||
} | ||
@@ -184,3 +212,3 @@ }); | ||
catch (err) { | ||
this.serverless.cli.log(`Something went wrong while creating NewRelicLambdaIntegrationRole: ${err}`); | ||
this.serverless.cli.log(`Something went wrong while creating NewRelicLambdaIntegrationRole: ${JSON.stringify(err)}`); | ||
} | ||
@@ -187,0 +215,0 @@ }); |
{ | ||
"name": "serverless-newrelic-lambda-layers", | ||
"version": "0.4.1", | ||
"version": "1.0.0", | ||
"description": "Serverless plugin for NewRelic APM AWS Lambda layers.", | ||
@@ -44,7 +44,7 @@ "main": "dist/index.js", | ||
"husky": "^4.3.0", | ||
"jest": "^25.5.4", | ||
"jest": "^26.6.3", | ||
"prettier": "^1.19.1", | ||
"ramda": "^0.27.1", | ||
"serverless": "^1.83.0", | ||
"ts-jest": "^25.5.1", | ||
"serverless": "^2.19.0", | ||
"ts-jest": "^26.4.4", | ||
"tslint": "^5.20.1", | ||
@@ -51,0 +51,0 @@ "tslint-config-prettier": "^1.18.0", |
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
68315
930
0