2019-08-21 14:31:28 -08:00
|
|
|
package config
|
|
|
|
|
|
|
|
import (
|
2019-08-26 17:01:58 -08:00
|
|
|
"fmt"
|
2019-08-21 14:31:28 -08:00
|
|
|
"log"
|
|
|
|
"path/filepath"
|
|
|
|
|
|
|
|
"encoding/json"
|
|
|
|
"github.com/aws/aws-sdk-go/aws"
|
|
|
|
"github.com/pkg/errors"
|
|
|
|
"gitlab.com/geeks-accelerator/oss/devops/pkg/devdeploy"
|
|
|
|
)
|
|
|
|
|
|
|
|
// Function define the name of a function.
|
|
|
|
type Function = string
|
|
|
|
|
|
|
|
var (
|
2019-08-21 19:28:23 -08:00
|
|
|
Function_Ddlogscollector = "ddlogscollector"
|
2019-08-21 14:31:28 -08:00
|
|
|
)
|
|
|
|
|
|
|
|
// List of function names used by main.go for help.
|
|
|
|
var FunctionNames = []Function{
|
|
|
|
// Python Datadog Logs Collector
|
|
|
|
Function_Ddlogscollector,
|
|
|
|
}
|
|
|
|
|
2019-08-26 04:48:43 -08:00
|
|
|
// NewFunction returns the *devdeploy.ProjectFunction.
|
|
|
|
func NewFunction(funcName string, cfg *devdeploy.Config) (*devdeploy.ProjectFunction, error) {
|
2019-08-21 14:31:28 -08:00
|
|
|
|
2019-08-26 04:48:43 -08:00
|
|
|
ctx := &devdeploy.ProjectFunction{
|
2019-08-26 17:01:58 -08:00
|
|
|
Name: fmt.Sprintf("%s-%s-%s", cfg.Env, cfg.ProjectName, funcName),
|
2019-08-26 04:48:43 -08:00
|
|
|
CodeDir: filepath.Join(cfg.ProjectRoot, "cmd", funcName),
|
|
|
|
DockerBuildDir: cfg.ProjectRoot,
|
2019-08-21 14:31:28 -08:00
|
|
|
DockerBuildContext: ".",
|
|
|
|
|
2019-08-26 04:48:43 -08:00
|
|
|
// Set the release tag for the image to use include env + function name + commit hash/tag.
|
2019-08-21 14:31:28 -08:00
|
|
|
ReleaseTag: devdeploy.GitLabCiReleaseTag(cfg.Env, funcName),
|
|
|
|
}
|
|
|
|
|
|
|
|
switch funcName {
|
|
|
|
case Function_Ddlogscollector:
|
|
|
|
|
|
|
|
// Python Datadog Logs Collector is
|
2019-08-26 04:48:43 -08:00
|
|
|
ctx.CodeDir = filepath.Join(cfg.ProjectRoot, "deployments", funcName)
|
2019-08-21 14:31:28 -08:00
|
|
|
|
|
|
|
// Change the build directory to the function directory instead of project root.
|
2019-08-26 04:48:43 -08:00
|
|
|
ctx.DockerBuildDir = ctx.CodeDir
|
2019-08-21 14:31:28 -08:00
|
|
|
|
|
|
|
// AwsLambdaFunction defines the details needed to create an lambda function.
|
|
|
|
ctx.AwsLambdaFunction = &devdeploy.AwsLambdaFunction{
|
|
|
|
FunctionName: ctx.Name,
|
|
|
|
Description: "Ship logs from cloudwatch to datadog",
|
|
|
|
|
|
|
|
Handler: "lambda_function.lambda_handler",
|
|
|
|
Runtime: "python2.7",
|
|
|
|
MemorySize: 512,
|
|
|
|
|
|
|
|
Timeout: aws.Int64(300),
|
|
|
|
Environment: map[string]string{
|
|
|
|
"DD_API_KEY": "",
|
|
|
|
"LAMBDA_FUNC": ctx.Name,
|
|
|
|
},
|
|
|
|
Tags: []devdeploy.Tag{
|
|
|
|
{Key: devdeploy.AwsTagNameProject, Value: cfg.ProjectName},
|
|
|
|
{Key: devdeploy.AwsTagNameEnv, Value: cfg.Env},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx.AwsIamRole = &devdeploy.AwsIamRole{
|
|
|
|
RoleName: "DatadogAWSIntegrationLambdaRole",
|
|
|
|
Description: "Allows Datadog to run Lambda functions to call AWS services on your behalf.",
|
|
|
|
AssumeRolePolicyDocument: "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"Service\":[\"lambda.amazonaws.com\"]},\"Action\":[\"sts:AssumeRole\"]}]}",
|
|
|
|
Tags: []devdeploy.Tag{
|
|
|
|
{Key: devdeploy.AwsTagNameProject, Value: cfg.ProjectName},
|
|
|
|
{Key: devdeploy.AwsTagNameEnv, Value: cfg.Env},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx.AwsIamPolicy = &devdeploy.AwsIamPolicy{
|
|
|
|
PolicyName: "DatadogAWSIntegrationPolicy",
|
|
|
|
Description: "Provides Datadog Lambda function the ability to ship AWS service related logs back to Datadog.",
|
|
|
|
PolicyDocument: devdeploy.AwsIamPolicyDocument{
|
|
|
|
Version: "2012-10-17",
|
|
|
|
Statement: []devdeploy.AwsIamStatementEntry{
|
|
|
|
{
|
|
|
|
Action: []string{
|
|
|
|
"apigateway:GET",
|
|
|
|
"autoscaling:Describe*",
|
|
|
|
"budgets:ViewBudget",
|
|
|
|
"cloudfront:GetDistributionConfig",
|
|
|
|
"cloudfront:ListDistributions",
|
|
|
|
"cloudtrail:DescribeTrails",
|
|
|
|
"cloudtrail:GetTrailStatus",
|
|
|
|
"cloudwatch:Describe*",
|
|
|
|
"cloudwatch:Get*",
|
|
|
|
"cloudwatch:List*",
|
|
|
|
"codedeploy:List*",
|
|
|
|
"codedeploy:BatchGet*",
|
|
|
|
"directconnect:Describe*",
|
|
|
|
"dynamodb:List*",
|
|
|
|
"dynamodb:Describe*",
|
|
|
|
"ec2:Describe*",
|
|
|
|
"ecs:Describe*",
|
|
|
|
"ecs:List*",
|
|
|
|
"elasticache:Describe*",
|
|
|
|
"elasticache:List*",
|
|
|
|
"elasticfilesystem:DescribeFileSystems",
|
|
|
|
"elasticfilesystem:DescribeTags",
|
|
|
|
"elasticloadbalancing:Describe*",
|
|
|
|
"elasticmapreduce:List*",
|
|
|
|
"elasticmapreduce:Describe*",
|
|
|
|
"es:ListTags",
|
|
|
|
"es:ListDomainNames",
|
|
|
|
"es:DescribeElasticsearchDomains",
|
|
|
|
"health:DescribeEvents",
|
|
|
|
"health:DescribeEventDetails",
|
|
|
|
"health:DescribeAffectedEntities",
|
|
|
|
"kinesis:List*",
|
|
|
|
"kinesis:Describe*",
|
|
|
|
"lambda:AddPermission",
|
|
|
|
"lambda:GetPolicy",
|
|
|
|
"lambda:List*",
|
|
|
|
"lambda:RemovePermission",
|
|
|
|
"logs:Get*",
|
|
|
|
"logs:Describe*",
|
|
|
|
"logs:FilterLogEvents",
|
|
|
|
"logs:TestMetricFilter",
|
|
|
|
"logs:PutSubscriptionFilter",
|
|
|
|
"logs:DeleteSubscriptionFilter",
|
|
|
|
"logs:DescribeSubscriptionFilters",
|
|
|
|
"rds:Describe*",
|
|
|
|
"rds:List*",
|
|
|
|
"redshift:DescribeClusters",
|
|
|
|
"redshift:DescribeLoggingStatus",
|
|
|
|
"route53:List*",
|
|
|
|
"s3:GetBucketLogging",
|
|
|
|
"s3:GetBucketLocation",
|
|
|
|
"s3:GetBucketNotification",
|
|
|
|
"s3:GetBucketTagging",
|
|
|
|
"s3:ListAllMyBuckets",
|
|
|
|
"s3:PutBucketNotification",
|
|
|
|
"ses:Get*",
|
|
|
|
"sns:List*",
|
|
|
|
"sns:Publish",
|
|
|
|
"sqs:ListQueues",
|
|
|
|
"support:*",
|
|
|
|
"tag:GetResources",
|
|
|
|
"tag:GetTagKeys",
|
|
|
|
"tag:GetTagValues",
|
|
|
|
"xray:BatchGetTraces",
|
|
|
|
"xray:GetTraceSummaries",
|
|
|
|
"lambda:List*",
|
|
|
|
"logs:DescribeLogGroups",
|
|
|
|
"logs:DescribeLogStreams",
|
|
|
|
"logs:FilterLogEvents",
|
|
|
|
"tag:GetResources",
|
|
|
|
"cloudfront:GetDistributionConfig",
|
|
|
|
"cloudfront:ListDistributions",
|
|
|
|
"elasticloadbalancing:DescribeLoadBalancers",
|
|
|
|
"elasticloadbalancing:DescribeLoadBalancerAttributes",
|
|
|
|
"lambda:AddPermission",
|
|
|
|
"lambda:GetPolicy",
|
|
|
|
"lambda:RemovePermission",
|
|
|
|
"redshift:DescribeClusters",
|
|
|
|
"redshift:DescribeLoggingStatus",
|
|
|
|
"s3:GetBucketLogging",
|
|
|
|
"s3:GetBucketLocation",
|
|
|
|
"s3:GetBucketNotification",
|
|
|
|
"s3:ListAllMyBuckets",
|
|
|
|
"s3:PutBucketNotification",
|
|
|
|
"logs:PutSubscriptionFilter",
|
|
|
|
"logs:DeleteSubscriptionFilter",
|
|
|
|
"logs:DescribeSubscriptionFilters",
|
|
|
|
},
|
|
|
|
Effect: "Allow",
|
|
|
|
Resource: "*",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
return nil, errors.Wrapf(devdeploy.ErrInvalidFunction,
|
|
|
|
"No function context defined for function '%s'",
|
|
|
|
funcName)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Append the datadog api key before execution.
|
|
|
|
ctx.AwsLambdaFunction.UpdateEnvironment = func(vars map[string]string) error {
|
|
|
|
datadogApiKey, err := getDatadogApiKey(cfg)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
vars["DD_API_KEY"] = datadogApiKey
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2019-08-26 04:48:43 -08:00
|
|
|
ctx.CodeS3Bucket = cfg.AwsS3BucketPrivate.BucketName
|
|
|
|
ctx.CodeS3Key = filepath.Join("src", "aws", "lambda", cfg.Env, ctx.Name, ctx.ReleaseTag+".zip")
|
|
|
|
|
2019-08-21 14:31:28 -08:00
|
|
|
// Set the docker file if no custom one has been defined for the service.
|
|
|
|
if ctx.Dockerfile == "" {
|
2019-08-26 04:48:43 -08:00
|
|
|
ctx.Dockerfile = filepath.Join(ctx.CodeDir, "Dockerfile")
|
2019-08-21 14:31:28 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
return ctx, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// BuildFunctionForTargetEnv executes the build commands for a target function.
|
|
|
|
func BuildFunctionForTargetEnv(log *log.Logger, awsCredentials devdeploy.AwsCredentials, targetEnv Env, functionName, releaseTag string, dryRun, noCache, noPush bool) error {
|
|
|
|
|
2019-08-26 04:48:43 -08:00
|
|
|
cfg, err := NewConfig(log, targetEnv, awsCredentials)
|
2019-08-21 14:31:28 -08:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2019-08-26 04:48:43 -08:00
|
|
|
targetFunc, err := NewFunction(functionName, cfg)
|
2019-08-21 14:31:28 -08:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Override the release tag if set.
|
|
|
|
if releaseTag != "" {
|
2019-08-26 04:48:43 -08:00
|
|
|
targetFunc.ReleaseTag = releaseTag
|
2019-08-21 14:31:28 -08:00
|
|
|
}
|
|
|
|
|
2019-08-26 04:48:43 -08:00
|
|
|
// Append build args to be used for all functions.
|
|
|
|
if targetFunc.DockerBuildArgs == nil {
|
|
|
|
targetFunc.DockerBuildArgs = make(map[string]string)
|
2019-08-21 14:31:28 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// funcPath is used to copy the service specific code in the Dockerfile.
|
2019-08-26 04:48:43 -08:00
|
|
|
codePath, err := filepath.Rel(cfg.ProjectRoot, targetFunc.CodeDir)
|
2019-08-21 14:31:28 -08:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2019-08-26 04:48:43 -08:00
|
|
|
targetFunc.DockerBuildArgs["code_path"] = codePath
|
2019-08-21 14:31:28 -08:00
|
|
|
|
|
|
|
// commitRef is used by main.go:build constant.
|
|
|
|
commitRef := getCommitRef()
|
|
|
|
if commitRef == "" {
|
2019-08-26 04:48:43 -08:00
|
|
|
commitRef = targetFunc.ReleaseTag
|
2019-08-21 14:31:28 -08:00
|
|
|
}
|
2019-08-26 04:48:43 -08:00
|
|
|
targetFunc.DockerBuildArgs["commit_ref"] = commitRef
|
2019-08-21 14:31:28 -08:00
|
|
|
|
|
|
|
if dryRun {
|
|
|
|
cfgJSON, err := json.MarshalIndent(cfg, "", " ")
|
|
|
|
if err != nil {
|
|
|
|
log.Fatalf("BuildFunctionForTargetEnv : Marshalling config to JSON : %+v", err)
|
|
|
|
}
|
|
|
|
log.Printf("BuildFunctionForTargetEnv : config : %v\n", string(cfgJSON))
|
|
|
|
|
2019-08-26 04:48:43 -08:00
|
|
|
detailsJSON, err := json.MarshalIndent(targetFunc, "", " ")
|
2019-08-21 14:31:28 -08:00
|
|
|
if err != nil {
|
|
|
|
log.Fatalf("BuildFunctionForTargetEnv : Marshalling details to JSON : %+v", err)
|
|
|
|
}
|
|
|
|
log.Printf("BuildFunctionForTargetEnv : details : %v\n", string(detailsJSON))
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2019-08-26 04:48:43 -08:00
|
|
|
return devdeploy.BuildLambdaForTargetEnv(log, cfg, targetFunc, noCache, noPush)
|
2019-08-21 14:31:28 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// DeployFunctionForTargetEnv executes the deploy commands for a target function.
|
|
|
|
func DeployFunctionForTargetEnv(log *log.Logger, awsCredentials devdeploy.AwsCredentials, targetEnv Env, functionName, releaseTag string, dryRun bool) error {
|
|
|
|
|
2019-08-26 04:48:43 -08:00
|
|
|
cfg, err := NewConfig(log, targetEnv, awsCredentials)
|
2019-08-21 14:31:28 -08:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2019-08-26 04:48:43 -08:00
|
|
|
targetFunc, err := NewFunction(functionName, cfg)
|
2019-08-21 14:31:28 -08:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Override the release tag if set.
|
|
|
|
if releaseTag != "" {
|
2019-08-26 04:48:43 -08:00
|
|
|
targetFunc.ReleaseTag = releaseTag
|
2019-08-21 14:31:28 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
if dryRun {
|
|
|
|
cfgJSON, err := json.MarshalIndent(cfg, "", " ")
|
|
|
|
if err != nil {
|
|
|
|
log.Fatalf("DeployFunctionForTargetEnv : Marshalling config to JSON : %+v", err)
|
|
|
|
}
|
|
|
|
log.Printf("DeployFunctionForTargetEnv : config : %v\n", string(cfgJSON))
|
|
|
|
|
2019-08-26 04:48:43 -08:00
|
|
|
detailsJSON, err := json.MarshalIndent(targetFunc, "", " ")
|
2019-08-21 14:31:28 -08:00
|
|
|
if err != nil {
|
|
|
|
log.Fatalf("DeployFunctionForTargetEnv : Marshalling details to JSON : %+v", err)
|
|
|
|
}
|
|
|
|
log.Printf("DeployFunctionForTargetEnv : details : %v\n", string(detailsJSON))
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2019-08-26 04:48:43 -08:00
|
|
|
return devdeploy.DeployLambdaToTargetEnv(log, cfg, targetFunc)
|
2019-08-21 14:31:28 -08:00
|
|
|
}
|