Skip to content

Commit

Permalink
change filename
Browse files Browse the repository at this point in the history
  • Loading branch information
austencollins committed Aug 31, 2020
1 parent bfbedc8 commit d9620ee
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 102 deletions.
File renamed without changes.
21 changes: 11 additions & 10 deletions src/serverless.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const {
createOrUpdateMetaRole,
deleteLambdaFunction,
removeAllRoles,
getMetrics,
getMetrics
} = require('./utils')

class AwsLambda extends Component {
Expand Down Expand Up @@ -59,8 +59,8 @@ class AwsLambda extends Component {

await Promise.all([
createOrUpdateFunctionRole(this, inputs, clients),
createOrUpdateMetaRole(this, inputs, clients, this.accountId),
]);
createOrUpdateMetaRole(this, inputs, clients, this.accountId)
])

console.log(
`Checking if an AWS Lambda function has already been created with name: ${inputs.name}`
Expand Down Expand Up @@ -114,7 +114,6 @@ class AwsLambda extends Component {
* @param {*} inputs
*/
async remove(inputs = {}) {

// this error message assumes that the user is running via the CLI though...
if (Object.keys(this.credentials.aws).length === 0) {
const msg = `Credentials not found. Make sure you have a .env file in the cwd. - Docs: https://git.io/JvArp`
Expand All @@ -126,13 +125,15 @@ class AwsLambda extends Component {
return
}

const clients = getClients(this.credentials.aws, this.state.region);
const clients = getClients(this.credentials.aws, this.state.region)

await removeAllRoles(this, clients);
await removeAllRoles(this, clients)

console.log(`Removing lambda ${this.state.name} from the ${this.state.region} region.`)
await deleteLambdaFunction(clients.lambda, this.state.name)
console.log(`Successfully removed lambda ${this.state.name} from the ${this.state.region} region.`)
console.log(
`Successfully removed lambda ${this.state.name} from the ${this.state.region} region.`
)

this.state = {}
return {}
Expand All @@ -144,7 +145,7 @@ class AwsLambda extends Component {
async metrics(inputs = {}) {
// Validate
if (!inputs.rangeStart || !inputs.rangeEnd) {
throw new Error('rangeStart and rangeEnd are require inputs');
throw new Error('rangeStart and rangeEnd are require inputs')
}

const result = await getMetrics(
Expand All @@ -153,9 +154,9 @@ class AwsLambda extends Component {
this.state.name,
inputs.rangeStart,
inputs.rangeEnd
);
)

return result;
return result
}
}

Expand Down
165 changes: 78 additions & 87 deletions src/utils.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
const https = require('https');
const https = require('https')
const AWS = require('@serverless/aws-sdk-extra')
const { equals, not, pick } = require('ramda')
const { readFile } = require('fs-extra')

const agent = new https.Agent({
keepAlive: true,
});
keepAlive: true
})

/**
* Sleep
Expand All @@ -28,9 +28,9 @@ const randomId = Math.random()
const getClients = (credentials = {}, region) => {
AWS.config.update({
httpOptions: {
agent,
},
});
agent
}
})

const extras = new AWS.Extras({ credentials, region })
const iam = new AWS.IAM({ credentials, region })
Expand All @@ -45,12 +45,12 @@ const getClients = (credentials = {}, region) => {
* @param {*} instance
*/
const prepareInputs = (inputs, instance) => {

return {
name:
inputs.name || instance.state.name || `${instance.name}-${instance.stage}-${randomId}`,
name: inputs.name || instance.state.name || `${instance.name}-${instance.stage}-${randomId}`,
roleName: inputs.roleName,
description: inputs.description || `An AWS Lambda function from the AWS Lambda Serverless Framework Component. Name: "${instance.name}" Stage: "${instance.stage}"`,
description:
inputs.description ||
`An AWS Lambda function from the AWS Lambda Serverless Framework Component. Name: "${instance.name}" Stage: "${instance.stage}"`,
memory: inputs.memory || 1028,
timeout: inputs.timeout || 10,
src: inputs.src || null,
Expand All @@ -76,46 +76,44 @@ const createOrUpdateFunctionRole = async (instance, inputs, clients) => {
if (inputs.roleName) {
console.log(
`Verifying the provided IAM Role with the name: ${inputs.roleName} in the inputs exists...`
);
)

const userRole = await clients.extras.getRole({ roleName: inputs.roleName });
const userRoleArn = userRole && userRole.Role && userRole.Role.Arn ? userRole.Role.Arn : null; // Don't save user provided role to state, always reference it as an input, in case it changes
const userRole = await clients.extras.getRole({ roleName: inputs.roleName })
const userRoleArn = userRole && userRole.Role && userRole.Role.Arn ? userRole.Role.Arn : null // Don't save user provided role to state, always reference it as an input, in case it changes

// If user role exists, save it to state so it can be used for the create/update lambda logic later
if (userRoleArn) {
console.log(`The provided IAM Role with the name: ${inputs.roleName} in the inputs exists.`);
instance.state.userRoleArn = userRoleArn;
console.log(`The provided IAM Role with the name: ${inputs.roleName} in the inputs exists.`)
instance.state.userRoleArn = userRoleArn

// Save AWS Account ID by fetching the role ID
// TODO: This may not work with cross-account roles.
instance.state.awsAccountId = instance.state.userRoleArn.split(':')[4];
instance.state.awsAccountId = instance.state.userRoleArn.split(':')[4]

// Be sure to delete defaultLambdaRoleArn data, if it exists
if (instance.state.defaultLambdaRoleArn) {
delete instance.state.defaultLambdaRoleArn
}
} else {
throw new Error(
`The provided IAM Role with the name: ${inputs.roleName} could not be found.`
);
throw new Error(`The provided IAM Role with the name: ${inputs.roleName} could not be found.`)
}
} else {
// Create a default role with basic Lambda permissions

const defaultLambdaRoleName = `${inputs.name}-lambda-role`;
const defaultLambdaRoleName = `${inputs.name}-lambda-role`
console.log(
`IAM Role not found. Creating or updating a default role with the name: ${defaultLambdaRoleName}`
);
)

const result = await clients.extras.deployRole({
roleName: defaultLambdaRoleName,
service: ['lambda.amazonaws.com'],
policy: 'arn:aws:iam::aws:policy/AWSLambdaFullAccess',
});
policy: 'arn:aws:iam::aws:policy/AWSLambdaFullAccess'
})

instance.state.defaultLambdaRoleName = defaultLambdaRoleName;
instance.state.defaultLambdaRoleArn = result.roleArn;
instance.state.awsAccountId = instance.state.defaultLambdaRoleArn.split(':')[4];
instance.state.defaultLambdaRoleName = defaultLambdaRoleName
instance.state.defaultLambdaRoleArn = result.roleArn
instance.state.awsAccountId = instance.state.defaultLambdaRoleArn.split(':')[4]

// Be sure to delete userRole data, if it exists
if (instance.state.userRoleArn) {
Expand All @@ -124,30 +122,30 @@ const createOrUpdateFunctionRole = async (instance, inputs, clients) => {

console.log(
`Default Lambda IAM Role created or updated with ARN ${instance.state.defaultLambdaRoleArn}`
);
)
}
};
}

/*
* Ensure the Meta IAM Role exists
*/
const createOrUpdateMetaRole = async (instance, inputs, clients, serverlessAccountId) => {
// Create or update Meta Role for monitoring and more, if option is enabled. It's enabled by default.
if (inputs.monitoring || typeof inputs.monitoring === 'undefined') {
console.log('Creating or updating the meta IAM Role...');
console.log('Creating or updating the meta IAM Role...')

const roleName = `${instance.name}-meta-role`;
const roleName = `${instance.name}-meta-role`

const assumeRolePolicyDocument = {
Version: '2012-10-17',
Statement: {
Effect: 'Allow',
Principal: {
AWS: `arn:aws:iam::${serverlessAccountId}:root`, // Serverless's Components account
AWS: `arn:aws:iam::${serverlessAccountId}:root` // Serverless's Components account
},
Action: 'sts:AssumeRole',
},
};
Action: 'sts:AssumeRole'
}
}

// Create a policy that only can access APIGateway and Lambda metrics, logs from CloudWatch...
const policy = {
Expand All @@ -164,8 +162,8 @@ const createOrUpdateMetaRole = async (instance, inputs, clients, serverlessAccou
'logs:List*',
'logs:Describe*',
'logs:TestMetricFilter',
'logs:FilterLogEvents',
],
'logs:FilterLogEvents'
]
// TODO: Finish this. Haven't been able to get this to work. Perhaps there is a missing service (Cloudfront?)
// Condition: {
// StringEquals: {
Expand All @@ -175,25 +173,25 @@ const createOrUpdateMetaRole = async (instance, inputs, clients, serverlessAccou
// ]
// }
// }
},
],
};
}
]
}

const roleDescription = `The Meta Role for the Serverless Framework App: ${instance.name} Stage: ${instance.stage}`;
const roleDescription = `The Meta Role for the Serverless Framework App: ${instance.name} Stage: ${instance.stage}`

const result = await clients.extras.deployRole({
roleName,
roleDescription,
policy,
assumeRolePolicyDocument,
});
assumeRolePolicyDocument
})

instance.state.metaRoleName = roleName;
instance.state.metaRoleArn = result.roleArn;
instance.state.metaRoleName = roleName
instance.state.metaRoleArn = result.roleArn

console.log(`Meta IAM Role created or updated with ARN ${instance.state.metaRoleArn}`);
console.log(`Meta IAM Role created or updated with ARN ${instance.state.metaRoleArn}`)
}
};
}

/**
* Create a new lambda function
Expand Down Expand Up @@ -258,17 +256,17 @@ const updateLambdaFunctionConfig = async (instance, lambda, inputs) => {
},
...(inputs.securityGroupIds
? {
VpcConfig: {
SecurityGroupIds: inputs.securityGroupIds,
SubnetIds: inputs.subnetIds
VpcConfig: {
SecurityGroupIds: inputs.securityGroupIds,
SubnetIds: inputs.subnetIds
}
}
}
: {
VpcConfig: {
SecurityGroupIds: [],
SubnetIds: []
}
})
VpcConfig: {
SecurityGroupIds: [],
SubnetIds: []
}
})
}

const res = await lambda.updateFunctionConfiguration(functionConfigParams).promise()
Expand Down Expand Up @@ -399,75 +397,68 @@ const inputsChanged = (prevLambda, lambda) => {
const removeAllRoles = async (instance, clients) => {
// Delete Function Role
if (instance.state.defaultLambdaRoleName) {
console.log('Deleting the default Function Role...');
console.log('Deleting the default Function Role...')
await clients.extras.removeRole({
roleName: instance.state.defaultLambdaRoleName,
});
roleName: instance.state.defaultLambdaRoleName
})
}

// Delete Meta Role
if (instance.state.metaRoleName) {
console.log('Deleting the Meta Role...');
console.log('Deleting the Meta Role...')
await clients.extras.removeRole({
roleName: instance.state.metaRoleName,
});
roleName: instance.state.metaRoleName
})
}
};

}

/**
* Get metrics from cloudwatch
* @param {*} clients
* @param {*} rangeStart MUST be a moment() object
* @param {*} rangeEnd MUST be a moment() object
*/
const getMetrics = async (
region,
metaRoleArn,
functionName,
rangeStart,
rangeEnd
) => {
const getMetrics = async (region, metaRoleArn, functionName, rangeStart, rangeEnd) => {
/**
* Create AWS STS Token via the meta role that is deployed with the Express Component
*/

// Assume Role
const assumeParams = {};
assumeParams.RoleSessionName = `session${Date.now()}`;
assumeParams.RoleArn = metaRoleArn;
assumeParams.DurationSeconds = 900;
const assumeParams = {}
assumeParams.RoleSessionName = `session${Date.now()}`
assumeParams.RoleArn = metaRoleArn
assumeParams.DurationSeconds = 900

const sts = new AWS.STS({ region })
const resAssume = await sts.assumeRole(assumeParams).promise();
const resAssume = await sts.assumeRole(assumeParams).promise()

const roleCreds = {};
roleCreds.accessKeyId = resAssume.Credentials.AccessKeyId;
roleCreds.secretAccessKey = resAssume.Credentials.SecretAccessKey;
roleCreds.sessionToken = resAssume.Credentials.SessionToken;
const roleCreds = {}
roleCreds.accessKeyId = resAssume.Credentials.AccessKeyId
roleCreds.secretAccessKey = resAssume.Credentials.SecretAccessKey
roleCreds.sessionToken = resAssume.Credentials.SessionToken

/**
* Instantiate a new Extras instance w/ the temporary credentials
*/

const extras = new AWS.Extras({
credentials: roleCreds,
region,
region
})

const resources = [
{
type: 'aws_lambda',
functionName,
},
];
functionName
}
]

return await extras.getMetrics({
rangeStart,
rangeEnd,
resources,
});
};
resources
})
}

/**
* Exports
Expand All @@ -484,5 +475,5 @@ module.exports = {
inputsChanged,
deleteLambdaFunction,
removeAllRoles,
getMetrics,
getMetrics
}
Loading

0 comments on commit d9620ee

Please sign in to comment.