Skip to content

Commit 3aced57

Browse files
donoghucmergify[bot]
authored andcommitted
Harmonize observability sre acceptance (#17781)
* Move ES config from ENV to file * Use fips filebeat impl for smoke tests * Standardize container orchestration Make rspec responsible for container orchestration. DRY shared functionality. * Ensure we test against the right versions Dynamically look up the version of logstash and test against the corresponding ES image. Also, extract this to make local dev easier. (cherry picked from commit 1195743)
1 parent 4512e57 commit 3aced57

File tree

11 files changed

+238
-216
lines changed

11 files changed

+238
-216
lines changed

.buildkite/pull_request_pipeline.yml

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -157,18 +157,7 @@ steps:
157157
command: |
158158
set -euo pipefail
159159
source .buildkite/scripts/common/vm-agent.sh
160-
QUALIFIED_VERSION="$(.buildkite/scripts/common/qualified-version.sh)"
161-
# Build the image locally with the gradle task
162-
./gradlew --stacktrace artifactDockerObservabilitySRE -PfedrampHighMode=true
163-
# Ensure it can at least start logstash
164-
docker run docker.elastic.co/logstash/logstash-observability-sre:$${QUALIFIED_VERSION} \
165-
logstash -e 'input { generator { count => 3 } } output { stdout { codec => rubydebug } }'
166-
# Run the smoke tests on the PR code
167-
docker tag docker.elastic.co/logstash/logstash-observability-sre:$${QUALIFIED_VERSION} \
168-
pr-built-observability-sre-image
169-
# observabilitySREsmokeTests orchestrates FIPS-mode docker images
170-
# and validates assertions separately, so it does not need FIPS flag.
171-
./gradlew observabilitySREsmokeTests --stacktrace
160+
./ci/observabilitySREsmoke_tests.sh
172161
173162
- label: ":lab_coat: Integration Tests - FIPS mode / part 1-of-3"
174163
key: "integration-tests-fips-part-1-of-3"

.buildkite/scripts/exhaustive-tests/generate-steps.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ def fips_test_runner_step() -> dict[str, typing.Any]:
183183
"command": LiteralScalarString("""#!/usr/bin/env bash
184184
set -euo pipefail
185185
source .buildkite/scripts/common/vm-agent.sh
186-
./gradlew observabilitySREacceptanceTests --stacktrace
186+
./ci/observabilitySREacceptance_tests.sh
187187
"""),
188188
}
189189
return step
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#!/bin/bash
2+
3+
set -e
4+
5+
QUALIFIED_VERSION="$(.buildkite/scripts/common/qualified-version.sh)"
6+
export OBSERVABILITY_SRE_IMAGE_VERSION="${OBSERVABILITY_SRE_IMAGE_VERSION:-$QUALIFIED_VERSION}"
7+
export ELASTICSEARCH_IMAGE_VERSION="${ELASTICSEARCH_IMAGE_VERSION:-$QUALIFIED_VERSION}"
8+
export FILEBEAT_IMAGE_VERSION="${FILEBEAT_IMAGE_VERSION:-$QUALIFIED_VERSION}"
9+
10+
./gradlew observabilitySREacceptanceTests --stacktrace

ci/observabilitySREsmoke_tests.sh

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#!/bin/bash
2+
3+
set -e
4+
5+
QUALIFIED_VERSION="$(.buildkite/scripts/common/qualified-version.sh)"
6+
export ELASTICSEARCH_IMAGE_VERSION="${ELASTICSEARCH_IMAGE_VERSION:-$QUALIFIED_VERSION}"
7+
export FILEBEAT_IMAGE_VERSION="${FILEBEAT_IMAGE_VERSION:-$QUALIFIED_VERSION}"
8+
9+
./gradlew --stacktrace artifactDockerObservabilitySRE -PfedrampHighMode=true
10+
11+
docker run docker.elastic.co/logstash/logstash-observability-sre:${QUALIFIED_VERSION} \
12+
logstash -e 'input { generator { count => 3 } } output { stdout { codec => rubydebug } }'
13+
14+
docker tag docker.elastic.co/logstash/logstash-observability-sre:${QUALIFIED_VERSION} pr-built-observability-sre-image
15+
16+
./gradlew observabilitySREsmokeTests --stacktrace

x-pack/build.gradle

Lines changed: 6 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,8 @@ tasks.register("buildFipsValidationGem") {
7777
}
7878

7979
tasks.register("observabilitySREsmokeTests", Test) {
80-
description = "Run ObservabilitySRE smoke tests using docker-compose and RSpec"
81-
// Need to have set up the ruby environment for rspec even through we are running in container
80+
description = "Run ObservabilitySRE smoke tests using RSpec with docker-compose orchestration"
81+
// Need to have set up the ruby environment for rspec
8282
dependsOn(":bootstrap", ":logstash-core:assemble", ":installDevelopmentGems")
8383
inputs.files fileTree("${projectDir}/distributions/internal/observabilitySRE/qa/smoke")
8484
doFirst {
@@ -88,40 +88,20 @@ tasks.register("observabilitySREsmokeTests", Test) {
8888
commandLine 'bash', './generate.sh'
8989
ignoreExitValue = false
9090
}
91-
def result = exec {
92-
workingDir file("distributions/internal/observabilitySRE/qa/smoke/docker")
93-
commandLine 'docker-compose', 'up', '--detach'
94-
ignoreExitValue = true
95-
}
96-
if (result.exitValue != 0) {
97-
throw new GradleException("Docker compose failed to start")
98-
}
99-
// Give containers time to start and show logs
100-
sleep(30000)
101-
exec {
102-
workingDir file("distributions/internal/observabilitySRE/qa/smoke/docker")
103-
commandLine 'docker-compose', 'logs'
104-
}
10591
}
10692
systemProperty 'logstash.root.dir', projectDir.parent
10793
include '**/org/logstash/xpack/test/RSpecObservabilitySRETests.class'
10894
doLast {
109-
exec {
110-
workingDir file("distributions/internal/observabilitySRE/qa/smoke/docker")
111-
commandLine 'docker-compose', 'down', '--volumes'
112-
ignoreExitValue = true
113-
}
11495
// Clean up the generated certificates
11596
delete fileTree("distributions/internal/observabilitySRE/qa/smoke/docker/certs").include("*.key", "*.crt", "*.csr", "*.srl")
11697
}
11798
}
11899

119100
tasks.register("observabilitySREacceptanceTests", Test) {
120-
description = "Run ObservabilitySRE acceptance tests"
121-
// Need to have set up the ruby environment for rspec even through we are running in container
101+
description = "Run ObservabilitySRE acceptance tests using RSpec with docker-compose orchestration"
102+
// Need to have set up the ruby environment for rspec
122103
dependsOn(":bootstrap", ":logstash-core:assemble", ":installDevelopmentGems")
123-
124-
inputs.files fileTree("${projectDir}/distributions/internal/observabilitySRE/qa/smoke")
104+
inputs.files fileTree("${projectDir}/distributions/internal/observabilitySRE/qa/acceptance")
125105
doFirst {
126106
// Generate the certificates first
127107
exec {
@@ -136,4 +116,4 @@ tasks.register("observabilitySREacceptanceTests", Test) {
136116
// Clean up the generated certificates
137117
delete fileTree("distributions/internal/observabilitySRE/qa/acceptance/docker/certs").include("*.key", "*.crt", "*.csr", "*.srl")
138118
}
139-
}
119+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# ObservabilitySRE container DEV guide
2+
3+
This is a top level guide for working on the ObservabiltySRE container locally.
4+
5+
## Building the image
6+
7+
You can use the gradle task in the top level of the logstash dir. This will build an image based on your local checkout.
8+
9+
```
10+
./gradlew --stacktrace artifactDockerObservabilitySRE -PfedrampHighMode=true
11+
```
12+
13+
## Smoke tests
14+
15+
The smoke tests are designed run against an image you have built locally. You can run the smoke tests with the helper in the `ci` dir. This sets the version of the ES fips image based on the logstash version. If you need to override that you can set the environment variables (see the script for details).
16+
17+
```
18+
./ci/observabilitySREsmoke_tests.sh
19+
```
20+
21+
## Acceptance tests
22+
23+
The acceptance tests are meant to run against an image that has been published to the elastic container repository. You can run the acceptance tests with the helper in the `ci` dir. This sets the version of the ES fips image based on the logstash version. If you need to override that you can set the environment variables (see the script for details).
24+
25+
```
26+
./ci/observabilitySREacceptance_tests.sh
27+
```

x-pack/distributions/internal/observabilitySRE/qa/acceptance/spec/acceptance_tests_spec.rb

Lines changed: 20 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -1,83 +1,18 @@
1-
require 'net/http'
2-
require 'uri'
3-
require 'json'
4-
require 'timeout'
1+
require_relative '../../spec/shared_helpers.rb'
52

63
describe "ObservabilitySRE FIPS container" do
7-
def es_request(path, body = nil)
8-
es_url = "https://localhost:9200"
9-
es_user = 'elastic'
10-
es_password = 'changeme'
11-
uri = URI.parse(es_url + path)
12-
http = Net::HTTP.new(uri.host, uri.port)
13-
http.use_ssl = true
14-
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
15-
16-
request = body ? Net::HTTP::Post.new(uri.request_uri) : Net::HTTP::Get.new(uri.request_uri)
17-
request.basic_auth(es_user, es_password)
18-
request["Content-Type"] = "application/json"
19-
request.body = body if body
20-
21-
http.request(request)
22-
end
23-
24-
def wait_until(timeout: 30, interval: 1, message: nil)
25-
Timeout.timeout(timeout) do
26-
loop do
27-
break if yield
28-
sleep interval
29-
end
30-
end
31-
rescue Timeout::Error
32-
raise message || "Condition not met within #{timeout} seconds"
33-
end
34-
35-
def wait_for_elasticsearch(max_retries = 120)
36-
retries = 0
37-
ready = false
38-
39-
while !ready && retries < max_retries
40-
begin
41-
response = es_request("/_cluster/health")
42-
if response.code == "200"
43-
health = JSON.parse(response.body)
44-
if ["green", "yellow"].include?(health["status"])
45-
ready = true
46-
end
47-
end
48-
rescue => e
49-
puts "Waiting for Elasticsearch: #{e.message}"
50-
ensure
51-
unless ready
52-
retries += 1
53-
sleep 1
54-
puts "Retry #{retries}/#{max_retries}"
55-
end
56-
end
57-
end
58-
59-
raise "System not ready after #{max_retries} seconds" unless ready
60-
end
61-
62-
def docker_compose_invoke(subcommand, env={})
63-
env_str = env.map{ |k,v| "#{k.to_s.upcase}=#{Shellwords.escape(v)} "}.join
64-
work_dir = Pathname.new("#{__dir__}/../docker").cleanpath
65-
command = "#{env_str}docker-compose --project-directory=#{Shellwords.escape(work_dir)} #{subcommand}"
66-
system(command) or fail "Failed to invoke Docker Compose with command `#{command}`"
67-
end
68-
69-
def docker_compose_up(env={}) = docker_compose_invoke("up --detach", env)
70-
71-
def docker_compose_down(env={}) = docker_compose_invoke("down --volumes", env)
4+
include SharedHelpers
725

736
context "when running LS to ES with FIPS-compliant configuration" do
747
before(:all) do
75-
docker_compose_up
8+
work_dir = File.expand_path("../docker", __dir__)
9+
docker_compose_up({}, work_dir)
7610
wait_for_elasticsearch
7711
end
7812

7913
after(:all) do
80-
docker_compose_down
14+
work_dir = File.expand_path("../docker", __dir__)
15+
docker_compose_down({}, work_dir)
8116
end
8217

8318
it "data flows from Logstash to Elasticsearch using FIPS-approved SSL" do
@@ -100,12 +35,14 @@ def docker_compose_down(env={}) = docker_compose_invoke("down --volumes", env)
10035

10136
context "when running LS to ES with non-FIPS compliant configuration" do
10237
before(:all) do
103-
docker_compose_up({"LOGSTASH_PIPELINE" => "logstash-to-elasticsearch-weak.conf"})
38+
work_dir = File.expand_path("../docker", __dir__)
39+
docker_compose_up({"LOGSTASH_PIPELINE" => "logstash-to-elasticsearch-weak.conf"}, work_dir)
10440
wait_for_elasticsearch
10541
end
10642

10743
after(:all) do
108-
docker_compose_down
44+
work_dir = File.expand_path("../docker", __dir__)
45+
docker_compose_down({}, work_dir)
10946
end
11047

11148
it "prevents data flow when using TLSv1.1 which is not FIPS-compliant" do
@@ -129,14 +66,16 @@ def docker_compose_down(env={}) = docker_compose_invoke("down --volumes", env)
12966

13067
context "When running Filebeat through LS to ES in a FIPS compliant configuration" do
13168
before(:all) do
132-
docker_compose_up({"LOGSTASH_PIPELINE" => "filebeat-to-ls-to-es.conf"})
69+
work_dir = File.expand_path("../docker", __dir__)
70+
docker_compose_up({"LOGSTASH_PIPELINE" => "filebeat-to-ls-to-es.conf"}, work_dir)
13371
wait_for_elasticsearch
13472
end
135-
73+
13674
after(:all) do
137-
docker_compose_down
75+
work_dir = File.expand_path("../docker", __dir__)
76+
docker_compose_down({}, work_dir)
13877
end
139-
78+
14079
it "data flows from Filebeat through Logstash to Elasticsearch" do
14180
# Wait for index to appear, indicating data is flowing
14281
wait_until(timeout: 30, message: "Index filebeat-test not found") do
@@ -157,12 +96,14 @@ def docker_compose_down(env={}) = docker_compose_invoke("down --volumes", env)
15796

15897
context "when running Filebeat through LS to ES with non-FIPS compliant configuration" do
15998
before(:all) do
160-
docker_compose_up({"LOGSTASH_PIPELINE" => "filebeat-to-ls-weak.conf"})
99+
work_dir = File.expand_path("../docker", __dir__)
100+
docker_compose_up({"LOGSTASH_PIPELINE" => "filebeat-to-ls-weak.conf"}, work_dir)
161101
wait_for_elasticsearch
162102
end
163103

164104
after(:all) do
165-
docker_compose_down
105+
work_dir = File.expand_path("../docker", __dir__)
106+
docker_compose_down({}, work_dir)
166107
end
167108

168109
it "prevents data flow when using TLSv1.1 which is not FIPS-compliant" do

x-pack/distributions/internal/observabilitySRE/qa/smoke/docker/docker-compose.yml

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,14 @@
1-
version: '3'
2-
31
services:
42
elasticsearch:
5-
image: docker.elastic.co/cloud-release/elasticsearch-cloud-ess-fips:8.19.0-SNAPSHOT
3+
image: docker.elastic.co/cloud-release/elasticsearch-cloud-ess-fips:${ELASTICSEARCH_IMAGE_VERSION:-8.19.0-SNAPSHOT}
64
environment:
75
- discovery.type=single-node
8-
- xpack.security.enabled=true
6+
- ES_JAVA_OPTS=-Xms1g -Xmx1g
97
- ELASTIC_PASSWORD=changeme
10-
- ES_JAVA_OPTS=-Xms512m -Xmx512m
11-
- xpack.security.http.ssl.enabled=true
12-
- xpack.security.http.ssl.key=/usr/share/elasticsearch/config/certs/elasticsearch.key
13-
- xpack.security.http.ssl.certificate=/usr/share/elasticsearch/config/certs/elasticsearch.crt
14-
- xpack.security.http.ssl.certificate_authorities=/usr/share/elasticsearch/config/certs/ca.crt
15-
- xpack.security.transport.ssl.enabled=true
16-
- xpack.security.transport.ssl.key=/usr/share/elasticsearch/config/certs/elasticsearch.key
17-
- xpack.security.transport.ssl.certificate=/usr/share/elasticsearch/config/certs/elasticsearch.crt
18-
- xpack.security.transport.ssl.certificate_authorities=/usr/share/elasticsearch/config/certs/ca.crt
198
ports:
209
- "9200:9200"
2110
volumes:
11+
- ./elasticsearch/config/${ELASTICSEARCH_CONFIG:-elasticsearch-fips.yml}:/usr/share/elasticsearch/config/elasticsearch.yml
2212
- ./certs:/usr/share/elasticsearch/config/certs
2313
networks:
2414
- smoketest
@@ -40,12 +30,22 @@ services:
4030
- smoketest
4131

4232
filebeat:
43-
image: docker.elastic.co/beats/filebeat:8.19.0-SNAPSHOT
44-
# Test runner mounts volume with non root user, do not require this file be root
45-
entrypoint: "filebeat -e --strict.perms=false"
33+
# The filebeat shipped with the elasticsearch-fips container is built for FIPS support
34+
# There is no stand alone distribution. This uses the shipped version for testing.
35+
image: docker.elastic.co/cloud-release/elasticsearch-cloud-ess-fips:${FILEBEAT_IMAGE_VERSION:-8.19.0-SNAPSHOT}
36+
container_name: fips_test_filebeat
37+
working_dir: /usr/share/filebeat
38+
entrypoint: ["/bin/bash", "-c"]
39+
# Start Filebeat with /tmp for data (always writable)
40+
command:
41+
- |
42+
exec /opt/filebeat/filebeat -e \
43+
--strict.perms=false \
44+
-c /usr/share/filebeat/filebeat.yml \
45+
--path.data /tmp/filebeat_data
4646
volumes:
4747
- ./filebeat/filebeat.yml:/usr/share/filebeat/filebeat.yml:ro
48-
- ./certs:/usr/share/filebeat/certs
48+
- ./certs:/usr/share/filebeat/certs:ro
4949
- ./test-logs:/test-logs:ro
5050
depends_on:
5151
- logstash
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Elasticsearch settings
2+
discovery.type: single-node
3+
http.port: 9200
4+
network.host: 0.0.0.0
5+
# Security settings
6+
xpack.security.enabled: true
7+
xpack.security.transport.ssl.enabled: true
8+
xpack.security.transport.ssl.verification_mode: certificate
9+
xpack.security.transport.ssl.key: /usr/share/elasticsearch/config/certs/elasticsearch.key
10+
xpack.security.transport.ssl.certificate: /usr/share/elasticsearch/config/certs/elasticsearch.crt
11+
xpack.security.transport.ssl.certificate_authorities: ["/usr/share/elasticsearch/config/certs/ca.crt"]
12+
xpack.security.http.ssl.enabled: true
13+
xpack.security.http.ssl.key: /usr/share/elasticsearch/config/certs/elasticsearch.key
14+
xpack.security.http.ssl.certificate: /usr/share/elasticsearch/config/certs/elasticsearch.crt
15+
xpack.security.http.ssl.certificate_authorities: ["/usr/share/elasticsearch/config/certs/ca.crt"]

0 commit comments

Comments
 (0)