Skip to content

Commit

Permalink
Create KubernetesAgent component to install the agent in Kubernetes
Browse files Browse the repository at this point in the history
  • Loading branch information
KevinFairise2 committed Feb 12, 2024
1 parent ddba83b commit 192cd9d
Show file tree
Hide file tree
Showing 2 changed files with 282 additions and 0 deletions.
52 changes: 52 additions & 0 deletions components/datadog/agent/kubernetes.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package agent

import (
"github.com/pulumi/pulumi-kubernetes/sdk/v3/go/kubernetes"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"

"github.com/DataDog/test-infra-definitions/common/config"
"github.com/DataDog/test-infra-definitions/components"
"github.com/DataDog/test-infra-definitions/components/datadog/kubernetesagentparams"
)

type KubernetesAgentOutput struct {
components.JSONImporter

AgentInstallName string `json:"agentInstallName"`
AgentInstallNameWindows string `json:"agentInstallNameWindows"`
}

// DockerAgent is a Docker installer on a remote Host
type KubernetesAgent struct {
pulumi.ResourceState
components.Component

AgentInstallName pulumi.StringOutput `pulumi:"agentInstallName"`
AgentInstallNameWindows pulumi.StringOutput `pulumi:"agentInstallNameWindows"`
}

func (h *KubernetesAgent) Export(ctx *pulumi.Context, out *KubernetesAgentOutput) error {
return components.Export(ctx, h, out)
}

func NewKubernetesAgent(e config.CommonEnvironment, clusterName string, kubeProvider *kubernetes.Provider, options ...kubernetesagentparams.Option) (*KubernetesAgent, error) {
return components.NewComponent(e, clusterName, func(comp *KubernetesAgent) error {
params, err := kubernetesagentparams.NewParams(&e, options...)
if err != nil {
return err
}
helmComponent, err := NewHelmInstallation(e, HelmInstallationArgs{
KubeProvider: kubeProvider,
Namespace: params.Namespace,
ValuesYAML: params.HelmValues,
}, params.PulumiDependsOn...)
if err != nil {
return err
}

// Fill component
comp.AgentInstallName = helmComponent.LinuxHelmReleaseName.Elem()
comp.AgentInstallNameWindows = helmComponent.WindowsHelmReleaseName.Elem()
return nil
})
}
230 changes: 230 additions & 0 deletions components/datadog/kubernetesagentparams/params.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,230 @@
package kubernetesagentparams

import (
"encoding/json"
"fmt"
"strings"

"github.com/DataDog/test-infra-definitions/common"
"github.com/DataDog/test-infra-definitions/common/config"
"github.com/DataDog/test-infra-definitions/common/utils"
"github.com/DataDog/test-infra-definitions/components/datadog/fakeintake"
"github.com/DataDog/test-infra-definitions/components/docker"

"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

const (
defaultAgentNamespace = "datadog"
)

// Params defines the parameters for the Kubernetes Agent installation.
// The Params configuration uses the [Functional options pattern].
//
// The available options are:
// - [WithImageTag]
// - [WithRepository]
// - [WithFullImagePath]
// - [WithPulumiDependsOn]
// - [WithEnvironmentVariables]
// - [WithAgentServiceEnvVariable]
// - [WithHostName]
// - [WithFakeintake]
// - [WithLogs]
// - [WithExtraComposeManifest]
//
// [Functional options pattern]: https://dave.cheney.net/2014/10/17/functional-options-for-friendly-apis

type Params struct {
// FullImagePath is the full path of the docker agent image to use.
// It has priority over ImageTag and Repository.
FullImagePath string
// ImageTag is the docker agent image tag to use.
ImageTag string
// Repository is the docker repository to use.
Repository string
// Namespace is the namespace to deploy the agent to.
Namespace string
// AgentServiceEnvironment is a map of environment variables to set in the docker compose agent service's environment.
AgentServiceEnvironment pulumi.Map
// ExtraComposeManifests is a list of extra docker compose manifests to add beside the agent service.
ExtraComposeManifests []docker.ComposeInlineManifest
// EnvironmentVariables is a map of environment variables to set with the docker-compose context
EnvironmentVariables pulumi.StringMap
// HelmValues is the Helm values to use for the agent installation.
HelmValues pulumi.AssetOrArchiveArray
// PulumiDependsOn is a list of resources to depend on.
PulumiDependsOn []pulumi.ResourceOption
}

type Option = func(*Params) error

func NewParams(e *config.CommonEnvironment, options ...Option) (*Params, error) {
version := &Params{
Namespace: defaultAgentNamespace,
AgentServiceEnvironment: pulumi.Map{},
EnvironmentVariables: pulumi.StringMap{},
}

if e.PipelineID() != "" && e.CommitSHA() != "" {
options = append(options, WithFullImagePath(utils.BuildDockerImagePath("669783387624.dkr.ecr.us-east-1.amazonaws.com/agent", fmt.Sprintf("%s-%s", e.PipelineID(), e.CommitSHA()))))
}

return common.ApplyOption(version, options)
}

// WithImageTag sets the agent image tag to use.
func WithImageTag(agentImageTag string) func(*Params) error {
return func(p *Params) error {
p.ImageTag = agentImageTag
return nil
}
}

// WithRepository sets the repository to use for the agent installation.
func WithRepository(repository string) func(*Params) error {
return func(p *Params) error {
p.Repository = repository
return nil
}
}

// WithFullImagePath sets the full path of the agent image to use.
func WithFullImagePath(fullImagePath string) func(*Params) error {
return func(p *Params) error {
p.FullImagePath = fullImagePath
return nil
}
}

// WithNamespace sets the namespace to deploy the agent to.
func WithNamespace(namespace string) func(*Params) error {
return func(p *Params) error {
p.Namespace = namespace
return nil
}
}

// WithPulumiDependsOn sets the resources to depend on.
func WithPulumiDependsOn(resources ...pulumi.ResourceOption) func(*Params) error {
return func(p *Params) error {
p.PulumiDependsOn = resources
return nil
}
}

// WithEnvironmentVariables sets the environment variables to use for the agent installation.
func WithEnvironmentVariables(environmentVariables pulumi.StringMap) func(*Params) error {
return func(p *Params) error {
p.EnvironmentVariables = environmentVariables
return nil
}
}

// WithAgentServiceEnvVariable set an environment variable in the docker compose agent service's environment.
func WithAgentServiceEnvVariable(key string, value pulumi.Input) func(*Params) error {
return func(p *Params) error {
p.AgentServiceEnvironment[key] = value
return nil
}
}

// WithHelmValues sets the Helm values to use for the agent installation.
func WithHelmValues(values string) func(*Params) error {
return func(p *Params) error {
p.HelmValues = pulumi.AssetOrArchiveArray{pulumi.NewStringAsset(values)}
return nil
}
}

// WithIntake configures the agent to use the given hostname as intake.
// The hostname must be a valid Datadog intake, with a SSL valid certificate
//
// To use a fakeintake, see WithFakeintake.
//
// This option is overwritten by `WithFakeintake`.
func WithIntake(hostname string) func(*Params) error {
return withIntakeHostname(pulumi.String(hostname), false)
}

// WithFakeintake installs the fake intake and configures the Agent to use it.
//
// This option is overwritten by `WithIntakeHostname`.
func WithFakeintake(fakeintake *fakeintake.Fakeintake) func(*Params) error {
return withIntakeHostname(fakeintake.Host, true)
}

func withIntakeHostname(hostname pulumi.StringInput, shouldSkipSSLCertificateValidation bool) func(*Params) error {
shouldEnforceHTTPInput := hostname.ToStringOutput().ApplyT(func(host string) (bool, error) {
return strings.HasPrefix(host, "https"), nil
}).(pulumi.BoolOutput)
return func(p *Params) error {
envVars := pulumi.Map{
"DD_DD_URL": pulumi.Sprintf("http://%s:80", hostname),
"DD_LOGS_CONFIG_DD_URL": pulumi.Sprintf("%s:80", hostname),
"DD_PROCESS_CONFIG_PROCESS_DD_URL": pulumi.Sprintf("http://%s:80", hostname),
"DD_APM_DD_URL": pulumi.Sprintf("http://%s:80", hostname),
"DD_SKIP_SSL_VALIDATION": pulumi.Bool(shouldSkipSSLCertificateValidation),
"DD_REMOTE_CONFIGURATION_NO_TLS_VALIDATION": pulumi.Bool(shouldSkipSSLCertificateValidation),
"DD_LOGS_CONFIG_LOGS_NO_SSL": pulumi.Bool(shouldSkipSSLCertificateValidation),
"DD_LOGS_CONFIG_FORCE_USE_HTTP": shouldEnforceHTTPInput,
}
for key, value := range envVars {
if err := WithAgentServiceEnvVariable(key, value)(p); err != nil {
return err
}
}
return nil
}
}

type additionalLogEndpointInput struct {
Hostname string `json:"host"`
APIKey string `json:"api_key,omitempty"`
Port string `json:"port,omitempty"`
IsReliable bool `json:"is_reliable,omitempty"`
}

func WithAdditionalFakeintake(fakeintake *fakeintake.Fakeintake) func(*Params) error {
additionalEndpointsContentInput := fakeintake.Host.ToStringOutput().ApplyT(func(host string) (string, error) {
endpoints := map[string][]string{
fmt.Sprintf("https://%s", host): {"00000000000000000000000000000000"},
}

jsonContent, err := json.Marshal(endpoints)
return string(jsonContent), err
}).(pulumi.StringOutput)
additionalLogsEndpointsContentInput := fakeintake.Host.ToStringOutput().ApplyT(func(host string) (string, error) {
endpoints := []additionalLogEndpointInput{
{
Hostname: host,
},
}
jsonContent, err := json.Marshal(endpoints)
return string(jsonContent), err
}).(pulumi.StringOutput)
shouldEnforceHTTPInput := fakeintake.Host.ToStringOutput().ApplyT(func(host string) (bool, error) {
return strings.HasPrefix(host, "https"), nil
}).(pulumi.BoolOutput)
return func(p *Params) error {
logsEnvVars := pulumi.Map{
"DD_ADDITIONAL_ENDPOINTS": additionalEndpointsContentInput,
"DD_LOGS_CONFIG_ADDITIONAL_ENDPOINTS": additionalLogsEndpointsContentInput,
"DD_SKIP_SSL_VALIDATION": pulumi.Bool(true),
"DD_REMOTE_CONFIGURATION_NO_TLS_VALIDATION": pulumi.Bool(true),
"DD_LOGS_CONFIG_LOGS_NO_SSL": pulumi.Bool(true),
"DD_LOGS_CONFIG_FORCE_USE_HTTP": shouldEnforceHTTPInput,
}
for key, value := range logsEnvVars {
if err := WithAgentServiceEnvVariable(key, value)(p); err != nil {
return err
}
}
return nil
}
}

// WithLogs enables the log agent
func WithLogs() func(*Params) error {
return WithAgentServiceEnvVariable("DD_LOGS_ENABLED", pulumi.String("true"))
}

0 comments on commit 192cd9d

Please sign in to comment.