From c9136f2ec8d76751c35487ba4139e1986074a577 Mon Sep 17 00:00:00 2001
From: Eugene <54681898+jimf5@users.noreply.github.com>
Date: Thu, 19 Dec 2024 17:53:38 -0800
Subject: [PATCH 1/8] Verify custom resource attributes support (#32).
Co-authored-by: p-pautov <37922380+p-pautov@users.noreply.github.com>
---
tests/test_otel.py | 32 +++++++++++++++++++++++++++++---
tests/trace_service.py | 14 +++++++++-----
2 files changed, 38 insertions(+), 8 deletions(-)
diff --git a/tests/test_otel.py b/tests/test_otel.py
index 10ce2fe..11caa85 100644
--- a/tests/test_otel.py
+++ b/tests/test_otel.py
@@ -28,7 +28,7 @@ http {
}
otel_trace on;
- otel_service_name test_service;
+ {{ resource_attrs }}
server {
listen 127.0.0.1:18443 ssl;
@@ -240,7 +240,7 @@ def test_context(client, trace_service, parent, path):
@pytest.mark.parametrize(
"nginx_config",
- [({"interval": "200ms", "scheme": "http://"})],
+ [{"interval": "200ms", "scheme": "http://"}],
indirect=True,
)
@pytest.mark.parametrize("batch_count", [1, 3])
@@ -257,8 +257,34 @@ def test_batches(client, trace_service, batch_count):
assert len(trace_service.batches) == batch_count
for batch in trace_service.batches:
- assert get_attr(batch[0].resource, "service.name") == "test_service"
+ assert (
+ get_attr(batch[0].resource, "service.name")
+ == "unknown_service:nginx"
+ )
assert len(batch[0].scope_spans[0].spans) == batch_size
time.sleep(0.3) # wait for +1 request to be flushed
trace_service.batches.clear()
+
+
+@pytest.mark.parametrize(
+ "nginx_config",
+ [
+ {
+ "resource_attrs": """
+ otel_service_name "test_service";
+ otel_resource_attr my.name "my name";
+ otel_resource_attr my.service "my service";
+ """,
+ }
+ ],
+ indirect=True,
+)
+def test_custom_resource_attributes(client, trace_service):
+ assert client.get("http://127.0.0.1:18080/ok").status_code == 200
+
+ batch = trace_service.get_batch()
+
+ assert get_attr(batch.resource, "service.name") == "test_service"
+ assert get_attr(batch.resource, "my.name") == "my name"
+ assert get_attr(batch.resource, "my.service") == "my service"
diff --git a/tests/trace_service.py b/tests/trace_service.py
index 9f094f9..3b191a1 100644
--- a/tests/trace_service.py
+++ b/tests/trace_service.py
@@ -14,16 +14,20 @@ class TraceService(trace_service_pb2_grpc.TraceServiceServicer):
self.batches.append(request.resource_spans)
return trace_service_pb2.ExportTracePartialSuccess()
- def get_span(self):
+ def get_batch(self):
for _ in range(10):
if len(self.batches):
break
time.sleep(0.001)
+ assert len(self.batches) == 1
+ assert len(self.batches[0]) == 1
+ return self.batches.pop()[0]
- assert len(self.batches) == 1, "No spans received"
- span = self.batches[0][0].scope_spans[0].spans.pop()
- self.batches.clear()
- return span
+ def get_span(self):
+ batch = self.get_batch()
+ assert len(batch.scope_spans) == 1
+ assert len(batch.scope_spans[0].spans) == 1
+ return batch.scope_spans[0].spans.pop()
@pytest.fixture(scope="module")
From f633a8eef23cdc5f4c4e980605b981cf75595a14 Mon Sep 17 00:00:00 2001
From: Pavel Pautov
Date: Thu, 21 Nov 2024 13:57:43 -0800
Subject: [PATCH 2/8] Fail early if "trusted_certificate" is a directory.
Previously, the error was caused by enormous std::string allocation.
---
src/http_module.cpp | 13 ++++++++-----
1 file changed, 8 insertions(+), 5 deletions(-)
diff --git a/src/http_module.cpp b/src/http_module.cpp
index df5702e..bc08b23 100644
--- a/src/http_module.cpp
+++ b/src/http_module.cpp
@@ -711,7 +711,8 @@ char* addResourceAttr(ngx_conf_t* cf, ngx_command_t* cmd, void* conf)
return NGX_CONF_OK;
}
-char* setTrustedCertificate(ngx_conf_t* cf, ngx_command_t* cmd, void* conf) {
+char* setTrustedCertificate(ngx_conf_t* cf, ngx_command_t* cmd, void* conf)
+{
auto path = ((ngx_str_t*)cf->args->elts)[1];
auto mcf = getMainConf(cf);
@@ -727,11 +728,13 @@ char* setTrustedCertificate(ngx_conf_t* cf, ngx_command_t* cmd, void* conf) {
return (char*)NGX_CONF_ERROR;
}
file.exceptions(std::ios::failbit | std::ios::badbit);
- file.seekg(0, std::ios::end);
- size_t size = file.tellg();
- mcf->trustedCert.resize(size);
+ file.peek(); // trigger early error for dirs
+
+ size_t size = file.seekg(0, std::ios::end).tellg();
file.seekg(0);
- file.read(&mcf->trustedCert[0], mcf->trustedCert.size());
+
+ mcf->trustedCert.resize(size);
+ file.read(&mcf->trustedCert[0], size);
} catch (const std::exception& e) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"failed to read \"%V\": %s", &path, e.what());
From 88a64bb2c3027be87057efedaa84d0c75d68610e Mon Sep 17 00:00:00 2001
From: Pavel Pautov
Date: Thu, 21 Nov 2024 21:46:01 -0800
Subject: [PATCH 3/8] Consolidate transport related parameters into a struct.
Also, replace leftover cast with getMainConf().
---
src/batch_exporter.hpp | 4 ++--
src/http_module.cpp | 11 +++++++----
src/trace_service_client.hpp | 16 +++++++++++-----
3 files changed, 20 insertions(+), 11 deletions(-)
diff --git a/src/batch_exporter.hpp b/src/batch_exporter.hpp
index cb3e075..a2e65b1 100644
--- a/src/batch_exporter.hpp
+++ b/src/batch_exporter.hpp
@@ -111,10 +111,10 @@ public:
int attrSize{0};
};
- BatchExporter(StrView target, bool ssl, const std::string& trustedCert,
+ BatchExporter(const Target& target,
size_t batchSize, size_t batchCount,
const std::map& resourceAttrs) :
- batchSize(batchSize), client(std::string(target), ssl, trustedCert)
+ batchSize(batchSize), client(target)
{
free.reserve(batchCount);
while (batchCount-- > 0) {
diff --git a/src/http_module.cpp b/src/http_module.cpp
index bc08b23..93898b1 100644
--- a/src/http_module.cpp
+++ b/src/http_module.cpp
@@ -576,10 +576,13 @@ ngx_int_t initWorkerProcess(ngx_cycle_t* cycle)
}
try {
+ Target target;
+ target.endpoint = std::string(toStrView(mcf->endpoint));
+ target.ssl = mcf->ssl;
+ target.trustedCert = mcf->trustedCert;
+
gExporter.reset(new BatchExporter(
- toStrView(mcf->endpoint),
- mcf->ssl,
- mcf->trustedCert,
+ target,
mcf->batchSize,
mcf->batchCount,
mcf->resourceAttrs));
@@ -772,7 +775,7 @@ void* createMainConf(ngx_conf_t* cf)
char* initMainConf(ngx_conf_t* cf, void* conf)
{
- auto mcf = (MainConf*)conf;
+ auto mcf = getMainConf(cf);
ngx_conf_init_msec_value(mcf->interval, 5000);
ngx_conf_init_size_value(mcf->batchSize, 512);
diff --git a/src/trace_service_client.hpp b/src/trace_service_client.hpp
index d248f00..485143c 100644
--- a/src/trace_service_client.hpp
+++ b/src/trace_service_client.hpp
@@ -8,6 +8,12 @@
namespace otel_proto_trace = opentelemetry::proto::collector::trace::v1;
+struct Target {
+ std::string endpoint;
+ bool ssl;
+ std::string trustedCert;
+};
+
class TraceServiceClient {
public:
typedef otel_proto_trace::ExportTraceServiceRequest Request;
@@ -17,18 +23,18 @@ public:
typedef std::function
ResponseCb;
- TraceServiceClient(const std::string& target, bool ssl,
- const std::string& trustedCert)
+ TraceServiceClient(const Target& target)
{
std::shared_ptr creds;
- if (ssl) {
+ if (target.ssl) {
grpc::SslCredentialsOptions options;
- options.pem_root_certs = trustedCert;
+ options.pem_root_certs = target.trustedCert;
+
creds = grpc::SslCredentials(options);
} else {
creds = grpc::InsecureChannelCredentials();
}
- auto channel = grpc::CreateChannel(target, creds);
+ auto channel = grpc::CreateChannel(target.endpoint, creds);
channel->GetState(true); // trigger 'connecting' state
stub = TraceService::NewStub(channel);
From a45a594801fbd57657fd821bdd298a39d4575175 Mon Sep 17 00:00:00 2001
From: Pavel Pautov
Date: Mon, 2 Dec 2024 21:07:38 -0800
Subject: [PATCH 4/8] Support sending custom headers to export endpoint (fix
#62).
The headers are configured by "header" directive in "otel_exporter" block, e.g.
otel_exporter {
endpoint localhost:4317;
header X-API-Token "token value";
}
---
src/http_module.cpp | 36 +++++++++++++++++++++++++++++++++++-
src/trace_service_client.hpp | 23 ++++++++++++++++++++++-
2 files changed, 57 insertions(+), 2 deletions(-)
diff --git a/src/http_module.cpp b/src/http_module.cpp
index 93898b1..ef77ffb 100644
--- a/src/http_module.cpp
+++ b/src/http_module.cpp
@@ -30,6 +30,7 @@ struct MainConf : MainConfBase {
std::map resourceAttrs;
bool ssl;
std::string trustedCert;
+ Target::HeaderVec headers;
};
struct SpanAttr {
@@ -49,6 +50,7 @@ char* setExporter(ngx_conf_t* cf, ngx_command_t* cmd, void* conf);
char* addResourceAttr(ngx_conf_t* cf, ngx_command_t* cmd, void* conf);
char* addSpanAttr(ngx_conf_t* cf, ngx_command_t* cmd, void* conf);
char* setTrustedCertificate(ngx_conf_t* cf, ngx_command_t* cmd, void* conf);
+char* addExporterHeader(ngx_conf_t* cf, ngx_command_t* cmd, void* conf);
namespace Propagation {
@@ -120,6 +122,10 @@ ngx_command_t gExporterCommands[] = {
NGX_CONF_TAKE1,
setTrustedCertificate },
+ { ngx_string("header"),
+ NGX_CONF_TAKE2,
+ addExporterHeader },
+
{ ngx_string("interval"),
NGX_CONF_TAKE1,
ngx_conf_set_msec_slot,
@@ -580,6 +586,7 @@ ngx_int_t initWorkerProcess(ngx_cycle_t* cycle)
target.endpoint = std::string(toStrView(mcf->endpoint));
target.ssl = mcf->ssl;
target.trustedCert = mcf->trustedCert;
+ target.headers = mcf->headers;
gExporter.reset(new BatchExporter(
target,
@@ -651,7 +658,7 @@ char* setExporter(ngx_conf_t* cf, ngx_command_t* cmd, void* conf)
continue;
}
- if (cf->args->nelts != 2) {
+ if (cf->args->nelts != static_cast(ffs(cmd->type))) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"invalid number of arguments in \"%V\" "
"directive of \"otel_exporter\"", name);
@@ -747,6 +754,33 @@ char* setTrustedCertificate(ngx_conf_t* cf, ngx_command_t* cmd, void* conf)
return NGX_CONF_OK;
}
+char* addExporterHeader(ngx_conf_t* cf, ngx_command_t* cmd, void* conf)
+{
+ auto args = (ngx_str_t*)cf->args->elts;
+
+ // don't force on users lower case name requirement of gRPC
+ ngx_strlow(args[1].data, args[1].data, args[1].len);
+
+ try {
+ // validate header here to avoid runtime assert failure in gRPC
+ auto name = toStrView(args[1]);
+ if (!Target::validateHeaderName(name)) {
+ return (char*)"has invalid header name";
+ }
+ auto value = toStrView(args[2]);
+ if (!Target::validateHeaderValue(value)) {
+ return (char*)"has invalid header value";
+ }
+
+ getMainConf(cf)->headers.emplace_back(name, value);
+ } catch (const std::exception& e) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "OTel: %s", e.what());
+ return (char*)NGX_CONF_ERROR;
+ }
+
+ return NGX_CONF_OK;
+}
+
void* createMainConf(ngx_conf_t* cf)
{
auto cln = ngx_pool_cleanup_add(cf->pool, sizeof(MainConf));
diff --git a/src/trace_service_client.hpp b/src/trace_service_client.hpp
index 485143c..4ed92e7 100644
--- a/src/trace_service_client.hpp
+++ b/src/trace_service_client.hpp
@@ -9,9 +9,24 @@
namespace otel_proto_trace = opentelemetry::proto::collector::trace::v1;
struct Target {
+ typedef std::vector> HeaderVec;
+
std::string endpoint;
bool ssl;
std::string trustedCert;
+ HeaderVec headers;
+
+ static bool validateHeaderName(StrView name)
+ {
+ return grpc_header_key_is_legal(
+ grpc_slice_from_static_buffer(name.data(), name.size()));
+ }
+
+ static bool validateHeaderValue(StrView value)
+ {
+ return grpc_header_nonbin_value_is_legal(
+ grpc_slice_from_static_buffer(value.data(), value.size()));
+ }
};
class TraceServiceClient {
@@ -23,7 +38,7 @@ public:
typedef std::function
ResponseCb;
- TraceServiceClient(const Target& target)
+ TraceServiceClient(const Target& target) : headers(target.headers)
{
std::shared_ptr creds;
if (target.ssl) {
@@ -44,6 +59,10 @@ public:
{
std::unique_ptr call{new ActiveCall{}};
+ for (auto& header : headers) {
+ call->context.AddMetadata(header.first, header.second);
+ }
+
call->request = std::move(req);
call->cb = std::move(cb);
@@ -113,6 +132,8 @@ private:
ResponseCb cb;
};
+ Target::HeaderVec headers;
+
std::unique_ptr stub;
grpc::CompletionQueue queue;
From 9dc4dc2803cc2e7e37f5c73fee7f8d342101aa41 Mon Sep 17 00:00:00 2001
From: Pavel Pautov
Date: Thu, 19 Dec 2024 21:28:17 -0800
Subject: [PATCH 5/8] Verify custom exporter headers support (#62).
---
tests/test_otel.py | 25 +++++++++++++++++++++++++
tests/trace_service.py | 11 ++++++++---
2 files changed, 33 insertions(+), 3 deletions(-)
diff --git a/tests/test_otel.py b/tests/test_otel.py
index 11caa85..513c1f1 100644
--- a/tests/test_otel.py
+++ b/tests/test_otel.py
@@ -25,6 +25,8 @@ http {
interval {{ interval or "1ms" }};
batch_size 3;
batch_count 3;
+
+ {{ exporter_opts }}
}
otel_trace on;
@@ -288,3 +290,26 @@ def test_custom_resource_attributes(client, trace_service):
assert get_attr(batch.resource, "service.name") == "test_service"
assert get_attr(batch.resource, "my.name") == "my name"
assert get_attr(batch.resource, "my.service") == "my service"
+
+
+@pytest.mark.parametrize(
+ "nginx_config",
+ [
+ {
+ "exporter_opts": """
+ header X-API-TOKEN api.value;
+ header Authorization "Basic value";
+ """,
+ }
+ ],
+ indirect=True,
+)
+@pytest.mark.parametrize("trace_service", ["skip_otelcol"], indirect=True)
+def test_exporter_headers(client, trace_service):
+ assert client.get("http://127.0.0.1:18080/ok").status_code == 200
+
+ assert trace_service.get_span().name == "/ok"
+
+ headers = dict(trace_service.last_metadata)
+ assert headers["x-api-token"] == "api.value"
+ assert headers["authorization"] == "Basic value"
diff --git a/tests/trace_service.py b/tests/trace_service.py
index 3b191a1..f47b104 100644
--- a/tests/trace_service.py
+++ b/tests/trace_service.py
@@ -12,6 +12,7 @@ class TraceService(trace_service_pb2_grpc.TraceServiceServicer):
def Export(self, request, context):
self.batches.append(request.resource_spans)
+ self.last_metadata = context.invocation_metadata()
return trace_service_pb2.ExportTracePartialSuccess()
def get_batch(self):
@@ -31,13 +32,17 @@ class TraceService(trace_service_pb2_grpc.TraceServiceServicer):
@pytest.fixture(scope="module")
-def trace_service(pytestconfig, logger):
+def trace_service(request, pytestconfig, logger):
server = grpc.server(concurrent.futures.ThreadPoolExecutor())
trace_service = TraceService()
trace_service_pb2_grpc.add_TraceServiceServicer_to_server(
trace_service, server
)
- listen_addr = f"127.0.0.1:{24317 if pytestconfig.option.otelcol else 14317}"
+ trace_service.use_otelcol = (
+ pytestconfig.option.otelcol
+ and getattr(request, "param", "") != "skip_otelcol"
+ )
+ listen_addr = f"127.0.0.1:{24317 if trace_service.use_otelcol else 14317}"
server.add_insecure_port(listen_addr)
logger.info(f"Starting trace service at {listen_addr}...")
server.start()
@@ -48,7 +53,7 @@ def trace_service(pytestconfig, logger):
@pytest.fixture(scope="module")
def otelcol(pytestconfig, testdir, logger, trace_service):
- if pytestconfig.option.otelcol is None:
+ if not trace_service.use_otelcol:
yield
return
From f578402f196499edd2a65c31020570fc37e1bdbf Mon Sep 17 00:00:00 2001
From: Eugene Grebenschikov
Date: Fri, 20 Dec 2024 17:24:27 -0800
Subject: [PATCH 6/8] Verify export via TLS (#12).
Co-authored-by: Pavel Pautov
---
tests/conftest.py | 19 ++++++++++---------
tests/test_otel.py | 20 ++++++++++++++++++--
tests/trace_service.py | 20 ++++++++++++++++----
3 files changed, 44 insertions(+), 15 deletions(-)
diff --git a/tests/conftest.py b/tests/conftest.py
index 7978759..25933e4 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -19,7 +19,7 @@ def pytest_addoption(parser):
parser.addoption("--globals", default="")
-def self_signed_cert(test_dir, name):
+def self_signed_cert(name):
k = crypto.PKey()
k.generate_key(crypto.TYPE_RSA, 2048)
cert = crypto.X509()
@@ -29,11 +29,9 @@ def self_signed_cert(test_dir, name):
cert.gmtime_adj_notAfter(365 * 86400) # 365 days
cert.set_pubkey(k)
cert.sign(k, "sha512")
- (test_dir / f"{name}.key").write_text(
- crypto.dump_privatekey(crypto.FILETYPE_PEM, k).decode("utf-8")
- )
- (test_dir / f"{name}.crt").write_text(
- crypto.dump_certificate(crypto.FILETYPE_PEM, cert).decode("utf-8")
+ return (
+ crypto.dump_privatekey(crypto.FILETYPE_PEM, k),
+ crypto.dump_certificate(crypto.FILETYPE_PEM, cert),
)
@@ -66,7 +64,7 @@ def nginx_config(request, pytestconfig, testdir, logger):
@pytest.fixture(scope="module")
-def nginx(testdir, pytestconfig, nginx_config, certs, logger, otelcol):
+def nginx(testdir, pytestconfig, nginx_config, cert, logger, otelcol):
(testdir / "nginx.conf").write_text(nginx_config)
logger.info("Starting nginx...")
proc = subprocess.Popen(
@@ -96,5 +94,8 @@ def nginx(testdir, pytestconfig, nginx_config, certs, logger, otelcol):
@pytest.fixture(scope="module")
-def certs(testdir):
- self_signed_cert(testdir, "localhost")
+def cert(testdir):
+ key, cert = self_signed_cert("localhost")
+ (testdir / "localhost.key").write_text(key.decode("utf-8"))
+ (testdir / "localhost.crt").write_text(cert.decode("utf-8"))
+ yield (key, cert)
diff --git a/tests/test_otel.py b/tests/test_otel.py
index 513c1f1..fef771a 100644
--- a/tests/test_otel.py
+++ b/tests/test_otel.py
@@ -21,7 +21,7 @@ http {
ssl_certificate_key localhost.key;
otel_exporter {
- endpoint {{ scheme }}127.0.0.1:14317;
+ endpoint {{ endpoint or "127.0.0.1:14317" }};
interval {{ interval or "1ms" }};
batch_size 3;
batch_count 3;
@@ -242,7 +242,7 @@ def test_context(client, trace_service, parent, path):
@pytest.mark.parametrize(
"nginx_config",
- [{"interval": "200ms", "scheme": "http://"}],
+ [{"interval": "200ms", "endpoint": "http://127.0.0.1:14317"}],
indirect=True,
)
@pytest.mark.parametrize("batch_count", [1, 3])
@@ -313,3 +313,19 @@ def test_exporter_headers(client, trace_service):
headers = dict(trace_service.last_metadata)
assert headers["x-api-token"] == "api.value"
assert headers["authorization"] == "Basic value"
+
+
+@pytest.mark.parametrize(
+ "nginx_config",
+ [
+ {
+ "endpoint": "https://localhost:14318",
+ "exporter_opts": "trusted_certificate localhost.crt;",
+ }
+ ],
+ indirect=True,
+)
+def test_tls_export(client, trace_service):
+ assert client.get("http://127.0.0.1:18080/ok").status_code == 200
+
+ assert trace_service.get_span().name == "/ok"
diff --git a/tests/trace_service.py b/tests/trace_service.py
index f47b104..5ef2bc6 100644
--- a/tests/trace_service.py
+++ b/tests/trace_service.py
@@ -32,7 +32,7 @@ class TraceService(trace_service_pb2_grpc.TraceServiceServicer):
@pytest.fixture(scope="module")
-def trace_service(request, pytestconfig, logger):
+def trace_service(request, pytestconfig, logger, cert):
server = grpc.server(concurrent.futures.ThreadPoolExecutor())
trace_service = TraceService()
trace_service_pb2_grpc.add_TraceServiceServicer_to_server(
@@ -44,6 +44,10 @@ def trace_service(request, pytestconfig, logger):
)
listen_addr = f"127.0.0.1:{24317 if trace_service.use_otelcol else 14317}"
server.add_insecure_port(listen_addr)
+ if not trace_service.use_otelcol:
+ creds = grpc.ssl_server_credentials([cert])
+ server.add_secure_port("127.0.0.1:14318", creds)
+ listen_addr += " and 127.0.0.1:14318"
logger.info(f"Starting trace service at {listen_addr}...")
server.start()
yield trace_service
@@ -52,18 +56,26 @@ def trace_service(request, pytestconfig, logger):
@pytest.fixture(scope="module")
-def otelcol(pytestconfig, testdir, logger, trace_service):
+def otelcol(pytestconfig, testdir, logger, trace_service, cert):
if not trace_service.use_otelcol:
yield
return
(testdir / "otel-config.yaml").write_text(
- """receivers:
+ f"""receivers:
otlp:
protocols:
grpc:
endpoint: 127.0.0.1:14317
+ otlp/tls:
+ protocols:
+ grpc:
+ endpoint: 127.0.0.1:14318
+ tls:
+ cert_file: {testdir}/localhost.crt
+ key_file: {testdir}/localhost.key
+
exporters:
otlp:
endpoint: 127.0.0.1:24317
@@ -73,7 +85,7 @@ exporters:
service:
pipelines:
traces:
- receivers: [otlp]
+ receivers: [otlp, otlp/tls]
exporters: [otlp]
telemetry:
metrics:
From 72d8eed53af4c2cd6f3e30a2efe0e38d66f5e176 Mon Sep 17 00:00:00 2001
From: Pavel Pautov
Date: Tue, 21 Jan 2025 23:02:39 -0800
Subject: [PATCH 7/8] Fix build against Nginx 1.22 (fix #85).
---
src/http_module.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/http_module.cpp b/src/http_module.cpp
index ef77ffb..78a5e89 100644
--- a/src/http_module.cpp
+++ b/src/http_module.cpp
@@ -296,10 +296,10 @@ ngx_int_t setHeader(ngx_http_request_t* r, StrView name, StrView value)
return NGX_ERROR;
}
+ *header = {};
header->hash = hash;
header->key = toNgxStr(name);
header->lowcase_key = header->key.data;
- header->next = NULL;
}
header->value = toNgxStr(value);
From 22d6380458c115b75ec7ed7d759bb47231f3d1f6 Mon Sep 17 00:00:00 2001
From: Pavel Pautov
Date: Thu, 27 Mar 2025 19:35:53 -0700
Subject: [PATCH 8/8] Add CI workflow for Alpine Linux.
The workflow uses Nginx build system with OS provided gRPC.
---
.github/workflows/alpine.yml | 45 ++++++++++++++++++++++++++++++++++++
.github/workflows/ubuntu.yml | 2 +-
2 files changed, 46 insertions(+), 1 deletion(-)
create mode 100644 .github/workflows/alpine.yml
diff --git a/.github/workflows/alpine.yml b/.github/workflows/alpine.yml
new file mode 100644
index 0000000..8dc0cef
--- /dev/null
+++ b/.github/workflows/alpine.yml
@@ -0,0 +1,45 @@
+name: Alpine build
+
+on:
+ push:
+ branches:
+ - main
+ pull_request:
+
+jobs:
+ test:
+ runs-on: ubuntu-latest
+ container: alpine
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v4
+ - name: Install dependencies
+ run: |
+ apk add build-base openssl-dev zlib-dev pcre2-dev \
+ cmake git grpc-dev protobuf-dev \
+ python3
+ - name: Checkout nginx
+ uses: actions/checkout@v4
+ with:
+ repository: nginx/nginx
+ path: nginx
+ - name: Build nginx
+ working-directory: nginx
+ run: |
+ auto/configure --with-compat --with-http_ssl_module \
+ --with-http_v2_module --with-http_v3_module
+ make -j $(nproc)
+ - name: Build module
+ working-directory: nginx
+ run: |
+ NGX_OTEL_CMAKE_OPTS="-D NGX_OTEL_GRPC=package" \
+ auto/configure --with-compat --add-dynamic-module=..
+ make -j $(nproc) modules
+ - name: Install test dependencies
+ run: |
+ python -m venv tests-venv
+ tests-venv/bin/pip install -r tests/requirements.txt
+ - name: Run tests
+ run: |
+ tests-venv/bin/pytest tests --maxfail=10 --nginx=nginx/objs/nginx \
+ --module=nginx/objs/ngx_otel_module.so
diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml
index 0f328d2..07be30e 100644
--- a/.github/workflows/ubuntu.yml
+++ b/.github/workflows/ubuntu.yml
@@ -7,7 +7,7 @@ on:
pull_request:
jobs:
- build-module:
+ test:
runs-on: ubuntu-22.04
steps:
- name: Checkout repository