pulumi / pulumi/examples

Consider adding a Datadog example

Open
#10 4 comments 6 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

area/examples kind/enhancement
Dominant language
TypeScript
Stars
2.6k
Forks
894
Avg merge
12h 19m
Merged PRs (30d)
39

Description

We helped add a Datadog agent to a customer's cluster, and wading through the information available on the internet was not terribly straightforward. This might make a nice example, especially since it's standalone and can be used even if nothing else is on Pulumi. It is loosely based on https://docs.datadoghq.com/integrations/amazon_ecs/. Here's a quick snapshot of the idea:

// Configure Datadog for the cluster.

import * as config from "./config";
import { cluster } from "./foundation";
import * as pulumi from "pulumi";
import * as aws from "@pulumi/aws";

const prefix = pulumi.getStack();

// Allocate a Datadog agent that runs on every host node.  Adapted from:
//     https://docs.datadoghq.com/integrations/amazon_ecs/
const datadogAgentTask = new aws.ecs.TaskDefinition(`${prefix}-datadog-agent-task`, {
    family: "dd-agent-task",
    containerDefinitions: JSON.stringify([{
        name: "dd-agent",
        image: "datadog/docker-dd-agent:latest",
        cpu: 10,
        memory: 256,
        essential: true,
        mountPoints: [
            {
              containerPath: "/var/run/docker.sock",
              sourceVolume: "docker_sock"
            },
            {
              containerPath: "/host/sys/fs/cgroup",
              sourceVolume: "cgroup",
              readOnly: true,
            },
            {
              containerPath: "/host/proc",
              sourceVolume: "proc",
              readOnly: true,
            }
        ],
        environment: [
            {
                name: "API_KEY",
                value: config.datadogKey,
            },
            {
                name: "SD_BACKEND",
                value: "docker",
            },
        ],
    }]),
    volume: [
        {
            name: "docker_sock",
            hostPath: "/var/run/docker.sock",
        },
        {
            name: "proc",
            hostPath: "/proc/",
        },
        {
            name: "cgroup",
            hostPath: "/cgroup/",
        }
    ],
});
const datadogAgent = new aws.ecs.Service(`${prefix}-datadog-agent`, {
    cluster: cluster.ecsClusterARN,
    taskDefinition: datadogAgentTask.arn,
    desiredCount: config.getClusterSize(),
    placementStrategy: [{ type: "spread", field: "instanceId" }],
    placementConstraints: [{ type: "distinctInstance" }],
});

// And now authorize Datadog to read all of the things that it needs to.
let datadogIntegrationRole = new aws.iam.Role(`${prefix}-datadog-role`, {
    assumeRolePolicy: JSON.stringify({
        Version: "2012-10-17",
        Statement: [{
            Action: "sts:AssumeRole",
            Effect: "Allow",
            Condition: {
                StringEquals: {
                    "sts:ExternalId": config.datadogKey,
                },
            },
            Principal: {
                AWS: aws.getCallerIdentity().then(caller => `arn:aws:iam::${caller.accountId}:root`),
            },
        }],
    }),
});

let datadogIntegrationPolicy = new aws.iam.RolePolicy(`${prefix}-datadog-policy`, {
    role: datadogIntegrationRole.name,
    policy: JSON.stringify({
        Version: "2012-10-17",
        Statement: {
            Effect: "Allow",
            Resource: "*",
            Action: [
                "autoscaling:Describe*",
                "cloudtrail:DescribeTrails",
                "cloudtrail:GetTrailStatus",
                "cloudwatch:Describe*",
                "cloudwatch:Get*",
                "cloudwatch:List*",
                "ec2:Describe*",
                "ec2:Get*",
                "ecs:Describe*",
                "ecs:List*",
                "elasticache:Describe*",
                "elasticache:List*",
                "elasticloadbalancing:Describe*",
                "elasticmapreduce:List*",
                "iam:Get*",
                "iam:List*",
                "kinesis:Get*",
                "kinesis:List*",
                "kinesis:Describe*",
                "logs:Get*",
                "logs:Describe*",
                "logs:TestMetricFilter",
                "rds:Describe*",
                "rds:List*",
                "route53:List*",
                "ses:Get*",
                "ses:List*",
                "sns:List*",
                "sns:Publish",
                "sqs:GetQueueAttributes",
                "sqs:ListQueues",
                "sqs:ReceiveMessage",
            ],
        },
    }),
});

We could probably wrap this up in a single class and make it as easy as

new Datadog(ecsARN);

to configure.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start from the TypeScript ECS snippet in the issue, including its ./config and ./foundation entry points, and review how standalone Pulumi examples are organized. Package the Datadog ECS agent and IAM setup as the proposed reusable Datadog example or class, with usage equivalent to new Datadog(ecsARN), and verify it can be used independently.

Written by the indexing model from the issue text.

Assessment

Tech stack
aws, typescript
Domain
cloud, devops
Issue type
Feature
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.