Skip to content

Commit

Permalink
sampling: add missing license check (#4328) (#4507)
Browse files Browse the repository at this point in the history
* Require platinum/trial license for tail-sampling
  • Loading branch information
axw authored Dec 10, 2020
1 parent e349695 commit 3291f4e
Show file tree
Hide file tree
Showing 5 changed files with 267 additions and 19 deletions.
169 changes: 158 additions & 11 deletions systemtest/containers.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,25 @@ import (
"context"
"fmt"
"log"
"net"
"net/url"
"os"
"os/exec"
"strings"
"time"

"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/client"
"github.com/testcontainers/testcontainers-go"
"github.com/testcontainers/testcontainers-go/wait"

"github.com/elastic/apm-server/systemtest/estest"
"github.com/elastic/go-elasticsearch/v7"
)

const startContainersTimeout = 5 * time.Minute

// StartStackContainers starts Docker containers for Elasticsearch and Kibana.
//
// We leave Elasticsearch and Kibana running, to avoid slowing down iterative
Expand All @@ -47,29 +57,71 @@ func StartStackContainers() error {

// Wait for up to 5 minutes for Kibana to become healthy,
// which implies Elasticsearch is healthy too.
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
ctx, cancel := context.WithTimeout(context.Background(), startContainersTimeout)
defer cancel()
return waitKibanaContainerHealthy(ctx)
}

// NewUnstartedElasticsearchContainer returns a new ElasticsearchContainer.
func NewUnstartedElasticsearchContainer() (*ElasticsearchContainer, error) {
// Create a testcontainer.ContainerRequest based on the "elasticsearch service
// defined in docker-compose.

docker, err := client.NewClientWithOpts(client.FromEnv)
if err != nil {
return err
return nil, err
}
defer docker.Close()

containers, err := docker.ContainerList(ctx, types.ContainerListOptions{
Filters: filters.NewArgs(
filters.Arg("label", "com.docker.compose.project=apm-server"),
filters.Arg("label", "com.docker.compose.service=kibana"),
),
})
container, err := stackContainerInfo(context.Background(), docker, "elasticsearch")
if err != nil {
return nil, err
}
containerDetails, err := docker.ContainerInspect(context.Background(), container.ID)
if err != nil {
return nil, err
}

req := testcontainers.ContainerRequest{
Image: container.Image,
AutoRemove: true,
}
waitFor := wait.ForHTTP("/")
waitFor.Port = "9200/tcp"
req.WaitingFor = waitFor

for port := range containerDetails.Config.ExposedPorts {
req.ExposedPorts = append(req.ExposedPorts, string(port))
}

env := make(map[string]string)
for _, kv := range containerDetails.Config.Env {
sep := strings.IndexRune(kv, '=')
k, v := kv[:sep], kv[sep+1:]
env[k] = v
}
for network := range containerDetails.NetworkSettings.Networks {
req.Networks = append(req.Networks, network)
}

// BUG(axw) ElasticsearchContainer currently does not support security.
env["xpack.security.enabled"] = "false"

return &ElasticsearchContainer{request: req, Env: env}, nil
}

func waitKibanaContainerHealthy(ctx context.Context) error {
docker, err := client.NewClientWithOpts(client.FromEnv)
if err != nil {
return err
}
if n := len(containers); n != 1 {
return fmt.Errorf("expected 1 kibana container, got %d", n)
defer docker.Close()

container, err := stackContainerInfo(ctx, docker, "kibana")
if err != nil {
return err
}

container := containers[0]
first := true
for {
containerJSON, err := docker.ContainerInspect(ctx, container.ID)
Expand All @@ -87,3 +139,98 @@ func StartStackContainers() error {
}
return nil
}

func stackContainerInfo(ctx context.Context, docker *client.Client, name string) (*types.Container, error) {
containers, err := docker.ContainerList(ctx, types.ContainerListOptions{
Filters: filters.NewArgs(
filters.Arg("label", "com.docker.compose.project=apm-server"),
filters.Arg("label", "com.docker.compose.service="+name),
),
})
if err != nil {
return nil, err
}
if n := len(containers); n != 1 {
return nil, fmt.Errorf("expected 1 %s container, got %d", name, n)
}
return &containers[0], nil
}

// ElasticsearchContainer represents an ephemeral Elasticsearch container.
//
// This can be used when the docker-compose "elasticsearch" service is insufficient.
type ElasticsearchContainer struct {
request testcontainers.ContainerRequest
container testcontainers.Container

// Env holds the environment variables to pass to the container,
// and will be initialised with the values in the docker-compose
// "elasticsearch" service definition.
//
// BUG(axw) ElasticsearchContainer currently does not support security,
// and will set "xpack.security.enabled=false" by default.
Env map[string]string

// Addr holds the "host:port" address for Elasticsearch's REST API.
// This will be populated by Start.
Addr string

// Client holds a client for interacting with Elasticsearch's REST API.
// This will be populated by Start.
Client *estest.Client
}

// Start starts the container.
//
// The Addr and Client fields will be updated on successful return.
//
// The container will be removed when Close() is called, or otherwise by a
// reaper process if the test process is aborted.
func (c *ElasticsearchContainer) Start() error {
ctx, cancel := context.WithTimeout(context.Background(), startContainersTimeout)
defer cancel()

// Update request from user-definable fields.
c.request.Env = c.Env

container, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{
ContainerRequest: c.request,
Started: true,
})
if err != nil {
return err
}
defer func() {
if c.container == nil {
// Something has gone wrong.
container.Terminate(ctx)
}
}()

ip, err := container.Host(ctx)
if err != nil {
return err
}
port, err := container.MappedPort(ctx, "9200")
if err != nil {
return err
}
c.Addr = net.JoinHostPort(ip, port.Port())

esURL := url.URL{Scheme: "http", Host: c.Addr}
config := newElasticsearchConfig()
config.Addresses[0] = esURL.String()
client, err := elasticsearch.NewClient(config)
if err != nil {
return err
}
c.Client = &estest.Client{Client: client}

c.container = container
return nil
}

// Close terminates and removes the container.
func (c *ElasticsearchContainer) Close() error {
return c.container.Terminate(context.Background())
}
7 changes: 2 additions & 5 deletions systemtest/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,9 @@ module github.com/elastic/apm-server/systemtest
go 1.14

require (
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 // indirect
github.com/Microsoft/go-winio v0.4.14 // indirect
github.com/containerd/containerd v1.3.6 // indirect
github.com/docker/distribution v2.7.1+incompatible // indirect
github.com/docker/docker v1.13.1
github.com/docker/go-connections v0.4.0 // indirect
github.com/docker/docker v17.12.0-ce-rc1.0.20200916142827-bd33bbf0497b+incompatible
github.com/elastic/apm-server/approvaltest v0.0.0-00010101000000-000000000000
github.com/elastic/go-elasticsearch/v7 v7.8.0
github.com/elastic/go-sysinfo v1.4.0 // indirect
Expand All @@ -17,9 +14,9 @@ require (
github.com/mitchellh/mapstructure v1.1.2
github.com/morikuni/aec v1.0.0 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.0.1 // indirect
github.com/prometheus/procfs v0.1.3 // indirect
github.com/stretchr/testify v1.6.1
github.com/testcontainers/testcontainers-go v0.9.0
github.com/tidwall/gjson v1.6.0
go.elastic.co/apm v1.8.1-0.20200913025752-7af7e1529586
go.elastic.co/fastjson v1.1.0
Expand Down
Loading

0 comments on commit 3291f4e

Please sign in to comment.