diff --git a/incubator/catalog-schema-registry.spec/src/main/resources/META-INF/zilla/schema_registry.idl b/incubator/catalog-schema-registry.spec/src/main/resources/META-INF/zilla/schema_registry.idl index df61e3605c..ae86ba3c4c 100644 --- a/incubator/catalog-schema-registry.spec/src/main/resources/META-INF/zilla/schema_registry.idl +++ b/incubator/catalog-schema-registry.spec/src/main/resources/META-INF/zilla/schema_registry.idl @@ -21,16 +21,16 @@ scope schema_registry REMOTE_ACCESS_REJECTED (1) } - struct SchemaRegistryRemoteAccessRejected extends core::event::Event + struct SchemaRegistryRemoteAccessRejectedEx extends core::stream::Extension { string8 method; string16 url; int16 status; } - union SchemaRegistryEvent switch (SchemaRegistryEventType) + union SchemaRegistryEventEx switch (SchemaRegistryEventType) { - case REMOTE_ACCESS_REJECTED: SchemaRegistryRemoteAccessRejected remoteAccessRejected; + case REMOTE_ACCESS_REJECTED: SchemaRegistryRemoteAccessRejectedEx remoteAccessRejected; } } } diff --git a/incubator/exporter-stdout.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/config/client.yaml b/incubator/catalog-schema-registry.spec/src/main/scripts/io/aklivity/zilla/specs/catalog/schema/registry/config/event.yaml similarity index 62% rename from incubator/exporter-stdout.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/config/client.yaml rename to incubator/catalog-schema-registry.spec/src/main/scripts/io/aklivity/zilla/specs/catalog/schema/registry/config/event.yaml index ff4c4a3aea..7e4e18bc0f 100644 --- a/incubator/exporter-stdout.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/config/client.yaml +++ b/incubator/catalog-schema-registry.spec/src/main/scripts/io/aklivity/zilla/specs/catalog/schema/registry/config/event.yaml @@ -17,10 +17,22 @@ name: test telemetry: exporters: - stdout0: - type: stdout + exporter0: + type: test + options: + events: + - qname: test.catalog0 + message: REMOTE_ACCESS_REJECTED GET http://localhost:8081/schemas/ids/0 0 +catalogs: + catalog0: + type: schema-registry + options: + url: http://localhost:8081 bindings: - app0: - type: kafka - kind: client - exit: net0 + net0: + type: test + kind: server + options: + catalogs: + - catalog0 + exit: app0 diff --git a/incubator/catalog-schema-registry/pom.xml b/incubator/catalog-schema-registry/pom.xml index 22c39b3d02..eb3a2dc794 100644 --- a/incubator/catalog-schema-registry/pom.xml +++ b/incubator/catalog-schema-registry/pom.xml @@ -24,7 +24,7 @@ 11 11 - 0.80 + 0.90 0 diff --git a/incubator/catalog-schema-registry/src/main/java/io/aklivity/zilla/runtime/catalog/schema/registry/internal/SchemaRegistryEventContext.java b/incubator/catalog-schema-registry/src/main/java/io/aklivity/zilla/runtime/catalog/schema/registry/internal/SchemaRegistryEventContext.java index 42770a31b1..baa8c36fb8 100644 --- a/incubator/catalog-schema-registry/src/main/java/io/aklivity/zilla/runtime/catalog/schema/registry/internal/SchemaRegistryEventContext.java +++ b/incubator/catalog-schema-registry/src/main/java/io/aklivity/zilla/runtime/catalog/schema/registry/internal/SchemaRegistryEventContext.java @@ -14,14 +14,17 @@ */ package io.aklivity.zilla.runtime.catalog.schema.registry.internal; +import static io.aklivity.zilla.runtime.catalog.schema.registry.internal.types.event.SchemaRegistryEventType.REMOTE_ACCESS_REJECTED; + import java.net.http.HttpRequest; import java.nio.ByteBuffer; import java.time.Clock; -import org.agrona.MutableDirectBuffer; +import org.agrona.concurrent.AtomicBuffer; import org.agrona.concurrent.UnsafeBuffer; -import io.aklivity.zilla.runtime.catalog.schema.registry.internal.types.event.SchemaRegistryEventFW; +import io.aklivity.zilla.runtime.catalog.schema.registry.internal.types.event.EventFW; +import io.aklivity.zilla.runtime.catalog.schema.registry.internal.types.event.SchemaRegistryEventExFW; import io.aklivity.zilla.runtime.engine.EngineContext; import io.aklivity.zilla.runtime.engine.binding.function.MessageConsumer; @@ -29,8 +32,10 @@ public class SchemaRegistryEventContext { private static final int EVENT_BUFFER_CAPACITY = 1024; - private final SchemaRegistryEventFW.Builder schemaRegistryEventRW = new SchemaRegistryEventFW.Builder(); - private final MutableDirectBuffer eventBuffer = new UnsafeBuffer(ByteBuffer.allocate(EVENT_BUFFER_CAPACITY)); + private final AtomicBuffer eventBuffer = new UnsafeBuffer(ByteBuffer.allocate(EVENT_BUFFER_CAPACITY)); + private final AtomicBuffer extensionBuffer = new UnsafeBuffer(ByteBuffer.allocate(EVENT_BUFFER_CAPACITY)); + private final EventFW.Builder eventRW = new EventFW.Builder(); + private final SchemaRegistryEventExFW.Builder schemaRegistryEventExRW = new SchemaRegistryEventExFW.Builder(); private final int schemaRegistryTypeId; private final MessageConsumer eventWriter; private final Clock clock; @@ -48,17 +53,22 @@ public void remoteAccessRejected( HttpRequest httpRequest, int status) { - SchemaRegistryEventFW event = schemaRegistryEventRW - .wrap(eventBuffer, 0, eventBuffer.capacity()) + SchemaRegistryEventExFW extension = schemaRegistryEventExRW + .wrap(extensionBuffer, 0, extensionBuffer.capacity()) .remoteAccessRejected(e -> e - .timestamp(clock.millis()) - .traceId(0L) - .namespacedId(catalogId) + .typeId(REMOTE_ACCESS_REJECTED.value()) .method(httpRequest.method()) .url(httpRequest.uri().toString()) .status((short) status) ) .build(); + EventFW event = eventRW + .wrap(eventBuffer, 0, eventBuffer.capacity()) + .timestamp(clock.millis()) + .traceId(0L) + .namespacedId(catalogId) + .extension(extension.buffer(), extension.offset(), extension.limit()) + .build(); eventWriter.accept(schemaRegistryTypeId, event.buffer(), event.offset(), event.limit()); } } diff --git a/incubator/catalog-schema-registry/src/main/java/io/aklivity/zilla/runtime/catalog/schema/registry/internal/SchemaRegistryEventFormatter.java b/incubator/catalog-schema-registry/src/main/java/io/aklivity/zilla/runtime/catalog/schema/registry/internal/SchemaRegistryEventFormatter.java new file mode 100644 index 0000000000..73d2ea40ec --- /dev/null +++ b/incubator/catalog-schema-registry/src/main/java/io/aklivity/zilla/runtime/catalog/schema/registry/internal/SchemaRegistryEventFormatter.java @@ -0,0 +1,66 @@ +/* + * Copyright 2021-2023 Aklivity Inc + * + * Licensed under the Aklivity Community License (the "License"); you may not use + * this file except in compliance with the License. You may obtain a copy of the + * License at + * + * https://www.aklivity.io/aklivity-community-license/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package io.aklivity.zilla.runtime.catalog.schema.registry.internal; + +import org.agrona.DirectBuffer; + +import io.aklivity.zilla.runtime.catalog.schema.registry.internal.types.StringFW; +import io.aklivity.zilla.runtime.catalog.schema.registry.internal.types.event.EventFW; +import io.aklivity.zilla.runtime.catalog.schema.registry.internal.types.event.SchemaRegistryEventExFW; +import io.aklivity.zilla.runtime.catalog.schema.registry.internal.types.event.SchemaRegistryRemoteAccessRejectedExFW; +import io.aklivity.zilla.runtime.engine.Configuration; +import io.aklivity.zilla.runtime.engine.event.EventFormatterSpi; + +public final class SchemaRegistryEventFormatter implements EventFormatterSpi +{ + private static final String REMOTE_ACCESS_REJECTED = "REMOTE_ACCESS_REJECTED %s %s %d"; + + private final EventFW eventRO = new EventFW(); + private final SchemaRegistryEventExFW schemaRegistryEventExRO = new SchemaRegistryEventExFW(); + + SchemaRegistryEventFormatter( + Configuration config) + { + } + + public String format( + DirectBuffer buffer, + int index, + int length) + { + final EventFW event = eventRO.wrap(buffer, index, index + length); + final SchemaRegistryEventExFW extension = schemaRegistryEventExRO + .wrap(event.extension().buffer(), event.extension().offset(), event.extension().limit()); + String result = null; + switch (extension.kind()) + { + case REMOTE_ACCESS_REJECTED: + { + SchemaRegistryRemoteAccessRejectedExFW ex = extension.remoteAccessRejected(); + result = String.format(REMOTE_ACCESS_REJECTED, asString(ex.method()), asString(ex.url()), + ex.status()); + break; + } + } + return result; + } + + private static String asString( + StringFW stringFW) + { + String s = stringFW.asString(); + return s == null ? "" : s; + } +} diff --git a/incubator/catalog-schema-registry/src/main/java/io/aklivity/zilla/runtime/catalog/schema/registry/internal/SchemaRegistryEventFormatterFactory.java b/incubator/catalog-schema-registry/src/main/java/io/aklivity/zilla/runtime/catalog/schema/registry/internal/SchemaRegistryEventFormatterFactory.java new file mode 100644 index 0000000000..dab25606c1 --- /dev/null +++ b/incubator/catalog-schema-registry/src/main/java/io/aklivity/zilla/runtime/catalog/schema/registry/internal/SchemaRegistryEventFormatterFactory.java @@ -0,0 +1,34 @@ +/* + * Copyright 2021-2023 Aklivity Inc + * + * Licensed under the Aklivity Community License (the "License"); you may not use + * this file except in compliance with the License. You may obtain a copy of the + * License at + * + * https://www.aklivity.io/aklivity-community-license/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package io.aklivity.zilla.runtime.catalog.schema.registry.internal; + +import io.aklivity.zilla.runtime.engine.Configuration; +import io.aklivity.zilla.runtime.engine.event.EventFormatterFactorySpi; + +public final class SchemaRegistryEventFormatterFactory implements EventFormatterFactorySpi +{ + @Override + public SchemaRegistryEventFormatter create( + Configuration config) + { + return new SchemaRegistryEventFormatter(config); + } + + @Override + public String type() + { + return SchemaRegistryCatalog.NAME; + } +} diff --git a/incubator/catalog-schema-registry/src/main/moditect/module-info.java b/incubator/catalog-schema-registry/src/main/moditect/module-info.java index 3c87217f1f..0481132093 100644 --- a/incubator/catalog-schema-registry/src/main/moditect/module-info.java +++ b/incubator/catalog-schema-registry/src/main/moditect/module-info.java @@ -22,4 +22,7 @@ provides io.aklivity.zilla.runtime.engine.config.OptionsConfigAdapterSpi with io.aklivity.zilla.runtime.catalog.schema.registry.internal.config.SchemaRegistryOptionsConfigAdapter; + + provides io.aklivity.zilla.runtime.engine.event.EventFormatterFactorySpi + with io.aklivity.zilla.runtime.catalog.schema.registry.internal.SchemaRegistryEventFormatterFactory; } diff --git a/incubator/catalog-schema-registry/src/main/resources/META-INF/services/io.aklivity.zilla.runtime.engine.event.EventFormatterFactorySpi b/incubator/catalog-schema-registry/src/main/resources/META-INF/services/io.aklivity.zilla.runtime.engine.event.EventFormatterFactorySpi new file mode 100644 index 0000000000..dc17437b9b --- /dev/null +++ b/incubator/catalog-schema-registry/src/main/resources/META-INF/services/io.aklivity.zilla.runtime.engine.event.EventFormatterFactorySpi @@ -0,0 +1 @@ +io.aklivity.zilla.runtime.catalog.schema.registry.internal.SchemaRegistryEventFormatterFactory \ No newline at end of file diff --git a/incubator/catalog-schema-registry/src/test/java/io/aklivity/zilla/runtime/catalog/schema/registry/internal/EventIT.java b/incubator/catalog-schema-registry/src/test/java/io/aklivity/zilla/runtime/catalog/schema/registry/internal/EventIT.java new file mode 100644 index 0000000000..a558900735 --- /dev/null +++ b/incubator/catalog-schema-registry/src/test/java/io/aklivity/zilla/runtime/catalog/schema/registry/internal/EventIT.java @@ -0,0 +1,59 @@ +/* + * Copyright 2021-2023 Aklivity Inc + * + * Licensed under the Aklivity Community License (the "License"); you may not use + * this file except in compliance with the License. You may obtain a copy of the + * License at + * + * https://www.aklivity.io/aklivity-community-license/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package io.aklivity.zilla.runtime.catalog.schema.registry.internal; + +import static java.util.concurrent.TimeUnit.SECONDS; +import static org.junit.rules.RuleChain.outerRule; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.DisableOnDebug; +import org.junit.rules.TestRule; +import org.junit.rules.Timeout; +import org.kaazing.k3po.junit.annotation.Specification; +import org.kaazing.k3po.junit.rules.K3poRule; + +import io.aklivity.zilla.runtime.engine.test.EngineRule; +import io.aklivity.zilla.runtime.engine.test.annotation.Configuration; + +public class EventIT +{ + private final K3poRule k3po = new K3poRule() + .addScriptRoot("net", "io/aklivity/zilla/specs/engine/streams/network") + .addScriptRoot("app", "io/aklivity/zilla/specs/engine/streams/application"); + + private final TestRule timeout = new DisableOnDebug(new Timeout(10, SECONDS)); + + private final EngineRule engine = new EngineRule() + .directory("target/zilla-itests") + .countersBufferCapacity(4096) + .configurationRoot("io/aklivity/zilla/specs/catalog/schema/registry/config") + .external("app0") + .clean(); + + @Rule + public final TestRule chain = outerRule(engine).around(k3po).around(timeout); + + @Test + @Configuration("event.yaml") + @Specification({ + "${net}/event/client", + "${app}/event/server" + }) + public void shouldLogEvents() throws Exception + { + k3po.finish(); + } +} diff --git a/incubator/exporter-stdout.spec/pom.xml b/incubator/exporter-stdout.spec/pom.xml index 8db58bd8c7..d099bd275d 100644 --- a/incubator/exporter-stdout.spec/pom.xml +++ b/incubator/exporter-stdout.spec/pom.xml @@ -41,18 +41,6 @@ engine.spec ${project.version} - - ${project.groupId} - binding-http.spec - ${project.version} - test - - - ${project.groupId} - binding-proxy.spec - ${project.version} - test - junit junit diff --git a/incubator/exporter-stdout.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/config/v1.1/server.authorization.credentials.yaml b/incubator/exporter-stdout.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/config/v1.1/server.authorization.credentials.yaml deleted file mode 100644 index a6daa035f9..0000000000 --- a/incubator/exporter-stdout.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/config/v1.1/server.authorization.credentials.yaml +++ /dev/null @@ -1,53 +0,0 @@ -# -# Copyright 2021-2023 Aklivity Inc -# -# Licensed under the Aklivity Community License (the "License"); you may not use -# this file except in compliance with the License. You may obtain a copy of the -# License at -# -# https://www.aklivity.io/aklivity-community-license/ -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OF ANY KIND, either express or implied. See the License for the -# specific language governing permissions and limitations under the License. -# - ---- -name: test -telemetry: - exporters: - stdout0: - type: stdout -guards: - jwt0: - type: jwt - options: - issuer: https://auth.example.com - audience: https://api.example.com - keys: - - kty: RSA - n: qqEu50hX+43Bx4W1UYWnAVKwFm+vDbP0kuIOSLVNa+HKQdHTf+3Sei5UCnkskn796izA29D0DdCy3ET9oaKRHIJyKbqFl0rv6f516QzOoXKC6N01sXBHBE/ovs0wwDvlaW+gFGPgkzdcfUlyrWLDnLV7LcuQymhTND2uH0oR3wJnNENN/OFgM1KGPPDOe19YsIKdLqARgxrhZVsh06OurEviZTXOBFI5r+yac7haDwOQhLHXNv+Y9MNvxs5QLWPFIM3bNUWfYrJnLrs4hGJS+y/KDM9Si+HL30QAFXy4YNO33J8DHjZ7ddG5n8/FqplOKvRtUgjcKWlxoGY4VdVaDQ== - e: AQAB - alg: RS256 - kid: example -bindings: - net0: - type: http - kind: server - options: - versions: - - http/1.1 - authorization: - jwt0: - credentials: - cookies: - access_token: "{credentials}" - headers: - authorization: Bearer {credentials} - query: - access_token: "{credentials}" - routes: - - exit: app0 - guarded: - jwt0: [] diff --git a/incubator/exporter-stdout.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/config/v1.1/server.yaml b/incubator/exporter-stdout.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/config/v1.1/server.yaml deleted file mode 100644 index 7202d45307..0000000000 --- a/incubator/exporter-stdout.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/config/v1.1/server.yaml +++ /dev/null @@ -1,33 +0,0 @@ -# -# Copyright 2021-2023 Aklivity Inc -# -# Licensed under the Aklivity Community License (the "License"); you may not use -# this file except in compliance with the License. You may obtain a copy of the -# License at -# -# https://www.aklivity.io/aklivity-community-license/ -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OF ANY KIND, either express or implied. See the License for the -# specific language governing permissions and limitations under the License. -# - ---- -name: test -telemetry: - exporters: - stdout0: - type: stdout -bindings: - net0: - type: http - kind: server - options: - versions: - - http/1.1 - routes: - - exit: app0 - when: - - headers: - :authority: localhost:8080 diff --git a/incubator/exporter-stdout.spec/src/main/scripts/io/aklivity/zilla/specs/binding/tcp/config/client.host.yaml b/incubator/exporter-stdout.spec/src/main/scripts/io/aklivity/zilla/specs/binding/tcp/config/client.host.yaml deleted file mode 100644 index 04191ddc52..0000000000 --- a/incubator/exporter-stdout.spec/src/main/scripts/io/aklivity/zilla/specs/binding/tcp/config/client.host.yaml +++ /dev/null @@ -1,28 +0,0 @@ -# -# Copyright 2021-2023 Aklivity Inc -# -# Licensed under the Aklivity Community License (the "License"); you may not use -# this file except in compliance with the License. You may obtain a copy of the -# License at -# -# https://www.aklivity.io/aklivity-community-license/ -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OF ANY KIND, either express or implied. See the License for the -# specific language governing permissions and limitations under the License. -# - ---- -name: test -telemetry: - exporters: - stdout0: - type: stdout -bindings: - app0: - type: tcp - kind: client - options: - host: localhost - port: 8080 diff --git a/incubator/exporter-stdout.spec/src/main/scripts/io/aklivity/zilla/specs/binding/tls/config/server.yaml b/incubator/exporter-stdout.spec/src/main/scripts/io/aklivity/zilla/specs/binding/tls/config/server.yaml deleted file mode 100644 index fd7e4b90a0..0000000000 --- a/incubator/exporter-stdout.spec/src/main/scripts/io/aklivity/zilla/specs/binding/tls/config/server.yaml +++ /dev/null @@ -1,38 +0,0 @@ -# -# Copyright 2021-2023 Aklivity Inc -# -# Licensed under the Aklivity Community License (the "License"); you may not use -# this file except in compliance with the License. You may obtain a copy of the -# License at -# -# https://www.aklivity.io/aklivity-community-license/ -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OF ANY KIND, either express or implied. See the License for the -# specific language governing permissions and limitations under the License. -# - ---- -name: test -telemetry: - exporters: - stdout0: - type: stdout -vaults: - server: - type: filesystem - options: - keys: - store: stores/server/keys - type: pkcs12 - password: generated -bindings: - net0: - type: tls - kind: server - vault: server - options: - keys: - - localhost - exit: app0 diff --git a/incubator/exporter-stdout.spec/src/main/scripts/io/aklivity/zilla/specs/binding/tls/config/stores/.gitignore b/incubator/exporter-stdout.spec/src/main/scripts/io/aklivity/zilla/specs/binding/tls/config/stores/.gitignore deleted file mode 100644 index 507484f3e9..0000000000 --- a/incubator/exporter-stdout.spec/src/main/scripts/io/aklivity/zilla/specs/binding/tls/config/stores/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -*.crt -*.csr diff --git a/incubator/exporter-stdout.spec/src/main/scripts/io/aklivity/zilla/specs/binding/tls/config/stores/client/keys b/incubator/exporter-stdout.spec/src/main/scripts/io/aklivity/zilla/specs/binding/tls/config/stores/client/keys deleted file mode 100644 index d2fa3da9b9..0000000000 Binary files a/incubator/exporter-stdout.spec/src/main/scripts/io/aklivity/zilla/specs/binding/tls/config/stores/client/keys and /dev/null differ diff --git a/incubator/exporter-stdout.spec/src/main/scripts/io/aklivity/zilla/specs/binding/tls/config/stores/client/signers b/incubator/exporter-stdout.spec/src/main/scripts/io/aklivity/zilla/specs/binding/tls/config/stores/client/signers deleted file mode 100644 index 58e72c4460..0000000000 Binary files a/incubator/exporter-stdout.spec/src/main/scripts/io/aklivity/zilla/specs/binding/tls/config/stores/client/signers and /dev/null differ diff --git a/incubator/exporter-stdout.spec/src/main/scripts/io/aklivity/zilla/specs/binding/tls/config/stores/client/trust b/incubator/exporter-stdout.spec/src/main/scripts/io/aklivity/zilla/specs/binding/tls/config/stores/client/trust deleted file mode 100644 index bb624ca8c8..0000000000 Binary files a/incubator/exporter-stdout.spec/src/main/scripts/io/aklivity/zilla/specs/binding/tls/config/stores/client/trust and /dev/null differ diff --git a/incubator/exporter-stdout.spec/src/main/scripts/io/aklivity/zilla/specs/binding/tls/config/stores/server/keys b/incubator/exporter-stdout.spec/src/main/scripts/io/aklivity/zilla/specs/binding/tls/config/stores/server/keys deleted file mode 100644 index e10b65832b..0000000000 Binary files a/incubator/exporter-stdout.spec/src/main/scripts/io/aklivity/zilla/specs/binding/tls/config/stores/server/keys and /dev/null differ diff --git a/incubator/exporter-stdout.spec/src/main/scripts/io/aklivity/zilla/specs/binding/tls/config/stores/server/signers b/incubator/exporter-stdout.spec/src/main/scripts/io/aklivity/zilla/specs/binding/tls/config/stores/server/signers deleted file mode 100644 index 0c8e698ab1..0000000000 Binary files a/incubator/exporter-stdout.spec/src/main/scripts/io/aklivity/zilla/specs/binding/tls/config/stores/server/signers and /dev/null differ diff --git a/incubator/exporter-stdout.spec/src/main/scripts/io/aklivity/zilla/specs/binding/tls/config/stores/server/trust b/incubator/exporter-stdout.spec/src/main/scripts/io/aklivity/zilla/specs/binding/tls/config/stores/server/trust deleted file mode 100644 index 377ed0c4c4..0000000000 Binary files a/incubator/exporter-stdout.spec/src/main/scripts/io/aklivity/zilla/specs/binding/tls/config/stores/server/trust and /dev/null differ diff --git a/incubator/exporter-stdout.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/config/v2/server.yaml b/incubator/exporter-stdout.spec/src/main/scripts/io/aklivity/zilla/specs/exporter/stdout/config/server.event.yaml similarity index 82% rename from incubator/exporter-stdout.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/config/v2/server.yaml rename to incubator/exporter-stdout.spec/src/main/scripts/io/aklivity/zilla/specs/exporter/stdout/config/server.event.yaml index effa3e4a6f..58c11c47ea 100644 --- a/incubator/exporter-stdout.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/config/v2/server.yaml +++ b/incubator/exporter-stdout.spec/src/main/scripts/io/aklivity/zilla/specs/exporter/stdout/config/server.event.yaml @@ -21,13 +21,10 @@ telemetry: type: stdout bindings: net0: - type: http + type: test kind: server options: - versions: - - h2 - routes: - - exit: app0 - when: - - headers: - :authority: localhost:8080 + events: + - timestamp: 42 + message: test event message + exit: app0 diff --git a/incubator/exporter-stdout/pom.xml b/incubator/exporter-stdout/pom.xml index 58bf155c90..8d551a92c5 100644 --- a/incubator/exporter-stdout/pom.xml +++ b/incubator/exporter-stdout/pom.xml @@ -26,7 +26,7 @@ 11 11 - 0.75 + 0.90 0 @@ -43,48 +43,6 @@ ${project.version} provided - - ${project.groupId} - binding-http.spec - ${project.version} - provided - - - ${project.groupId} - binding-kafka.spec - ${project.version} - provided - - - ${project.groupId} - binding-tcp.spec - ${project.version} - provided - - - ${project.groupId} - binding-tls.spec - ${project.version} - provided - - - ${project.groupId} - catalog-schema-registry.spec - ${project.version} - provided - - - ${project.groupId} - guard-jwt.spec - ${project.version} - provided - - - ${project.groupId} - vault-filesystem.spec - ${project.version} - provided - ${project.groupId} engine @@ -92,54 +50,6 @@ ${project.version} test - - ${project.groupId} - binding-http - ${project.version} - test - - - ${project.groupId} - binding-kafka - ${project.version} - test - - - ${project.groupId} - binding-tcp - ${project.version} - test - - - ${project.groupId} - binding-tls - ${project.version} - test - - - ${project.groupId} - catalog-schema-registry - ${project.version} - test - - - ${project.groupId} - guard-jwt - ${project.version} - test - - - ${project.groupId} - model-json - ${project.version} - test - - - ${project.groupId} - vault-filesystem - ${project.version} - test - junit junit diff --git a/incubator/exporter-stdout/src/main/java/io/aklivity/zilla/runtime/exporter/stdout/internal/StdoutExporterContext.java b/incubator/exporter-stdout/src/main/java/io/aklivity/zilla/runtime/exporter/stdout/internal/StdoutExporterContext.java index bb8d7d3adb..c7cdec617b 100644 --- a/incubator/exporter-stdout/src/main/java/io/aklivity/zilla/runtime/exporter/stdout/internal/StdoutExporterContext.java +++ b/incubator/exporter-stdout/src/main/java/io/aklivity/zilla/runtime/exporter/stdout/internal/StdoutExporterContext.java @@ -22,6 +22,7 @@ import io.aklivity.zilla.runtime.engine.config.AttributeConfig; import io.aklivity.zilla.runtime.engine.config.ExporterConfig; import io.aklivity.zilla.runtime.engine.config.KindConfig; +import io.aklivity.zilla.runtime.engine.event.EventFormatter; import io.aklivity.zilla.runtime.engine.exporter.ExporterContext; import io.aklivity.zilla.runtime.engine.exporter.ExporterHandler; import io.aklivity.zilla.runtime.engine.metrics.Collector; @@ -63,10 +64,9 @@ public String supplyQName( return context.supplyQName(namespacedId); } - public int supplyTypeId( - String name) + public EventFormatter supplyEventFormatter() { - return context.supplyTypeId(name); + return context.supplyEventFormatter(); } public MessageReader supplyEventReader() diff --git a/incubator/exporter-stdout/src/main/java/io/aklivity/zilla/runtime/exporter/stdout/internal/stream/EventHandler.java b/incubator/exporter-stdout/src/main/java/io/aklivity/zilla/runtime/exporter/stdout/internal/stream/EventHandler.java deleted file mode 100644 index f8f2a84e8b..0000000000 --- a/incubator/exporter-stdout/src/main/java/io/aklivity/zilla/runtime/exporter/stdout/internal/stream/EventHandler.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2021-2023 Aklivity Inc - * - * Licensed under the Aklivity Community License (the "License"); you may not use - * this file except in compliance with the License. You may obtain a copy of the - * License at - * - * https://www.aklivity.io/aklivity-community-license/ - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ -package io.aklivity.zilla.runtime.exporter.stdout.internal.stream; - -import java.io.PrintStream; -import java.time.Instant; -import java.time.OffsetDateTime; -import java.time.ZoneId; -import java.time.format.DateTimeFormatter; - -import org.agrona.DirectBuffer; - -import io.aklivity.zilla.runtime.exporter.stdout.internal.StdoutExporterContext; -import io.aklivity.zilla.runtime.exporter.stdout.internal.types.StringFW; - -public abstract class EventHandler -{ - protected static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("dd/MMM/yyyy:HH:mm:ss Z"); - - protected final StdoutExporterContext context; - protected final PrintStream out; - - public EventHandler( - StdoutExporterContext context, - PrintStream out) - { - this.context = context; - this.out = out; - } - - public abstract void handleEvent( - int msgTypeId, - DirectBuffer buffer, - int index, - int length); - - protected static String asString( - StringFW stringFW) - { - String s = stringFW.asString(); - return s == null ? "" : s; - } - - protected static String identity( - StringFW identity) - { - int length = identity.length(); - return length <= 0 ? "-" : identity.asString(); - } - - protected static String asDateTime( - long timestamp) - { - Instant instant = Instant.ofEpochMilli(timestamp); - OffsetDateTime offsetDateTime = OffsetDateTime.ofInstant(instant, ZoneId.systemDefault()); - return offsetDateTime.format(FORMATTER); - } -} diff --git a/incubator/exporter-stdout/src/main/java/io/aklivity/zilla/runtime/exporter/stdout/internal/stream/StdoutEventsStream.java b/incubator/exporter-stdout/src/main/java/io/aklivity/zilla/runtime/exporter/stdout/internal/stream/StdoutEventsStream.java index c6e330f377..1a866e87c2 100644 --- a/incubator/exporter-stdout/src/main/java/io/aklivity/zilla/runtime/exporter/stdout/internal/stream/StdoutEventsStream.java +++ b/incubator/exporter-stdout/src/main/java/io/aklivity/zilla/runtime/exporter/stdout/internal/stream/StdoutEventsStream.java @@ -15,34 +15,37 @@ package io.aklivity.zilla.runtime.exporter.stdout.internal.stream; import java.io.PrintStream; +import java.time.Instant; +import java.time.OffsetDateTime; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; import org.agrona.DirectBuffer; -import org.agrona.collections.Int2ObjectHashMap; -import io.aklivity.zilla.runtime.engine.binding.function.MessageConsumer; import io.aklivity.zilla.runtime.engine.binding.function.MessageReader; +import io.aklivity.zilla.runtime.engine.event.EventFormatter; import io.aklivity.zilla.runtime.exporter.stdout.internal.StdoutExporterContext; +import io.aklivity.zilla.runtime.exporter.stdout.internal.types.event.EventFW; public class StdoutEventsStream { + private static final String FORMAT = "%s [%s] %s%n"; // qname [timestamp] extension\n + private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("dd/MMM/yyyy:HH:mm:ss Z"); + + private final StdoutExporterContext context; private final MessageReader readEvent; - private final Int2ObjectHashMap eventHandlers; + private final EventFormatter formatter; + private final EventFW eventRO = new EventFW(); + private final PrintStream out; public StdoutEventsStream( StdoutExporterContext context, PrintStream out) { + this.context = context; this.readEvent = context.supplyEventReader(); - - final Int2ObjectHashMap eventHandlers = new Int2ObjectHashMap<>(); - eventHandlers.put(context.supplyTypeId("http"), new StdoutHttpHandler(context, out)::handleEvent); - eventHandlers.put(context.supplyTypeId("jwt"), new StdoutJwtHandler(context, out)::handleEvent); - eventHandlers.put(context.supplyTypeId("kafka"), new StdoutKafkaHandler(context, out)::handleEvent); - eventHandlers.put(context.supplyTypeId("schema-registry"), - new StdoutSchemaRegistryHandler(context, out)::handleEvent); - eventHandlers.put(context.supplyTypeId("tcp"), new StdoutTcpHandler(context, out)::handleEvent); - eventHandlers.put(context.supplyTypeId("tls"), new StdoutTlsHandler(context, out)::handleEvent); - this.eventHandlers = eventHandlers; + this.formatter = context.supplyEventFormatter(); + this.out = out; } public int process() @@ -56,10 +59,17 @@ private void handleEvent( int index, int length) { - final MessageConsumer handler = eventHandlers.get(msgTypeId); - if (handler != null) - { - handler.accept(msgTypeId, buffer, index, length); - } + final EventFW event = eventRO.wrap(buffer, index, index + length); + String qname = context.supplyQName(event.namespacedId()); + String extension = formatter.format(msgTypeId, buffer, index, length); + out.format(FORMAT, qname, asDateTime(event.timestamp()), extension); + } + + private static String asDateTime( + long timestamp) + { + Instant instant = Instant.ofEpochMilli(timestamp); + OffsetDateTime offsetDateTime = OffsetDateTime.ofInstant(instant, ZoneId.systemDefault()); + return offsetDateTime.format(FORMATTER); } } diff --git a/incubator/exporter-stdout/src/main/java/io/aklivity/zilla/runtime/exporter/stdout/internal/stream/StdoutHttpHandler.java b/incubator/exporter-stdout/src/main/java/io/aklivity/zilla/runtime/exporter/stdout/internal/stream/StdoutHttpHandler.java deleted file mode 100644 index 86dabe799b..0000000000 --- a/incubator/exporter-stdout/src/main/java/io/aklivity/zilla/runtime/exporter/stdout/internal/stream/StdoutHttpHandler.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2021-2023 Aklivity Inc - * - * Licensed under the Aklivity Community License (the "License"); you may not use - * this file except in compliance with the License. You may obtain a copy of the - * License at - * - * https://www.aklivity.io/aklivity-community-license/ - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ -package io.aklivity.zilla.runtime.exporter.stdout.internal.stream; - -import java.io.PrintStream; - -import org.agrona.DirectBuffer; - -import io.aklivity.zilla.runtime.exporter.stdout.internal.StdoutExporterContext; -import io.aklivity.zilla.runtime.exporter.stdout.internal.types.event.HttpEventFW; -import io.aklivity.zilla.runtime.exporter.stdout.internal.types.event.HttpRequestAcceptedFW; - -public class StdoutHttpHandler extends EventHandler -{ - private static final String REQUEST_ACCEPTED_FORMAT = "%s %s [%s] REQUEST_ACCEPTED %s %s %s %s%n"; - - private final HttpEventFW httpEventRO = new HttpEventFW(); - - public StdoutHttpHandler( - StdoutExporterContext context, - PrintStream out) - { - super(context, out); - } - - public void handleEvent( - int msgTypeId, - DirectBuffer buffer, - int index, - int length) - { - final HttpEventFW event = httpEventRO.wrap(buffer, index, index + length); - switch (event.kind()) - { - case REQUEST_ACCEPTED: - { - HttpRequestAcceptedFW e = event.requestAccepted(); - String qname = context.supplyQName(e.namespacedId()); - out.format(REQUEST_ACCEPTED_FORMAT, qname, identity(e.identity()), asDateTime(e.timestamp()), asString(e.scheme()), - asString(e.method()), asString(e.authority()), asString(e.path())); - break; - } - } - } -} diff --git a/incubator/exporter-stdout/src/main/java/io/aklivity/zilla/runtime/exporter/stdout/internal/stream/StdoutJwtHandler.java b/incubator/exporter-stdout/src/main/java/io/aklivity/zilla/runtime/exporter/stdout/internal/stream/StdoutJwtHandler.java deleted file mode 100644 index 7acf1ee0fe..0000000000 --- a/incubator/exporter-stdout/src/main/java/io/aklivity/zilla/runtime/exporter/stdout/internal/stream/StdoutJwtHandler.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2021-2023 Aklivity Inc - * - * Licensed under the Aklivity Community License (the "License"); you may not use - * this file except in compliance with the License. You may obtain a copy of the - * License at - * - * https://www.aklivity.io/aklivity-community-license/ - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ -package io.aklivity.zilla.runtime.exporter.stdout.internal.stream; - -import java.io.PrintStream; - -import org.agrona.DirectBuffer; - -import io.aklivity.zilla.runtime.exporter.stdout.internal.StdoutExporterContext; -import io.aklivity.zilla.runtime.exporter.stdout.internal.types.event.JwtAuthorizationFailedFW; -import io.aklivity.zilla.runtime.exporter.stdout.internal.types.event.JwtEventFW; - -public class StdoutJwtHandler extends EventHandler -{ - private static final String AUTHORIZATION_FAILED_FORMAT = "%s %s [%s] AUTHORIZATION_FAILED%n"; - - private final JwtEventFW jwtEventRO = new JwtEventFW(); - - public StdoutJwtHandler( - StdoutExporterContext context, - PrintStream out) - { - super(context, out); - } - - public void handleEvent( - int msgTypeId, - DirectBuffer buffer, - int index, - int length) - { - JwtEventFW event = jwtEventRO.wrap(buffer, index, index + length); - switch (event.kind()) - { - case AUTHORIZATION_FAILED: - JwtAuthorizationFailedFW e = event.authorizationFailed(); - String qname = context.supplyQName(e.namespacedId()); - out.printf(AUTHORIZATION_FAILED_FORMAT, qname, identity(e.identity()), asDateTime(e.timestamp())); - break; - } - } -} diff --git a/incubator/exporter-stdout/src/main/java/io/aklivity/zilla/runtime/exporter/stdout/internal/stream/StdoutKafkaHandler.java b/incubator/exporter-stdout/src/main/java/io/aklivity/zilla/runtime/exporter/stdout/internal/stream/StdoutKafkaHandler.java deleted file mode 100644 index bae2026051..0000000000 --- a/incubator/exporter-stdout/src/main/java/io/aklivity/zilla/runtime/exporter/stdout/internal/stream/StdoutKafkaHandler.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright 2021-2023 Aklivity Inc - * - * Licensed under the Aklivity Community License (the "License"); you may not use - * this file except in compliance with the License. You may obtain a copy of the - * License at - * - * https://www.aklivity.io/aklivity-community-license/ - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ -package io.aklivity.zilla.runtime.exporter.stdout.internal.stream; - -import java.io.PrintStream; - -import org.agrona.DirectBuffer; - -import io.aklivity.zilla.runtime.exporter.stdout.internal.StdoutExporterContext; -import io.aklivity.zilla.runtime.exporter.stdout.internal.types.event.EventFW; -import io.aklivity.zilla.runtime.exporter.stdout.internal.types.event.KafkaApiVersionRejectedFW; -import io.aklivity.zilla.runtime.exporter.stdout.internal.types.event.KafkaEventFW; - -public class StdoutKafkaHandler extends EventHandler -{ - private static final String AUTHORIZATION_FAILED_FORMAT = "%s - [%s] AUTHORIZATION_FAILED%n"; - private static final String API_VERSION_REJECTED_FORMAT = "%s - [%s] API_VERSION_REJECTED %d %d%n"; - - private final KafkaEventFW kafkaEventRO = new KafkaEventFW(); - - public StdoutKafkaHandler( - StdoutExporterContext context, - PrintStream out) - { - super(context, out); - } - - public void handleEvent( - int msgTypeId, - DirectBuffer buffer, - int index, - int length) - { - final KafkaEventFW event = kafkaEventRO.wrap(buffer, index, index + length); - switch (event.kind()) - { - case AUTHORIZATION_FAILED: - { - EventFW e = event.authorizationFailed(); - String qname = context.supplyQName(e.namespacedId()); - out.printf(AUTHORIZATION_FAILED_FORMAT, qname, asDateTime(e.timestamp())); - break; - } - case API_VERSION_REJECTED: - { - KafkaApiVersionRejectedFW e = event.apiVersionRejected(); - String qname = context.supplyQName(e.namespacedId()); - out.printf(API_VERSION_REJECTED_FORMAT, qname, asDateTime(e.timestamp()), e.apiKey(), e.apiVersion()); - break; - } - } - } -} diff --git a/incubator/exporter-stdout/src/main/java/io/aklivity/zilla/runtime/exporter/stdout/internal/stream/StdoutSchemaRegistryHandler.java b/incubator/exporter-stdout/src/main/java/io/aklivity/zilla/runtime/exporter/stdout/internal/stream/StdoutSchemaRegistryHandler.java deleted file mode 100644 index 376826b0fd..0000000000 --- a/incubator/exporter-stdout/src/main/java/io/aklivity/zilla/runtime/exporter/stdout/internal/stream/StdoutSchemaRegistryHandler.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2021-2023 Aklivity Inc - * - * Licensed under the Aklivity Community License (the "License"); you may not use - * this file except in compliance with the License. You may obtain a copy of the - * License at - * - * https://www.aklivity.io/aklivity-community-license/ - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ -package io.aklivity.zilla.runtime.exporter.stdout.internal.stream; - -import java.io.PrintStream; - -import org.agrona.DirectBuffer; - -import io.aklivity.zilla.runtime.exporter.stdout.internal.StdoutExporterContext; -import io.aklivity.zilla.runtime.exporter.stdout.internal.types.event.SchemaRegistryEventFW; -import io.aklivity.zilla.runtime.exporter.stdout.internal.types.event.SchemaRegistryRemoteAccessRejectedFW; - -public class StdoutSchemaRegistryHandler extends EventHandler -{ - private static final String REMOTE_ACCESS_REJECTED = "%s - [%s] REMOTE_ACCESS_REJECTED %s %s %d%n"; - - private final SchemaRegistryEventFW schemaRegistryEventRO = new SchemaRegistryEventFW(); - - public StdoutSchemaRegistryHandler( - StdoutExporterContext context, - PrintStream out) - { - super(context, out); - } - - public void handleEvent( - int msgTypeId, - DirectBuffer buffer, - int index, - int length) - { - SchemaRegistryEventFW event = schemaRegistryEventRO.wrap(buffer, index, index + length); - switch (event.kind()) - { - case REMOTE_ACCESS_REJECTED: - SchemaRegistryRemoteAccessRejectedFW e = event.remoteAccessRejected(); - String qname = context.supplyQName(e.namespacedId()); - out.printf(REMOTE_ACCESS_REJECTED, qname, asDateTime(e.timestamp()), asString(e.method()), asString(e.url()), - e.status()); - break; - } - } -} diff --git a/incubator/exporter-stdout/src/main/java/io/aklivity/zilla/runtime/exporter/stdout/internal/stream/StdoutTcpHandler.java b/incubator/exporter-stdout/src/main/java/io/aklivity/zilla/runtime/exporter/stdout/internal/stream/StdoutTcpHandler.java deleted file mode 100644 index 0584a4eddf..0000000000 --- a/incubator/exporter-stdout/src/main/java/io/aklivity/zilla/runtime/exporter/stdout/internal/stream/StdoutTcpHandler.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2021-2023 Aklivity Inc - * - * Licensed under the Aklivity Community License (the "License"); you may not use - * this file except in compliance with the License. You may obtain a copy of the - * License at - * - * https://www.aklivity.io/aklivity-community-license/ - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ -package io.aklivity.zilla.runtime.exporter.stdout.internal.stream; - -import java.io.PrintStream; - -import org.agrona.DirectBuffer; - -import io.aklivity.zilla.runtime.exporter.stdout.internal.StdoutExporterContext; -import io.aklivity.zilla.runtime.exporter.stdout.internal.types.event.TcpDnsFailedFW; -import io.aklivity.zilla.runtime.exporter.stdout.internal.types.event.TcpEventFW; - -public class StdoutTcpHandler extends EventHandler -{ - private static final String DNS_FAILED_FORMAT = "%s - [%s] DNS_FAILED %s%n"; - - private final TcpEventFW tcpEventRO = new TcpEventFW(); - - public StdoutTcpHandler( - StdoutExporterContext context, - PrintStream out) - { - super(context, out); - } - - public void handleEvent( - int msgTypeId, - DirectBuffer buffer, - int index, - int length) - { - final TcpEventFW event = tcpEventRO.wrap(buffer, index, index + length); - switch (event.kind()) - { - case DNS_FAILED: - TcpDnsFailedFW e = event.dnsFailed(); - String qname = context.supplyQName(e.namespacedId()); - out.printf(DNS_FAILED_FORMAT, qname, asDateTime(e.timestamp()), asString(e.address())); - break; - } - } -} diff --git a/incubator/exporter-stdout/src/main/java/io/aklivity/zilla/runtime/exporter/stdout/internal/stream/StdoutTlsHandler.java b/incubator/exporter-stdout/src/main/java/io/aklivity/zilla/runtime/exporter/stdout/internal/stream/StdoutTlsHandler.java deleted file mode 100644 index a3ecce6abf..0000000000 --- a/incubator/exporter-stdout/src/main/java/io/aklivity/zilla/runtime/exporter/stdout/internal/stream/StdoutTlsHandler.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright 2021-2023 Aklivity Inc - * - * Licensed under the Aklivity Community License (the "License"); you may not use - * this file except in compliance with the License. You may obtain a copy of the - * License at - * - * https://www.aklivity.io/aklivity-community-license/ - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ -package io.aklivity.zilla.runtime.exporter.stdout.internal.stream; - -import java.io.PrintStream; - -import org.agrona.DirectBuffer; - -import io.aklivity.zilla.runtime.exporter.stdout.internal.StdoutExporterContext; -import io.aklivity.zilla.runtime.exporter.stdout.internal.types.event.EventFW; -import io.aklivity.zilla.runtime.exporter.stdout.internal.types.event.TlsEventFW; - -public class StdoutTlsHandler extends EventHandler -{ - private static final String TLS_FAILED_FORMAT = "%s - [%s] TLS_FAILED%n"; - private static final String PROTOCOL_REJECTED_FORMAT = "%s - [%s] PROTOCOL_REJECTED%n"; - private static final String KEY_REJECTED_FORMAT = "%s - [%s] KEY_REJECTED%n"; - private static final String PEER_NOT_VERIFIED_FORMAT = "%s - [%s] PEER_NOT_VERIFIED%n"; - private static final String HANDSHAKE_FAILED_FORMAT = "%s - [%s] HANDSHAKE_FAILED%n"; - - private final TlsEventFW tlsEventRO = new TlsEventFW(); - - public StdoutTlsHandler( - StdoutExporterContext context, - PrintStream out) - { - super(context, out); - } - - public void handleEvent( - int msgTypeId, - DirectBuffer buffer, - int index, - int length) - { - TlsEventFW event = tlsEventRO.wrap(buffer, index, index + length); - switch (event.kind()) - { - case TLS_FAILED: - { - EventFW e = event.tlsFailed(); - String qname = context.supplyQName(e.namespacedId()); - out.printf(TLS_FAILED_FORMAT, qname, asDateTime(e.timestamp())); - break; - } - case TLS_PROTOCOL_REJECTED: - { - EventFW e = event.tlsProtocolRejected(); - String qname = context.supplyQName(e.namespacedId()); - out.printf(PROTOCOL_REJECTED_FORMAT, qname, asDateTime(e.timestamp())); - break; - } - case TLS_KEY_REJECTED: - { - EventFW e = event.tlsKeyRejected(); - String qname = context.supplyQName(e.namespacedId()); - out.printf(KEY_REJECTED_FORMAT, qname, asDateTime(e.timestamp())); - break; - } - case TLS_PEER_NOT_VERIFIED: - { - EventFW e = event.tlsPeerNotVerified(); - String qname = context.supplyQName(e.namespacedId()); - out.printf(PEER_NOT_VERIFIED_FORMAT, qname, asDateTime(e.timestamp())); - break; - } - case TLS_HANDSHAKE_FAILED: - { - EventFW e = event.tlsHandshakeFailed(); - String qname = context.supplyQName(e.namespacedId()); - out.printf(HANDSHAKE_FAILED_FORMAT, qname, asDateTime(e.timestamp())); - break; - } - } - } -} diff --git a/incubator/exporter-stdout/src/test/java/io/aklivity/zilla/runtime/exporter/stdout/internal/StdoutExporterConfigurationTest.java b/incubator/exporter-stdout/src/test/java/io/aklivity/zilla/runtime/exporter/stdout/internal/StdoutExporterConfigurationTest.java new file mode 100644 index 0000000000..7d2c479f55 --- /dev/null +++ b/incubator/exporter-stdout/src/test/java/io/aklivity/zilla/runtime/exporter/stdout/internal/StdoutExporterConfigurationTest.java @@ -0,0 +1,31 @@ +/* + * Copyright 2021-2023 Aklivity Inc + * + * Licensed under the Aklivity Community License (the "License"); you may not use + * this file except in compliance with the License. You may obtain a copy of the + * License at + * + * https://www.aklivity.io/aklivity-community-license/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package io.aklivity.zilla.runtime.exporter.stdout.internal; + +import static io.aklivity.zilla.runtime.exporter.stdout.internal.StdoutConfiguration.STDOUT_OUTPUT; +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +public class StdoutExporterConfigurationTest +{ + public static final String STDOUT_OUTPUT_NAME = "zilla.exporter.stdout.output"; + + @Test + public void shouldVerifyConstants() + { + assertEquals(STDOUT_OUTPUT.name(), STDOUT_OUTPUT_NAME); + } +} diff --git a/incubator/exporter-stdout/src/test/java/io/aklivity/zilla/runtime/exporter/stdout/internal/events/JwtEventsIT.java b/incubator/exporter-stdout/src/test/java/io/aklivity/zilla/runtime/exporter/stdout/internal/events/EventIT.java similarity index 68% rename from incubator/exporter-stdout/src/test/java/io/aklivity/zilla/runtime/exporter/stdout/internal/events/JwtEventsIT.java rename to incubator/exporter-stdout/src/test/java/io/aklivity/zilla/runtime/exporter/stdout/internal/events/EventIT.java index 41fa36d119..b31462dda6 100644 --- a/incubator/exporter-stdout/src/test/java/io/aklivity/zilla/runtime/exporter/stdout/internal/events/JwtEventsIT.java +++ b/incubator/exporter-stdout/src/test/java/io/aklivity/zilla/runtime/exporter/stdout/internal/events/EventIT.java @@ -14,7 +14,7 @@ */ package io.aklivity.zilla.runtime.exporter.stdout.internal.events; -import static io.aklivity.zilla.runtime.binding.http.internal.HttpConfiguration.HTTP_SERVER_HEADER; +import static io.aklivity.zilla.runtime.exporter.stdout.internal.StdoutExporterConfigurationTest.STDOUT_OUTPUT_NAME; import static java.util.concurrent.TimeUnit.SECONDS; import static org.junit.rules.RuleChain.outerRule; @@ -32,19 +32,18 @@ import io.aklivity.zilla.runtime.engine.test.annotation.Configuration; import io.aklivity.zilla.runtime.engine.test.annotation.Configure; -public class JwtEventsIT +public class EventIT { private final K3poRule k3po = new K3poRule() - .addScriptRoot("net", "io/aklivity/zilla/specs/binding/http/streams/network/rfc7230/authorization") - .addScriptRoot("app", "io/aklivity/zilla/specs/binding/http/streams/application/rfc7230/authorization"); + .addScriptRoot("net", "io/aklivity/zilla/specs/engine/streams/network") + .addScriptRoot("app", "io/aklivity/zilla/specs/engine/streams/application"); - private final TestRule timeout = new DisableOnDebug(new Timeout(10, SECONDS)); + private final TestRule timeout = new DisableOnDebug(new Timeout(5, SECONDS)); private final EngineRule engine = new EngineRule() .directory("target/zilla-itests") - .countersBufferCapacity(8192) - .configure(HTTP_SERVER_HEADER, "Zilla") - .configurationRoot("io/aklivity/zilla/specs/binding/http/config/v1.1") + .countersBufferCapacity(4096) + .configurationRoot("io/aklivity/zilla/specs/exporter/stdout/config") .external("app0") .clean(); @@ -54,15 +53,16 @@ public class JwtEventsIT public final TestRule chain = outerRule(output).around(engine).around(k3po).around(timeout); @Test - @Configuration("server.authorization.credentials.yaml") + @Configuration("server.event.yaml") @Specification({ - "${net}/reject.credentials.header/client", + "${net}/event/client", + "${app}/event/server" }) - @Configure(name = "zilla.exporter.stdout.output", + @Configure(name = STDOUT_OUTPUT_NAME, value = "io.aklivity.zilla.runtime.exporter.stdout.internal.events.StdoutOutputRule.OUT") - public void shouldRejectCredentialsHeader() throws Exception + public void shouldLogEvents() throws Exception { k3po.finish(); - output.expect(Pattern.compile("test.net0 user \\[[^\\]]+\\] AUTHORIZATION_FAILED\n")); + output.expect(Pattern.compile("test.net0 \\[[^\\]]+\\] test event message\n")); } } diff --git a/incubator/exporter-stdout/src/test/java/io/aklivity/zilla/runtime/exporter/stdout/internal/events/TlsEventsIT.java b/incubator/exporter-stdout/src/test/java/io/aklivity/zilla/runtime/exporter/stdout/internal/events/TlsEventsIT.java deleted file mode 100644 index cb201e110c..0000000000 --- a/incubator/exporter-stdout/src/test/java/io/aklivity/zilla/runtime/exporter/stdout/internal/events/TlsEventsIT.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright 2021-2023 Aklivity Inc - * - * Licensed under the Aklivity Community License (the "License"); you may not use - * this file except in compliance with the License. You may obtain a copy of the - * License at - * - * https://www.aklivity.io/aklivity-community-license/ - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ -package io.aklivity.zilla.runtime.exporter.stdout.internal.events; - -import static io.aklivity.zilla.runtime.engine.EngineConfiguration.ENGINE_DRAIN_ON_CLOSE; -import static java.util.concurrent.TimeUnit.SECONDS; -import static org.junit.rules.RuleChain.outerRule; - -import java.util.regex.Pattern; - -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.DisableOnDebug; -import org.junit.rules.TestRule; -import org.junit.rules.Timeout; -import org.kaazing.k3po.junit.annotation.Specification; -import org.kaazing.k3po.junit.rules.K3poRule; - -import io.aklivity.zilla.runtime.engine.test.EngineRule; -import io.aklivity.zilla.runtime.engine.test.annotation.Configuration; -import io.aklivity.zilla.runtime.engine.test.annotation.Configure; - -public class TlsEventsIT -{ - private final K3poRule k3po = new K3poRule() - .addScriptRoot("net", "io/aklivity/zilla/specs/binding/tls/streams/network") - .addScriptRoot("app", "io/aklivity/zilla/specs/binding/tls/streams/application"); - - private final TestRule timeout = new DisableOnDebug(new Timeout(10, SECONDS)); - - private final EngineRule engine = new EngineRule() - .directory("target/zilla-itests") - .countersBufferCapacity(8192) - .configurationRoot("io/aklivity/zilla/specs/binding/tls/config") - .external("app0") - .configure(ENGINE_DRAIN_ON_CLOSE, false) - .clean(); - - private final StdoutOutputRule output = new StdoutOutputRule(); - - @Rule - public final TestRule chain = outerRule(output).around(engine).around(k3po).around(timeout); - - @Test - @Configuration("server.yaml") - @Specification({ - "${net}/client.hello.malformed/client"}) - @Configure(name = "zilla.exporter.stdout.output", - value = "io.aklivity.zilla.runtime.exporter.stdout.internal.events.StdoutOutputRule.OUT") - public void shouldResetMalformedClientHello() throws Exception - { - k3po.finish(); - output.expect(Pattern.compile("test.net0 - \\[[^\\]]+\\] TLS_FAILED\n")); - } - - @Test - @Configuration("server.yaml") - @Specification({ - "${net}/server.handshake.timeout/client"}) - @Configure(name = "zilla.binding.tls.handshake.timeout", value = "1") - @Configure(name = "zilla.exporter.stdout.output", - value = "io.aklivity.zilla.runtime.exporter.stdout.internal.events.StdoutOutputRule.OUT") - public void shouldTimeoutHandshake() throws Exception - { - k3po.finish(); - output.expect(Pattern.compile("test.net0 - \\[[^\\]]+\\] HANDSHAKE_FAILED\n")); - } -} diff --git a/runtime/binding-http/src/main/java/io/aklivity/zilla/runtime/binding/http/internal/HttpEventContext.java b/runtime/binding-http/src/main/java/io/aklivity/zilla/runtime/binding/http/internal/HttpEventContext.java index f4c0ee0fc1..0b81d70e4b 100644 --- a/runtime/binding-http/src/main/java/io/aklivity/zilla/runtime/binding/http/internal/HttpEventContext.java +++ b/runtime/binding-http/src/main/java/io/aklivity/zilla/runtime/binding/http/internal/HttpEventContext.java @@ -15,6 +15,8 @@ */ package io.aklivity.zilla.runtime.binding.http.internal; +import static io.aklivity.zilla.runtime.binding.http.internal.types.event.HttpEventType.REQUEST_ACCEPTED; + import java.nio.ByteBuffer; import java.time.Clock; import java.util.Map; @@ -25,7 +27,8 @@ import io.aklivity.zilla.runtime.binding.http.internal.types.Array32FW; import io.aklivity.zilla.runtime.binding.http.internal.types.HttpHeaderFW; import io.aklivity.zilla.runtime.binding.http.internal.types.String8FW; -import io.aklivity.zilla.runtime.binding.http.internal.types.event.HttpEventFW; +import io.aklivity.zilla.runtime.binding.http.internal.types.event.EventFW; +import io.aklivity.zilla.runtime.binding.http.internal.types.event.HttpEventExFW; import io.aklivity.zilla.runtime.engine.EngineContext; import io.aklivity.zilla.runtime.engine.binding.function.MessageConsumer; import io.aklivity.zilla.runtime.engine.guard.GuardHandler; @@ -39,7 +42,9 @@ public class HttpEventContext private static final String8FW HEADER_PATH = new String8FW(":path"); private final AtomicBuffer eventBuffer = new UnsafeBuffer(ByteBuffer.allocate(EVENT_BUFFER_CAPACITY)); - private final HttpEventFW.Builder httpEventRW = new HttpEventFW.Builder(); + private final AtomicBuffer extensionBuffer = new UnsafeBuffer(ByteBuffer.allocate(EVENT_BUFFER_CAPACITY)); + private final EventFW.Builder eventRW = new EventFW.Builder(); + private final HttpEventExFW.Builder httpEventExRW = new HttpEventExFW.Builder(); private final int httpTypeId; private final MessageConsumer eventWriter; private final Clock clock; @@ -60,12 +65,10 @@ public void requestAccepted( Map headers) { String identity = guard == null ? null : guard.identity(authorization); - HttpEventFW event = httpEventRW - .wrap(eventBuffer, 0, eventBuffer.capacity()) + HttpEventExFW extension = httpEventExRW + .wrap(extensionBuffer, 0, extensionBuffer.capacity()) .requestAccepted(e -> e - .timestamp(clock.millis()) - .traceId(traceId) - .namespacedId(bindingId) + .typeId(REQUEST_ACCEPTED.value()) .identity(identity) .scheme(headers.get(":scheme")) .method(headers.get(":method")) @@ -73,6 +76,13 @@ public void requestAccepted( .path(headers.get(":path")) ) .build(); + EventFW event = eventRW + .wrap(eventBuffer, 0, eventBuffer.capacity()) + .timestamp(clock.millis()) + .traceId(traceId) + .namespacedId(bindingId) + .extension(extension.buffer(), extension.offset(), extension.limit()) + .build(); eventWriter.accept(httpTypeId, event.buffer(), event.offset(), event.limit()); } @@ -84,12 +94,10 @@ public void requestAccepted( Array32FW headers) { String identity = guard == null ? null : guard.identity(authorization); - HttpEventFW event = httpEventRW - .wrap(eventBuffer, 0, eventBuffer.capacity()) + HttpEventExFW extension = httpEventExRW + .wrap(extensionBuffer, 0, extensionBuffer.capacity()) .requestAccepted(e -> e - .timestamp(clock.millis()) - .traceId(traceId) - .namespacedId(bindingId) + .typeId(REQUEST_ACCEPTED.value()) .identity(identity) .scheme(headers.matchFirst(h -> HEADER_SCHEME.equals(h.name())).value().asString()) .method(headers.matchFirst(h -> HEADER_METHOD.equals(h.name())).value().asString()) @@ -97,6 +105,13 @@ public void requestAccepted( .path(headers.matchFirst(h -> HEADER_PATH.equals(h.name())).value().asString()) ) .build(); + EventFW event = eventRW + .wrap(eventBuffer, 0, eventBuffer.capacity()) + .timestamp(clock.millis()) + .traceId(traceId) + .namespacedId(bindingId) + .extension(extension.buffer(), extension.offset(), extension.limit()) + .build(); eventWriter.accept(httpTypeId, event.buffer(), event.offset(), event.limit()); } } diff --git a/runtime/binding-http/src/main/java/io/aklivity/zilla/runtime/binding/http/internal/HttpEventFormatter.java b/runtime/binding-http/src/main/java/io/aklivity/zilla/runtime/binding/http/internal/HttpEventFormatter.java new file mode 100644 index 0000000000..221b3097a8 --- /dev/null +++ b/runtime/binding-http/src/main/java/io/aklivity/zilla/runtime/binding/http/internal/HttpEventFormatter.java @@ -0,0 +1,74 @@ +/* + * Copyright 2021-2023 Aklivity Inc. + * + * Aklivity licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package io.aklivity.zilla.runtime.binding.http.internal; + +import org.agrona.DirectBuffer; + +import io.aklivity.zilla.runtime.binding.http.internal.types.StringFW; +import io.aklivity.zilla.runtime.binding.http.internal.types.event.EventFW; +import io.aklivity.zilla.runtime.binding.http.internal.types.event.HttpEventExFW; +import io.aklivity.zilla.runtime.binding.http.internal.types.event.HttpRequestAcceptedExFW; +import io.aklivity.zilla.runtime.engine.Configuration; +import io.aklivity.zilla.runtime.engine.event.EventFormatterSpi; + +public final class HttpEventFormatter implements EventFormatterSpi +{ + private static final String REQUEST_ACCEPTED_FORMAT = "REQUEST_ACCEPTED %s %s %s %s %s"; + + private final EventFW eventRO = new EventFW(); + private final HttpEventExFW httpEventExRO = new HttpEventExFW(); + + HttpEventFormatter( + Configuration config) + { + } + + public String format( + DirectBuffer buffer, + int index, + int length) + { + final EventFW event = eventRO.wrap(buffer, index, index + length); + final HttpEventExFW extension = httpEventExRO + .wrap(event.extension().buffer(), event.extension().offset(), event.extension().limit()); + String result = null; + switch (extension.kind()) + { + case REQUEST_ACCEPTED: + { + HttpRequestAcceptedExFW ex = extension.requestAccepted(); + result = String.format(REQUEST_ACCEPTED_FORMAT, identity(ex.identity()), asString(ex.scheme()), asString(ex.method()), + asString(ex.authority()), asString(ex.path())); + break; + } + } + return result; + } + + private static String asString( + StringFW stringFW) + { + String s = stringFW.asString(); + return s == null ? "" : s; + } + + private static String identity( + StringFW identity) + { + int length = identity.length(); + return length <= 0 ? "-" : identity.asString(); + } +} diff --git a/runtime/binding-http/src/main/java/io/aklivity/zilla/runtime/binding/http/internal/HttpEventFormatterFactory.java b/runtime/binding-http/src/main/java/io/aklivity/zilla/runtime/binding/http/internal/HttpEventFormatterFactory.java new file mode 100644 index 0000000000..d50404473d --- /dev/null +++ b/runtime/binding-http/src/main/java/io/aklivity/zilla/runtime/binding/http/internal/HttpEventFormatterFactory.java @@ -0,0 +1,35 @@ +/* + * Copyright 2021-2023 Aklivity Inc. + * + * Aklivity licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package io.aklivity.zilla.runtime.binding.http.internal; + +import io.aklivity.zilla.runtime.engine.Configuration; +import io.aklivity.zilla.runtime.engine.event.EventFormatterFactorySpi; + +public final class HttpEventFormatterFactory implements EventFormatterFactorySpi +{ + @Override + public HttpEventFormatter create( + Configuration config) + { + return new HttpEventFormatter(config); + } + + @Override + public String type() + { + return HttpBinding.NAME; + } +} diff --git a/runtime/binding-http/src/main/java/io/aklivity/zilla/runtime/binding/http/internal/stream/HttpServerFactory.java b/runtime/binding-http/src/main/java/io/aklivity/zilla/runtime/binding/http/internal/stream/HttpServerFactory.java index 7b6a5fc925..69bd7f202c 100644 --- a/runtime/binding-http/src/main/java/io/aklivity/zilla/runtime/binding/http/internal/stream/HttpServerFactory.java +++ b/runtime/binding-http/src/main/java/io/aklivity/zilla/runtime/binding/http/internal/stream/HttpServerFactory.java @@ -2271,7 +2271,7 @@ private boolean onDecodeHeaders( final HttpHeaderFW connection = beginEx.headers().matchFirst(h -> HEADER_CONNECTION.equals(h.name())); exchange.responseClosing = connection != null && connectionClose.reset(connection.value().asString()).matches(); - event.requestAccepted(traceId, routedId, guard, authorization, beginEx.headers()); + event.requestAccepted(traceId, originId, guard, authorization, beginEx.headers()); this.exchange = exchange; } return headersValid; diff --git a/runtime/binding-http/src/main/moditect/module-info.java b/runtime/binding-http/src/main/moditect/module-info.java index 6f1b960854..b837b223eb 100644 --- a/runtime/binding-http/src/main/moditect/module-info.java +++ b/runtime/binding-http/src/main/moditect/module-info.java @@ -27,4 +27,7 @@ provides io.aklivity.zilla.runtime.engine.config.ConditionConfigAdapterSpi with io.aklivity.zilla.runtime.binding.http.internal.config.HttpConditionConfigAdapter; + + provides io.aklivity.zilla.runtime.engine.event.EventFormatterFactorySpi + with io.aklivity.zilla.runtime.binding.http.internal.HttpEventFormatterFactory; } diff --git a/runtime/binding-http/src/main/resources/META-INF/services/io.aklivity.zilla.runtime.engine.event.EventFormatterFactorySpi b/runtime/binding-http/src/main/resources/META-INF/services/io.aklivity.zilla.runtime.engine.event.EventFormatterFactorySpi new file mode 100644 index 0000000000..1365f0fabe --- /dev/null +++ b/runtime/binding-http/src/main/resources/META-INF/services/io.aklivity.zilla.runtime.engine.event.EventFormatterFactorySpi @@ -0,0 +1 @@ +io.aklivity.zilla.runtime.binding.http.internal.HttpEventFormatterFactory diff --git a/incubator/exporter-stdout/src/test/java/io/aklivity/zilla/runtime/exporter/stdout/internal/events/Http11EventsIT.java b/runtime/binding-http/src/test/java/io/aklivity/zilla/runtime/binding/http/internal/streams/rfc7230/server/EventIT.java similarity index 60% rename from incubator/exporter-stdout/src/test/java/io/aklivity/zilla/runtime/exporter/stdout/internal/events/Http11EventsIT.java rename to runtime/binding-http/src/test/java/io/aklivity/zilla/runtime/binding/http/internal/streams/rfc7230/server/EventIT.java index c942d6e141..06e97df87b 100644 --- a/incubator/exporter-stdout/src/test/java/io/aklivity/zilla/runtime/exporter/stdout/internal/events/Http11EventsIT.java +++ b/runtime/binding-http/src/test/java/io/aklivity/zilla/runtime/binding/http/internal/streams/rfc7230/server/EventIT.java @@ -1,25 +1,25 @@ /* - * Copyright 2021-2023 Aklivity Inc + * Copyright 2021-2023 Aklivity Inc. * - * Licensed under the Aklivity Community License (the "License"); you may not use - * this file except in compliance with the License. You may obtain a copy of the - * License at + * Aklivity licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: * - * https://www.aklivity.io/aklivity-community-license/ + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. */ -package io.aklivity.zilla.runtime.exporter.stdout.internal.events; +package io.aklivity.zilla.runtime.binding.http.internal.streams.rfc7230.server; import static io.aklivity.zilla.runtime.engine.EngineConfiguration.ENGINE_BUFFER_SLOT_CAPACITY; import static java.util.concurrent.TimeUnit.SECONDS; import static org.junit.rules.RuleChain.outerRule; -import java.util.regex.Pattern; - +import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import org.junit.rules.DisableOnDebug; @@ -30,9 +30,8 @@ import io.aklivity.zilla.runtime.engine.test.EngineRule; import io.aklivity.zilla.runtime.engine.test.annotation.Configuration; -import io.aklivity.zilla.runtime.engine.test.annotation.Configure; -public class Http11EventsIT +public class EventIT { private final K3poRule k3po = new K3poRule() .addScriptRoot("net", "io/aklivity/zilla/specs/binding/http/streams/network/rfc7230/message.format") @@ -48,21 +47,17 @@ public class Http11EventsIT .external("app0") .clean(); - private final StdoutOutputRule output = new StdoutOutputRule(); - @Rule - public final TestRule chain = outerRule(output).around(engine).around(k3po).around(timeout); + public final TestRule chain = outerRule(engine).around(k3po).around(timeout); @Test - @Configuration("server.yaml") + @Ignore + @Configuration("server.event.yaml") @Specification({ "${net}/request.with.headers/client", "${app}/request.with.headers/server" }) - @Configure(name = "zilla.exporter.stdout.output", - value = "io.aklivity.zilla.runtime.exporter.stdout.internal.events.StdoutOutputRule.OUT") public void requestWithHeaders() throws Exception { k3po.finish(); - output.expect(Pattern.compile("test.app0 - \\[[^\\]]+\\] REQUEST_ACCEPTED http GET localhost:8080 /\n")); } } diff --git a/incubator/exporter-stdout/src/test/java/io/aklivity/zilla/runtime/exporter/stdout/internal/events/Http2EventsIT.java b/runtime/binding-http/src/test/java/io/aklivity/zilla/runtime/binding/http/internal/streams/rfc7540/server/EventIT.java similarity index 60% rename from incubator/exporter-stdout/src/test/java/io/aklivity/zilla/runtime/exporter/stdout/internal/events/Http2EventsIT.java rename to runtime/binding-http/src/test/java/io/aklivity/zilla/runtime/binding/http/internal/streams/rfc7540/server/EventIT.java index e858786c85..8bf5686dbf 100644 --- a/incubator/exporter-stdout/src/test/java/io/aklivity/zilla/runtime/exporter/stdout/internal/events/Http2EventsIT.java +++ b/runtime/binding-http/src/test/java/io/aklivity/zilla/runtime/binding/http/internal/streams/rfc7540/server/EventIT.java @@ -1,25 +1,25 @@ /* - * Copyright 2021-2023 Aklivity Inc + * Copyright 2021-2023 Aklivity Inc. * - * Licensed under the Aklivity Community License (the "License"); you may not use - * this file except in compliance with the License. You may obtain a copy of the - * License at + * Aklivity licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: * - * https://www.aklivity.io/aklivity-community-license/ + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. */ -package io.aklivity.zilla.runtime.exporter.stdout.internal.events; +package io.aklivity.zilla.runtime.binding.http.internal.streams.rfc7540.server; import static io.aklivity.zilla.runtime.binding.http.internal.HttpConfiguration.HTTP_CONCURRENT_STREAMS; import static java.util.concurrent.TimeUnit.SECONDS; import static org.junit.rules.RuleChain.outerRule; -import java.util.regex.Pattern; - +import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import org.junit.rules.DisableOnDebug; @@ -30,9 +30,8 @@ import io.aklivity.zilla.runtime.engine.test.EngineRule; import io.aklivity.zilla.runtime.engine.test.annotation.Configuration; -import io.aklivity.zilla.runtime.engine.test.annotation.Configure; -public class Http2EventsIT +public class EventIT { private final K3poRule k3po = new K3poRule() .addScriptRoot("net", "io/aklivity/zilla/specs/binding/http/streams/network/rfc7540/message.format") @@ -48,21 +47,17 @@ public class Http2EventsIT .external("app0") .clean(); - private final StdoutOutputRule output = new StdoutOutputRule(); - @Rule - public final TestRule chain = outerRule(output).around(engine).around(k3po).around(timeout); + public final TestRule chain = outerRule(engine).around(k3po).around(timeout); @Test - @Configuration("server.yaml") + @Ignore + @Configuration("server.event.yaml") @Specification({ "${net}/connection.headers/client", "${app}/connection.headers/server" }) - @Configure(name = "zilla.exporter.stdout.output", - value = "io.aklivity.zilla.runtime.exporter.stdout.internal.events.StdoutOutputRule.OUT") public void connectionHeaders() throws Exception { k3po.finish(); - output.expect(Pattern.compile("test.net0 - \\[[^\\]]+\\] REQUEST_ACCEPTED http GET localhost:8080 /\n")); } } diff --git a/runtime/binding-kafka/src/main/java/io/aklivity/zilla/runtime/binding/kafka/internal/KafkaEventContext.java b/runtime/binding-kafka/src/main/java/io/aklivity/zilla/runtime/binding/kafka/internal/KafkaEventContext.java index 86e8bc3168..587280caae 100644 --- a/runtime/binding-kafka/src/main/java/io/aklivity/zilla/runtime/binding/kafka/internal/KafkaEventContext.java +++ b/runtime/binding-kafka/src/main/java/io/aklivity/zilla/runtime/binding/kafka/internal/KafkaEventContext.java @@ -15,23 +15,28 @@ */ package io.aklivity.zilla.runtime.binding.kafka.internal; +import static io.aklivity.zilla.runtime.binding.kafka.internal.types.event.KafkaEventType.API_VERSION_REJECTED; +import static io.aklivity.zilla.runtime.binding.kafka.internal.types.event.KafkaEventType.AUTHORIZATION_FAILED; + import java.nio.ByteBuffer; import java.time.Clock; -import org.agrona.MutableDirectBuffer; +import org.agrona.concurrent.AtomicBuffer; import org.agrona.concurrent.UnsafeBuffer; -import io.aklivity.zilla.runtime.binding.kafka.internal.types.event.KafkaEventFW; +import io.aklivity.zilla.runtime.binding.kafka.internal.types.event.EventFW; +import io.aklivity.zilla.runtime.binding.kafka.internal.types.event.KafkaEventExFW; import io.aklivity.zilla.runtime.engine.EngineContext; import io.aklivity.zilla.runtime.engine.binding.function.MessageConsumer; public class KafkaEventContext { private static final int EVENT_BUFFER_CAPACITY = 1024; - private static final int ERROR_NONE = 0; - private final KafkaEventFW.Builder kafkaEventRW = new KafkaEventFW.Builder(); - private final MutableDirectBuffer eventBuffer = new UnsafeBuffer(ByteBuffer.allocate(EVENT_BUFFER_CAPACITY)); + private final AtomicBuffer eventBuffer = new UnsafeBuffer(ByteBuffer.allocate(EVENT_BUFFER_CAPACITY)); + private final AtomicBuffer extensionBuffer = new UnsafeBuffer(ByteBuffer.allocate(EVENT_BUFFER_CAPACITY)); + private final EventFW.Builder eventRW = new EventFW.Builder(); + private final KafkaEventExFW.Builder kafkaEventExRW = new KafkaEventExFW.Builder(); private final int kafkaTypeId; private final MessageConsumer eventWriter; private final Clock clock; @@ -46,16 +51,23 @@ public KafkaEventContext( public void authorizationFailed( long traceId, - long bindingId) + long bindingId, + String identity) { - KafkaEventFW event = kafkaEventRW - .wrap(eventBuffer, 0, eventBuffer.capacity()) + KafkaEventExFW extension = kafkaEventExRW + .wrap(extensionBuffer, 0, extensionBuffer.capacity()) .authorizationFailed(e -> e - .timestamp(clock.millis()) - .traceId(traceId) - .namespacedId(bindingId) + .typeId(AUTHORIZATION_FAILED.value()) + .identity(identity) ) .build(); + EventFW event = eventRW + .wrap(eventBuffer, 0, eventBuffer.capacity()) + .timestamp(clock.millis()) + .traceId(traceId) + .namespacedId(bindingId) + .extension(extension.buffer(), extension.offset(), extension.limit()) + .build(); eventWriter.accept(kafkaTypeId, event.buffer(), event.offset(), event.limit()); } @@ -65,16 +77,21 @@ public void apiVersionRejected( int apiKey, int apiVersion) { - KafkaEventFW event = kafkaEventRW - .wrap(eventBuffer, 0, eventBuffer.capacity()) + KafkaEventExFW extension = kafkaEventExRW + .wrap(extensionBuffer, 0, extensionBuffer.capacity()) .apiVersionRejected(e -> e - .timestamp(clock.millis()) - .traceId(traceId) - .namespacedId(bindingId) + .typeId(API_VERSION_REJECTED.value()) .apiKey(apiKey) .apiVersion(apiVersion) ) .build(); + EventFW event = eventRW + .wrap(eventBuffer, 0, eventBuffer.capacity()) + .timestamp(clock.millis()) + .traceId(traceId) + .namespacedId(bindingId) + .extension(extension.buffer(), extension.offset(), extension.limit()) + .build(); eventWriter.accept(kafkaTypeId, event.buffer(), event.offset(), event.limit()); } } diff --git a/runtime/binding-kafka/src/main/java/io/aklivity/zilla/runtime/binding/kafka/internal/KafkaEventFormatter.java b/runtime/binding-kafka/src/main/java/io/aklivity/zilla/runtime/binding/kafka/internal/KafkaEventFormatter.java new file mode 100644 index 0000000000..515aa6f08e --- /dev/null +++ b/runtime/binding-kafka/src/main/java/io/aklivity/zilla/runtime/binding/kafka/internal/KafkaEventFormatter.java @@ -0,0 +1,73 @@ +/* + * Copyright 2021-2023 Aklivity Inc. + * + * Aklivity licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package io.aklivity.zilla.runtime.binding.kafka.internal; + +import org.agrona.DirectBuffer; + +import io.aklivity.zilla.runtime.binding.kafka.internal.types.StringFW; +import io.aklivity.zilla.runtime.binding.kafka.internal.types.event.EventFW; +import io.aklivity.zilla.runtime.binding.kafka.internal.types.event.KafkaApiVersionRejectedExFW; +import io.aklivity.zilla.runtime.binding.kafka.internal.types.event.KafkaAuthorizationFailedExFW; +import io.aklivity.zilla.runtime.binding.kafka.internal.types.event.KafkaEventExFW; +import io.aklivity.zilla.runtime.engine.Configuration; +import io.aklivity.zilla.runtime.engine.event.EventFormatterSpi; + +public final class KafkaEventFormatter implements EventFormatterSpi +{ + private static final String AUTHORIZATION_FAILED_FORMAT = "AUTHORIZATION_FAILED %s"; + private static final String API_VERSION_REJECTED_FORMAT = "API_VERSION_REJECTED %d %d"; + + private final EventFW eventRO = new EventFW(); + private final KafkaEventExFW kafkaEventExRO = new KafkaEventExFW(); + + KafkaEventFormatter( + Configuration config) + { + } + + public String format( + DirectBuffer buffer, + int index, + int length) + { + final EventFW event = eventRO.wrap(buffer, index, index + length); + final KafkaEventExFW extension = kafkaEventExRO + .wrap(event.extension().buffer(), event.extension().offset(), event.extension().limit()); + String result = null; + switch (extension.kind()) + { + case AUTHORIZATION_FAILED: + { + KafkaAuthorizationFailedExFW ex = extension.authorizationFailed(); + result = String.format(AUTHORIZATION_FAILED_FORMAT, identity(ex.identity())); + break; + } + case API_VERSION_REJECTED: + { + final KafkaApiVersionRejectedExFW ex = extension.apiVersionRejected(); + result = String.format(API_VERSION_REJECTED_FORMAT, ex.apiKey(), ex.apiVersion()); + } + } + return result; + } + + private static String identity( + StringFW identity) + { + int length = identity.length(); + return length <= 0 ? "-" : identity.asString(); + } +} diff --git a/runtime/binding-kafka/src/main/java/io/aklivity/zilla/runtime/binding/kafka/internal/KafkaEventFormatterFactory.java b/runtime/binding-kafka/src/main/java/io/aklivity/zilla/runtime/binding/kafka/internal/KafkaEventFormatterFactory.java new file mode 100644 index 0000000000..f522ba7851 --- /dev/null +++ b/runtime/binding-kafka/src/main/java/io/aklivity/zilla/runtime/binding/kafka/internal/KafkaEventFormatterFactory.java @@ -0,0 +1,35 @@ +/* + * Copyright 2021-2023 Aklivity Inc. + * + * Aklivity licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package io.aklivity.zilla.runtime.binding.kafka.internal; + +import io.aklivity.zilla.runtime.engine.Configuration; +import io.aklivity.zilla.runtime.engine.event.EventFormatterFactorySpi; + +public final class KafkaEventFormatterFactory implements EventFormatterFactorySpi +{ + @Override + public KafkaEventFormatter create( + Configuration config) + { + return new KafkaEventFormatter(config); + } + + @Override + public String type() + { + return KafkaBinding.NAME; + } +} diff --git a/runtime/binding-kafka/src/main/java/io/aklivity/zilla/runtime/binding/kafka/internal/stream/KafkaClientSaslHandshaker.java b/runtime/binding-kafka/src/main/java/io/aklivity/zilla/runtime/binding/kafka/internal/stream/KafkaClientSaslHandshaker.java index ca61063380..2e3ed716a4 100644 --- a/runtime/binding-kafka/src/main/java/io/aklivity/zilla/runtime/binding/kafka/internal/stream/KafkaClientSaslHandshaker.java +++ b/runtime/binding-kafka/src/main/java/io/aklivity/zilla/runtime/binding/kafka/internal/stream/KafkaClientSaslHandshaker.java @@ -708,7 +708,7 @@ private int decodeSaslPlainAuthenticate( final int errorCode = authenticateResponse.errorCode(); if (errorCode != ERROR_NONE) { - event.authorizationFailed(traceId, client.originId); + event.authorizationFailed(traceId, client.originId, client.sasl.username); } progress = authenticateResponse.limit(); @@ -746,7 +746,7 @@ private int decodeSaslScramAuthenticateFirst( final int errorCode = authenticateResponse.errorCode(); if (errorCode != ERROR_NONE) { - event.authorizationFailed(traceId, client.originId); + event.authorizationFailed(traceId, client.originId, client.sasl.username); } progress = authenticateResponse.limit(); diff --git a/runtime/binding-kafka/src/main/moditect/module-info.java b/runtime/binding-kafka/src/main/moditect/module-info.java index b15ffc4089..1191e87119 100644 --- a/runtime/binding-kafka/src/main/moditect/module-info.java +++ b/runtime/binding-kafka/src/main/moditect/module-info.java @@ -34,4 +34,7 @@ provides io.aklivity.zilla.runtime.binding.kafka.identity.KafkaClientIdSupplierFactorySpi with io.aklivity.zilla.runtime.binding.kafka.internal.identity.KafkaConfluentClientIdSupplierFactory; + + provides io.aklivity.zilla.runtime.engine.event.EventFormatterFactorySpi + with io.aklivity.zilla.runtime.binding.kafka.internal.KafkaEventFormatterFactory; } diff --git a/runtime/binding-kafka/src/main/resources/META-INF/services/io.aklivity.zilla.runtime.engine.event.EventFormatterFactorySpi b/runtime/binding-kafka/src/main/resources/META-INF/services/io.aklivity.zilla.runtime.engine.event.EventFormatterFactorySpi new file mode 100644 index 0000000000..6659873202 --- /dev/null +++ b/runtime/binding-kafka/src/main/resources/META-INF/services/io.aklivity.zilla.runtime.engine.event.EventFormatterFactorySpi @@ -0,0 +1 @@ +io.aklivity.zilla.runtime.binding.kafka.internal.KafkaEventFormatterFactory diff --git a/incubator/exporter-stdout/src/test/java/io/aklivity/zilla/runtime/exporter/stdout/internal/events/KafkaEventsIT.java b/runtime/binding-kafka/src/test/java/io/aklivity/zilla/runtime/binding/kafka/internal/stream/EventIT.java similarity index 58% rename from incubator/exporter-stdout/src/test/java/io/aklivity/zilla/runtime/exporter/stdout/internal/events/KafkaEventsIT.java rename to runtime/binding-kafka/src/test/java/io/aklivity/zilla/runtime/binding/kafka/internal/stream/EventIT.java index e1e8c9fda7..e62066ce95 100644 --- a/incubator/exporter-stdout/src/test/java/io/aklivity/zilla/runtime/exporter/stdout/internal/events/KafkaEventsIT.java +++ b/runtime/binding-kafka/src/test/java/io/aklivity/zilla/runtime/binding/kafka/internal/stream/EventIT.java @@ -1,24 +1,23 @@ /* - * Copyright 2021-2023 Aklivity Inc + * Copyright 2021-2023 Aklivity Inc. * - * Licensed under the Aklivity Community License (the "License"); you may not use - * this file except in compliance with the License. You may obtain a copy of the - * License at + * Aklivity licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: * - * https://www.aklivity.io/aklivity-community-license/ + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. */ -package io.aklivity.zilla.runtime.exporter.stdout.internal.events; +package io.aklivity.zilla.runtime.binding.kafka.internal.stream; import static java.util.concurrent.TimeUnit.SECONDS; import static org.junit.rules.RuleChain.outerRule; -import java.util.regex.Pattern; - import org.junit.Rule; import org.junit.Test; import org.junit.rules.DisableOnDebug; @@ -29,9 +28,8 @@ import io.aklivity.zilla.runtime.engine.test.EngineRule; import io.aklivity.zilla.runtime.engine.test.annotation.Configuration; -import io.aklivity.zilla.runtime.engine.test.annotation.Configure; -public class KafkaEventsIT +public class EventIT { private final K3poRule k3po = new K3poRule() .addScriptRoot("net", "io/aklivity/zilla/specs/binding/kafka/streams/network/group.f1.j5.s3.l3.h3") @@ -43,27 +41,22 @@ public class KafkaEventsIT .directory("target/zilla-itests") .countersBufferCapacity(8192) .configure("zilla.binding.kafka.client.instance.id", - "io.aklivity.zilla.runtime.exporter.stdout.internal.events.KafkaEventsIT::supplyInstanceId") + "io.aklivity.zilla.runtime.binding.kafka.internal.stream.EventIT::supplyInstanceId") .configurationRoot("io/aklivity/zilla/specs/binding/kafka/config") .external("net0") .clean(); - private final StdoutOutputRule output = new StdoutOutputRule(); - @Rule - public final TestRule chain = outerRule(output).around(engine).around(k3po).around(timeout); + public final TestRule chain = outerRule(engine).around(k3po).around(timeout); @Test - @Configuration("client.yaml") + @Configuration("client.event.yaml") @Specification({ "${app}/invalid.describe.config/client", "${net}/invalid.describe.config/server"}) - @Configure(name = "zilla.exporter.stdout.output", - value = "io.aklivity.zilla.runtime.exporter.stdout.internal.events.StdoutOutputRule.OUT") public void shouldHandleInvalidDescribeConfig() throws Exception { k3po.finish(); - output.expect(Pattern.compile("test.app0 - \\[[^\\]]+\\] API_VERSION_REJECTED 32 0\n")); } public static String supplyInstanceId() diff --git a/runtime/binding-tcp/src/main/java/io/aklivity/zilla/runtime/binding/tcp/internal/TcpEventContext.java b/runtime/binding-tcp/src/main/java/io/aklivity/zilla/runtime/binding/tcp/internal/TcpEventContext.java index 7159725444..981c7bf6e3 100644 --- a/runtime/binding-tcp/src/main/java/io/aklivity/zilla/runtime/binding/tcp/internal/TcpEventContext.java +++ b/runtime/binding-tcp/src/main/java/io/aklivity/zilla/runtime/binding/tcp/internal/TcpEventContext.java @@ -15,13 +15,16 @@ */ package io.aklivity.zilla.runtime.binding.tcp.internal; +import static io.aklivity.zilla.runtime.binding.tcp.internal.types.event.TcpEventType.DNS_FAILED; + import java.nio.ByteBuffer; import java.time.Clock; -import org.agrona.MutableDirectBuffer; +import org.agrona.concurrent.AtomicBuffer; import org.agrona.concurrent.UnsafeBuffer; -import io.aklivity.zilla.runtime.binding.tcp.internal.types.event.TcpEventFW; +import io.aklivity.zilla.runtime.binding.tcp.internal.types.event.EventFW; +import io.aklivity.zilla.runtime.binding.tcp.internal.types.event.TcpEventExFW; import io.aklivity.zilla.runtime.engine.EngineContext; import io.aklivity.zilla.runtime.engine.binding.function.MessageConsumer; @@ -29,8 +32,11 @@ public class TcpEventContext { private static final int EVENT_BUFFER_CAPACITY = 1024; - private final TcpEventFW.Builder tcpEventRW = new TcpEventFW.Builder(); - private final MutableDirectBuffer eventBuffer = new UnsafeBuffer(ByteBuffer.allocate(EVENT_BUFFER_CAPACITY)); + private final AtomicBuffer eventBuffer = new UnsafeBuffer(ByteBuffer.allocate(EVENT_BUFFER_CAPACITY)); + private final AtomicBuffer extensionBuffer = new UnsafeBuffer(ByteBuffer.allocate(EVENT_BUFFER_CAPACITY)); + private final EventFW.Builder eventRW = new EventFW.Builder(); + private final TcpEventExFW.Builder tcpEventExRW = new TcpEventExFW.Builder(); + private final int tcpTypeId; private final MessageConsumer eventWriter; private final Clock clock; @@ -48,15 +54,20 @@ public void dnsResolutionFailed( long bindingId, String address) { - TcpEventFW event = tcpEventRW - .wrap(eventBuffer, 0, eventBuffer.capacity()) + TcpEventExFW extension = tcpEventExRW + .wrap(extensionBuffer, 0, extensionBuffer.capacity()) .dnsFailed(e -> e - .timestamp(clock.millis()) - .traceId(traceId) - .namespacedId(bindingId) + .typeId(DNS_FAILED.value()) .address(address) ) .build(); + EventFW event = eventRW + .wrap(eventBuffer, 0, eventBuffer.capacity()) + .timestamp(clock.millis()) + .traceId(traceId) + .namespacedId(bindingId) + .extension(extension.buffer(), extension.offset(), extension.limit()) + .build(); eventWriter.accept(tcpTypeId, event.buffer(), event.offset(), event.limit()); } } diff --git a/runtime/binding-tcp/src/main/java/io/aklivity/zilla/runtime/binding/tcp/internal/TcpEventFormatter.java b/runtime/binding-tcp/src/main/java/io/aklivity/zilla/runtime/binding/tcp/internal/TcpEventFormatter.java new file mode 100644 index 0000000000..5fd1716db2 --- /dev/null +++ b/runtime/binding-tcp/src/main/java/io/aklivity/zilla/runtime/binding/tcp/internal/TcpEventFormatter.java @@ -0,0 +1,66 @@ +/* + * Copyright 2021-2023 Aklivity Inc. + * + * Aklivity licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package io.aklivity.zilla.runtime.binding.tcp.internal; + +import org.agrona.DirectBuffer; + +import io.aklivity.zilla.runtime.binding.tcp.internal.types.StringFW; +import io.aklivity.zilla.runtime.binding.tcp.internal.types.event.EventFW; +import io.aklivity.zilla.runtime.binding.tcp.internal.types.event.TcpDnsFailedExFW; +import io.aklivity.zilla.runtime.binding.tcp.internal.types.event.TcpEventExFW; +import io.aklivity.zilla.runtime.engine.Configuration; +import io.aklivity.zilla.runtime.engine.event.EventFormatterSpi; + +public final class TcpEventFormatter implements EventFormatterSpi +{ + private static final String DNS_FAILED_FORMAT = "DNS_FAILED %s"; + + private final EventFW eventRO = new EventFW(); + private final TcpEventExFW tcpEventExRO = new TcpEventExFW(); + + TcpEventFormatter( + Configuration config) + { + } + + public String format( + DirectBuffer buffer, + int index, + int length) + { + final EventFW event = eventRO.wrap(buffer, index, index + length); + final TcpEventExFW extension = tcpEventExRO + .wrap(event.extension().buffer(), event.extension().offset(), event.extension().limit()); + String result = null; + switch (extension.kind()) + { + case DNS_FAILED: + { + final TcpDnsFailedExFW ex = extension.dnsFailed(); + result = String.format(DNS_FAILED_FORMAT, asString(ex.address())); + break; + } + } + return result; + } + + private static String asString( + StringFW stringFW) + { + String s = stringFW.asString(); + return s == null ? "" : s; + } +} diff --git a/runtime/binding-tcp/src/main/java/io/aklivity/zilla/runtime/binding/tcp/internal/TcpEventFormatterFactory.java b/runtime/binding-tcp/src/main/java/io/aklivity/zilla/runtime/binding/tcp/internal/TcpEventFormatterFactory.java new file mode 100644 index 0000000000..71ab9c3c70 --- /dev/null +++ b/runtime/binding-tcp/src/main/java/io/aklivity/zilla/runtime/binding/tcp/internal/TcpEventFormatterFactory.java @@ -0,0 +1,35 @@ +/* + * Copyright 2021-2023 Aklivity Inc. + * + * Aklivity licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package io.aklivity.zilla.runtime.binding.tcp.internal; + +import io.aklivity.zilla.runtime.engine.Configuration; +import io.aklivity.zilla.runtime.engine.event.EventFormatterFactorySpi; + +public final class TcpEventFormatterFactory implements EventFormatterFactorySpi +{ + @Override + public TcpEventFormatter create( + Configuration config) + { + return new TcpEventFormatter(config); + } + + @Override + public String type() + { + return TcpBinding.NAME; + } +} diff --git a/runtime/binding-tcp/src/main/moditect/module-info.java b/runtime/binding-tcp/src/main/moditect/module-info.java index 103492b28c..8f1a1dcd4b 100644 --- a/runtime/binding-tcp/src/main/moditect/module-info.java +++ b/runtime/binding-tcp/src/main/moditect/module-info.java @@ -27,4 +27,7 @@ provides io.aklivity.zilla.runtime.engine.config.ConditionConfigAdapterSpi with io.aklivity.zilla.runtime.binding.tcp.internal.config.TcpConditionConfigAdapter; + + provides io.aklivity.zilla.runtime.engine.event.EventFormatterFactorySpi + with io.aklivity.zilla.runtime.binding.tcp.internal.TcpEventFormatterFactory; } diff --git a/runtime/binding-tcp/src/main/resources/META-INF/services/io.aklivity.zilla.runtime.engine.event.EventFormatterFactorySpi b/runtime/binding-tcp/src/main/resources/META-INF/services/io.aklivity.zilla.runtime.engine.event.EventFormatterFactorySpi new file mode 100644 index 0000000000..11c94b1f1a --- /dev/null +++ b/runtime/binding-tcp/src/main/resources/META-INF/services/io.aklivity.zilla.runtime.engine.event.EventFormatterFactorySpi @@ -0,0 +1 @@ +io.aklivity.zilla.runtime.binding.tcp.internal.TcpEventFormatterFactory diff --git a/incubator/exporter-stdout/src/test/java/io/aklivity/zilla/runtime/exporter/stdout/internal/events/TcpEventsIT.java b/runtime/binding-tcp/src/test/java/io/aklivity/zilla/runtime/binding/tcp/internal/streams/EventIT.java similarity index 60% rename from incubator/exporter-stdout/src/test/java/io/aklivity/zilla/runtime/exporter/stdout/internal/events/TcpEventsIT.java rename to runtime/binding-tcp/src/test/java/io/aklivity/zilla/runtime/binding/tcp/internal/streams/EventIT.java index 989f89eb83..95917fb03a 100644 --- a/incubator/exporter-stdout/src/test/java/io/aklivity/zilla/runtime/exporter/stdout/internal/events/TcpEventsIT.java +++ b/runtime/binding-tcp/src/test/java/io/aklivity/zilla/runtime/binding/tcp/internal/streams/EventIT.java @@ -1,25 +1,25 @@ /* - * Copyright 2021-2023 Aklivity Inc + * Copyright 2021-2023 Aklivity Inc. * - * Licensed under the Aklivity Community License (the "License"); you may not use - * this file except in compliance with the License. You may obtain a copy of the - * License at + * Aklivity licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: * - * https://www.aklivity.io/aklivity-community-license/ + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. */ -package io.aklivity.zilla.runtime.exporter.stdout.internal.events; +package io.aklivity.zilla.runtime.binding.tcp.internal.streams; import static java.util.concurrent.TimeUnit.SECONDS; import static org.junit.rules.RuleChain.outerRule; import java.net.InetAddress; import java.net.UnknownHostException; -import java.util.regex.Pattern; import org.junit.Rule; import org.junit.Test; @@ -33,7 +33,7 @@ import io.aklivity.zilla.runtime.engine.test.annotation.Configuration; import io.aklivity.zilla.runtime.engine.test.annotation.Configure; -public class TcpEventsIT +public class EventIT { private final K3poRule k3po = new K3poRule() .addScriptRoot("net", "io/aklivity/zilla/specs/binding/tcp/streams/network/rfc793") @@ -47,24 +47,19 @@ public class TcpEventsIT .configurationRoot("io/aklivity/zilla/specs/binding/tcp/config") .clean(); - private final StdoutOutputRule output = new StdoutOutputRule(); - @Rule - public final TestRule chain = outerRule(output).around(engine).around(k3po).around(timeout); + public final TestRule chain = outerRule(engine).around(k3po).around(timeout); @Test - @Configuration("client.host.yaml") + @Configuration("client.event.yaml") @Specification({ "${app}/connection.failed/client" }) - @Configure(name = "zilla.exporter.stdout.output", - value = "io.aklivity.zilla.runtime.exporter.stdout.internal.events.StdoutOutputRule.OUT") @Configure(name = "zilla.engine.host.resolver", - value = "io.aklivity.zilla.runtime.exporter.stdout.internal.events.TcpEventsIT::resolveHost") + value = "io.aklivity.zilla.runtime.binding.tcp.internal.streams.EventIT::resolveHost") public void dnsResolutionFailed() throws Exception { k3po.finish(); - output.expect(Pattern.compile("test.app0 - \\[[^\\]]+\\] DNS_FAILED localhost\n")); } public static InetAddress[] resolveHost( diff --git a/runtime/binding-tls/src/main/java/io/aklivity/zilla/runtime/binding/tls/internal/TlsEventContext.java b/runtime/binding-tls/src/main/java/io/aklivity/zilla/runtime/binding/tls/internal/TlsEventContext.java index 22722224ea..ec7c2aa090 100644 --- a/runtime/binding-tls/src/main/java/io/aklivity/zilla/runtime/binding/tls/internal/TlsEventContext.java +++ b/runtime/binding-tls/src/main/java/io/aklivity/zilla/runtime/binding/tls/internal/TlsEventContext.java @@ -15,13 +15,20 @@ */ package io.aklivity.zilla.runtime.binding.tls.internal; +import static io.aklivity.zilla.runtime.binding.tls.internal.types.event.TlsEventType.TLS_FAILED; +import static io.aklivity.zilla.runtime.binding.tls.internal.types.event.TlsEventType.TLS_HANDSHAKE_FAILED; +import static io.aklivity.zilla.runtime.binding.tls.internal.types.event.TlsEventType.TLS_KEY_REJECTED; +import static io.aklivity.zilla.runtime.binding.tls.internal.types.event.TlsEventType.TLS_PEER_NOT_VERIFIED; +import static io.aklivity.zilla.runtime.binding.tls.internal.types.event.TlsEventType.TLS_PROTOCOL_REJECTED; + import java.nio.ByteBuffer; import java.time.Clock; -import org.agrona.MutableDirectBuffer; +import org.agrona.concurrent.AtomicBuffer; import org.agrona.concurrent.UnsafeBuffer; -import io.aklivity.zilla.runtime.binding.tls.internal.types.event.TlsEventFW; +import io.aklivity.zilla.runtime.binding.tls.internal.types.event.EventFW; +import io.aklivity.zilla.runtime.binding.tls.internal.types.event.TlsEventExFW; import io.aklivity.zilla.runtime.engine.EngineContext; import io.aklivity.zilla.runtime.engine.binding.function.MessageConsumer; @@ -29,8 +36,10 @@ public class TlsEventContext { private static final int EVENT_BUFFER_CAPACITY = 1024; - private final TlsEventFW.Builder tlsEventRW = new TlsEventFW.Builder(); - private final MutableDirectBuffer eventBuffer = new UnsafeBuffer(ByteBuffer.allocate(EVENT_BUFFER_CAPACITY)); + private final AtomicBuffer eventBuffer = new UnsafeBuffer(ByteBuffer.allocate(EVENT_BUFFER_CAPACITY)); + private final AtomicBuffer extensionBuffer = new UnsafeBuffer(ByteBuffer.allocate(EVENT_BUFFER_CAPACITY)); + private final EventFW.Builder eventRW = new EventFW.Builder(); + private final TlsEventExFW.Builder tlsEventExRW = new TlsEventExFW.Builder(); private final int tlsTypeId; private final MessageConsumer eventWriter; private final Clock clock; @@ -47,14 +56,19 @@ public void tlsFailed( long traceId, long bindingId) { - TlsEventFW event = tlsEventRW - .wrap(eventBuffer, 0, eventBuffer.capacity()) + TlsEventExFW extension = tlsEventExRW + .wrap(extensionBuffer, 0, extensionBuffer.capacity()) .tlsFailed(e -> e - .timestamp(clock.millis()) - .traceId(traceId) - .namespacedId(bindingId) + .typeId(TLS_FAILED.value()) ) .build(); + EventFW event = eventRW + .wrap(eventBuffer, 0, eventBuffer.capacity()) + .timestamp(clock.millis()) + .traceId(traceId) + .namespacedId(bindingId) + .extension(extension.buffer(), extension.offset(), extension.limit()) + .build(); eventWriter.accept(tlsTypeId, event.buffer(), event.offset(), event.limit()); } @@ -62,14 +76,19 @@ public void tlsProtocolRejected( long traceId, long bindingId) { - TlsEventFW event = tlsEventRW - .wrap(eventBuffer, 0, eventBuffer.capacity()) + TlsEventExFW extension = tlsEventExRW + .wrap(extensionBuffer, 0, extensionBuffer.capacity()) .tlsProtocolRejected(e -> e - .timestamp(clock.millis()) - .traceId(traceId) - .namespacedId(bindingId) + .typeId(TLS_PROTOCOL_REJECTED.value()) ) .build(); + EventFW event = eventRW + .wrap(eventBuffer, 0, eventBuffer.capacity()) + .timestamp(clock.millis()) + .traceId(traceId) + .namespacedId(bindingId) + .extension(extension.buffer(), extension.offset(), extension.limit()) + .build(); eventWriter.accept(tlsTypeId, event.buffer(), event.offset(), event.limit()); } @@ -77,14 +96,19 @@ public void tlsKeyRejected( long traceId, long bindingId) { - TlsEventFW event = tlsEventRW - .wrap(eventBuffer, 0, eventBuffer.capacity()) + TlsEventExFW extension = tlsEventExRW + .wrap(extensionBuffer, 0, extensionBuffer.capacity()) .tlsKeyRejected(e -> e - .timestamp(clock.millis()) - .traceId(traceId) - .namespacedId(bindingId) + .typeId(TLS_KEY_REJECTED.value()) ) .build(); + EventFW event = eventRW + .wrap(eventBuffer, 0, eventBuffer.capacity()) + .timestamp(clock.millis()) + .traceId(traceId) + .namespacedId(bindingId) + .extension(extension.buffer(), extension.offset(), extension.limit()) + .build(); eventWriter.accept(tlsTypeId, event.buffer(), event.offset(), event.limit()); } @@ -92,14 +116,19 @@ public void tlsPeerNotVerified( long traceId, long bindingId) { - TlsEventFW event = tlsEventRW - .wrap(eventBuffer, 0, eventBuffer.capacity()) + TlsEventExFW extension = tlsEventExRW + .wrap(extensionBuffer, 0, extensionBuffer.capacity()) .tlsPeerNotVerified(e -> e - .timestamp(clock.millis()) - .traceId(traceId) - .namespacedId(bindingId) + .typeId(TLS_PEER_NOT_VERIFIED.value()) ) .build(); + EventFW event = eventRW + .wrap(eventBuffer, 0, eventBuffer.capacity()) + .timestamp(clock.millis()) + .traceId(traceId) + .namespacedId(bindingId) + .extension(extension.buffer(), extension.offset(), extension.limit()) + .build(); eventWriter.accept(tlsTypeId, event.buffer(), event.offset(), event.limit()); } @@ -107,14 +136,19 @@ public void tlsHandshakeFailed( long traceId, long bindingId) { - TlsEventFW event = tlsEventRW - .wrap(eventBuffer, 0, eventBuffer.capacity()) + TlsEventExFW extension = tlsEventExRW + .wrap(extensionBuffer, 0, extensionBuffer.capacity()) .tlsHandshakeFailed(e -> e - .timestamp(clock.millis()) - .traceId(traceId) - .namespacedId(bindingId) + .typeId(TLS_HANDSHAKE_FAILED.value()) ) .build(); + EventFW event = eventRW + .wrap(eventBuffer, 0, eventBuffer.capacity()) + .timestamp(clock.millis()) + .traceId(traceId) + .namespacedId(bindingId) + .extension(extension.buffer(), extension.offset(), extension.limit()) + .build(); eventWriter.accept(tlsTypeId, event.buffer(), event.offset(), event.limit()); } } diff --git a/runtime/binding-tls/src/main/java/io/aklivity/zilla/runtime/binding/tls/internal/TlsEventFormatter.java b/runtime/binding-tls/src/main/java/io/aklivity/zilla/runtime/binding/tls/internal/TlsEventFormatter.java new file mode 100644 index 0000000000..49a03c9cb5 --- /dev/null +++ b/runtime/binding-tls/src/main/java/io/aklivity/zilla/runtime/binding/tls/internal/TlsEventFormatter.java @@ -0,0 +1,80 @@ +/* + * Copyright 2021-2023 Aklivity Inc. + * + * Aklivity licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package io.aklivity.zilla.runtime.binding.tls.internal; + +import org.agrona.DirectBuffer; + +import io.aklivity.zilla.runtime.binding.tls.internal.types.event.EventFW; +import io.aklivity.zilla.runtime.binding.tls.internal.types.event.TlsEventExFW; +import io.aklivity.zilla.runtime.engine.Configuration; +import io.aklivity.zilla.runtime.engine.event.EventFormatterSpi; + +public final class TlsEventFormatter implements EventFormatterSpi +{ + private static final String TLS_FAILED_FORMAT = "TLS_FAILED"; + private static final String PROTOCOL_REJECTED_FORMAT = "PROTOCOL_REJECTED"; + private static final String KEY_REJECTED_FORMAT = "KEY_REJECTED"; + private static final String PEER_NOT_VERIFIED_FORMAT = "PEER_NOT_VERIFIED"; + private static final String HANDSHAKE_FAILED_FORMAT = "HANDSHAKE_FAILED"; + + private final EventFW eventRO = new EventFW(); + private final TlsEventExFW tlsEventExRO = new TlsEventExFW(); + + TlsEventFormatter( + Configuration config) + { + } + + public String format( + DirectBuffer buffer, + int index, + int length) + { + final EventFW event = eventRO.wrap(buffer, index, index + length); + final TlsEventExFW extension = tlsEventExRO + .wrap(event.extension().buffer(), event.extension().offset(), event.extension().limit()); + String result = null; + switch (extension.kind()) + { + case TLS_FAILED: + { + result = TLS_FAILED_FORMAT; + break; + } + case TLS_PROTOCOL_REJECTED: + { + result = PROTOCOL_REJECTED_FORMAT; + break; + } + case TLS_KEY_REJECTED: + { + result = KEY_REJECTED_FORMAT; + break; + } + case TLS_PEER_NOT_VERIFIED: + { + result = PEER_NOT_VERIFIED_FORMAT; + break; + } + case TLS_HANDSHAKE_FAILED: + { + result = HANDSHAKE_FAILED_FORMAT; + break; + } + } + return result; + } +} diff --git a/runtime/binding-tls/src/main/java/io/aklivity/zilla/runtime/binding/tls/internal/TlsEventFormatterFactory.java b/runtime/binding-tls/src/main/java/io/aklivity/zilla/runtime/binding/tls/internal/TlsEventFormatterFactory.java new file mode 100644 index 0000000000..bd6a8996a2 --- /dev/null +++ b/runtime/binding-tls/src/main/java/io/aklivity/zilla/runtime/binding/tls/internal/TlsEventFormatterFactory.java @@ -0,0 +1,35 @@ +/* + * Copyright 2021-2023 Aklivity Inc. + * + * Aklivity licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package io.aklivity.zilla.runtime.binding.tls.internal; + +import io.aklivity.zilla.runtime.engine.Configuration; +import io.aklivity.zilla.runtime.engine.event.EventFormatterFactorySpi; + +public final class TlsEventFormatterFactory implements EventFormatterFactorySpi +{ + @Override + public TlsEventFormatter create( + Configuration config) + { + return new TlsEventFormatter(config); + } + + @Override + public String type() + { + return TlsBinding.NAME; + } +} diff --git a/runtime/binding-tls/src/main/moditect/module-info.java b/runtime/binding-tls/src/main/moditect/module-info.java index 194599b35c..d63aacfe37 100644 --- a/runtime/binding-tls/src/main/moditect/module-info.java +++ b/runtime/binding-tls/src/main/moditect/module-info.java @@ -29,4 +29,7 @@ provides io.aklivity.zilla.runtime.engine.config.ConditionConfigAdapterSpi with io.aklivity.zilla.runtime.binding.tls.internal.config.TlsConditionConfigAdapter; + + provides io.aklivity.zilla.runtime.engine.event.EventFormatterFactorySpi + with io.aklivity.zilla.runtime.binding.tls.internal.TlsEventFormatterFactory; } diff --git a/runtime/binding-tls/src/main/resources/META-INF/services/io.aklivity.zilla.runtime.engine.event.EventFormatterFactorySpi b/runtime/binding-tls/src/main/resources/META-INF/services/io.aklivity.zilla.runtime.engine.event.EventFormatterFactorySpi new file mode 100644 index 0000000000..24e5306dcf --- /dev/null +++ b/runtime/binding-tls/src/main/resources/META-INF/services/io.aklivity.zilla.runtime.engine.event.EventFormatterFactorySpi @@ -0,0 +1 @@ +io.aklivity.zilla.runtime.binding.tls.internal.TlsEventFormatterFactory diff --git a/runtime/binding-tls/src/test/java/io/aklivity/zilla/runtime/binding/tls/internal/streams/ClientIT.java b/runtime/binding-tls/src/test/java/io/aklivity/zilla/runtime/binding/tls/internal/streams/ClientIT.java index 3273970d18..5014f76995 100644 --- a/runtime/binding-tls/src/test/java/io/aklivity/zilla/runtime/binding/tls/internal/streams/ClientIT.java +++ b/runtime/binding-tls/src/test/java/io/aklivity/zilla/runtime/binding/tls/internal/streams/ClientIT.java @@ -377,4 +377,15 @@ public void shouldTimeoutHandshake() throws Exception { k3po.finish(); } + + @Test + @Configuration("client.event.yaml") + @Specification({ + "${app}/client.handshake.timeout/client", + "${net}/client.handshake.timeout/server" }) + @Configure(name = TlsConfigurationTest.TLS_HANDSHAKE_TIMEOUT_NAME, value = "1") + public void shouldLogHandshakeErrorEvent() throws Exception + { + k3po.finish(); + } } diff --git a/runtime/binding-tls/src/test/java/io/aklivity/zilla/runtime/binding/tls/internal/streams/ServerIT.java b/runtime/binding-tls/src/test/java/io/aklivity/zilla/runtime/binding/tls/internal/streams/ServerIT.java index f36f40709c..83c4a3b84d 100644 --- a/runtime/binding-tls/src/test/java/io/aklivity/zilla/runtime/binding/tls/internal/streams/ServerIT.java +++ b/runtime/binding-tls/src/test/java/io/aklivity/zilla/runtime/binding/tls/internal/streams/ServerIT.java @@ -318,4 +318,23 @@ public void shouldRejectWhenPortNotRouted() throws Exception { k3po.finish(); } + + @Test + @Configuration("server.event.tls.failed.yaml") + @Specification({ + "${net}/client.hello.malformed/client"}) + public void shouldLogTlsFailedEvent() throws Exception + { + k3po.finish(); + } + + @Test + @Configuration("server.event.handshake.failed.yaml") + @Specification({ + "${net}/server.handshake.timeout/client"}) + @Configure(name = TlsConfigurationTest.TLS_HANDSHAKE_TIMEOUT_NAME, value = "1") + public void shouldLogHandshakeFailedEvent() throws Exception + { + k3po.finish(); + } } diff --git a/runtime/engine/pom.xml b/runtime/engine/pom.xml index ccea03c210..29b6d8b63c 100644 --- a/runtime/engine/pom.xml +++ b/runtime/engine/pom.xml @@ -253,6 +253,7 @@ io/aklivity/zilla/runtime/engine/test/internal/**/*.schema.patch.json io/aklivity/zilla/runtime/engine/test/internal/binding/**/*.class io/aklivity/zilla/runtime/engine/test/internal/catalog/**/*.class + io/aklivity/zilla/runtime/engine/test/internal/event/**/*.class io/aklivity/zilla/runtime/engine/test/internal/exporter/**/*.class io/aklivity/zilla/runtime/engine/test/internal/guard/**/*.class io/aklivity/zilla/runtime/engine/test/internal/metrics/**/*.class diff --git a/runtime/engine/src/main/java/io/aklivity/zilla/runtime/engine/Engine.java b/runtime/engine/src/main/java/io/aklivity/zilla/runtime/engine/Engine.java index b89c0bde13..3172979cf4 100644 --- a/runtime/engine/src/main/java/io/aklivity/zilla/runtime/engine/Engine.java +++ b/runtime/engine/src/main/java/io/aklivity/zilla/runtime/engine/Engine.java @@ -61,6 +61,7 @@ import io.aklivity.zilla.runtime.engine.binding.function.MessageReader; import io.aklivity.zilla.runtime.engine.catalog.Catalog; import io.aklivity.zilla.runtime.engine.config.KindConfig; +import io.aklivity.zilla.runtime.engine.event.EventFormatterFactory; import io.aklivity.zilla.runtime.engine.exporter.Exporter; import io.aklivity.zilla.runtime.engine.ext.EngineExtContext; import io.aklivity.zilla.runtime.engine.ext.EngineExtSpi; @@ -108,6 +109,7 @@ public final class Engine implements Collector, AutoCloseable Collection vaults, Collection catalogs, Collection models, + EventFormatterFactory eventFormatterFactory, ErrorHandler errorHandler, Collection affinities, boolean readonly) @@ -161,9 +163,9 @@ public final class Engine implements Collector, AutoCloseable for (int coreIndex = 0; coreIndex < workerCount; coreIndex++) { EngineWorker worker = - new EngineWorker(config, tasks, labels, errorHandler, tuning::affinity, - bindings, exporters, guards, vaults, catalogs, models, metricGroups, - this, this::supplyEventReader, coreIndex, readonly); + new EngineWorker(config, tasks, labels, errorHandler, tuning::affinity, bindings, exporters, + guards, vaults, catalogs, models, metricGroups, this, this::supplyEventReader, + eventFormatterFactory, coreIndex, readonly); workers.add(worker); } this.workers = workers; diff --git a/runtime/engine/src/main/java/io/aklivity/zilla/runtime/engine/EngineBuilder.java b/runtime/engine/src/main/java/io/aklivity/zilla/runtime/engine/EngineBuilder.java index ae989060c0..3f05d5434f 100644 --- a/runtime/engine/src/main/java/io/aklivity/zilla/runtime/engine/EngineBuilder.java +++ b/runtime/engine/src/main/java/io/aklivity/zilla/runtime/engine/EngineBuilder.java @@ -27,6 +27,7 @@ import io.aklivity.zilla.runtime.engine.binding.BindingFactory; import io.aklivity.zilla.runtime.engine.catalog.Catalog; import io.aklivity.zilla.runtime.engine.catalog.CatalogFactory; +import io.aklivity.zilla.runtime.engine.event.EventFormatterFactory; import io.aklivity.zilla.runtime.engine.exporter.Exporter; import io.aklivity.zilla.runtime.engine.exporter.ExporterFactory; import io.aklivity.zilla.runtime.engine.guard.Guard; @@ -139,9 +140,11 @@ public Engine build() models.add(model); } + EventFormatterFactory eventFormatterFactory = EventFormatterFactory.instantiate(); + final ErrorHandler errorHandler = requireNonNull(this.errorHandler, "errorHandler"); return new Engine(config, bindings, exporters, guards, metricGroups, vaults, - catalogs, models, errorHandler, affinities, readonly); + catalogs, models, eventFormatterFactory, errorHandler, affinities, readonly); } } diff --git a/runtime/engine/src/main/java/io/aklivity/zilla/runtime/engine/EngineContext.java b/runtime/engine/src/main/java/io/aklivity/zilla/runtime/engine/EngineContext.java index 0360890834..8129da8b20 100644 --- a/runtime/engine/src/main/java/io/aklivity/zilla/runtime/engine/EngineContext.java +++ b/runtime/engine/src/main/java/io/aklivity/zilla/runtime/engine/EngineContext.java @@ -34,6 +34,7 @@ import io.aklivity.zilla.runtime.engine.config.BindingConfig; import io.aklivity.zilla.runtime.engine.config.ModelConfig; import io.aklivity.zilla.runtime.engine.config.NamespaceConfig; +import io.aklivity.zilla.runtime.engine.event.EventFormatter; import io.aklivity.zilla.runtime.engine.guard.GuardHandler; import io.aklivity.zilla.runtime.engine.metrics.Metric; import io.aklivity.zilla.runtime.engine.model.ConverterHandler; @@ -71,6 +72,8 @@ MessageConsumer supplySender( MessageConsumer supplyReceiver( long streamId); + EventFormatter supplyEventFormatter(); + void detachSender( long replyId); diff --git a/runtime/engine/src/main/java/io/aklivity/zilla/runtime/engine/event/EventFormatter.java b/runtime/engine/src/main/java/io/aklivity/zilla/runtime/engine/event/EventFormatter.java new file mode 100644 index 0000000000..f8ffd8ccd8 --- /dev/null +++ b/runtime/engine/src/main/java/io/aklivity/zilla/runtime/engine/event/EventFormatter.java @@ -0,0 +1,42 @@ +/* + * Copyright 2021-2023 Aklivity Inc. + * + * Aklivity licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package io.aklivity.zilla.runtime.engine.event; + +import org.agrona.DirectBuffer; +import org.agrona.collections.Long2ObjectHashMap; + +import io.aklivity.zilla.runtime.engine.factory.Factory; + +public final class EventFormatter extends Factory +{ + private final Long2ObjectHashMap formatters; + + EventFormatter( + Long2ObjectHashMap formatters) + { + this.formatters = formatters; + } + + public String format( + int msgTypeId, + DirectBuffer buffer, + int index, + int length) + { + EventFormatterSpi formatter = formatters.get(msgTypeId); + return formatter != null ? formatter.format(buffer, index, length) : null; + } +} diff --git a/runtime/engine/src/main/java/io/aklivity/zilla/runtime/engine/event/EventFormatterFactory.java b/runtime/engine/src/main/java/io/aklivity/zilla/runtime/engine/event/EventFormatterFactory.java new file mode 100644 index 0000000000..a4b083521a --- /dev/null +++ b/runtime/engine/src/main/java/io/aklivity/zilla/runtime/engine/event/EventFormatterFactory.java @@ -0,0 +1,58 @@ +/* + * Copyright 2021-2023 Aklivity Inc. + * + * Aklivity licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package io.aklivity.zilla.runtime.engine.event; + +import static java.util.ServiceLoader.load; + +import java.util.Map; + +import org.agrona.collections.Long2ObjectHashMap; + +import io.aklivity.zilla.runtime.engine.Configuration; +import io.aklivity.zilla.runtime.engine.EngineContext; +import io.aklivity.zilla.runtime.engine.factory.Factory; + +public final class EventFormatterFactory extends Factory +{ + private final Map factories; + + public EventFormatter create( + Configuration config, + EngineContext context) + { + Long2ObjectHashMap formatters = new Long2ObjectHashMap<>(); + for (Map.Entry entry : factories.entrySet()) + { + String type = entry.getKey(); + EventFormatterFactorySpi factory = entry.getValue(); + EventFormatterSpi formatter = factory.create(config); + int typeId = context.supplyTypeId(type); + formatters.put(typeId, formatter); + } + return new EventFormatter(formatters); + } + + public static EventFormatterFactory instantiate() + { + return instantiate(load(EventFormatterFactorySpi.class), EventFormatterFactory::new); + } + + private EventFormatterFactory( + Map factories) + { + this.factories = factories; + } +} diff --git a/runtime/engine/src/main/java/io/aklivity/zilla/runtime/engine/event/EventFormatterFactorySpi.java b/runtime/engine/src/main/java/io/aklivity/zilla/runtime/engine/event/EventFormatterFactorySpi.java new file mode 100644 index 0000000000..4958f95153 --- /dev/null +++ b/runtime/engine/src/main/java/io/aklivity/zilla/runtime/engine/event/EventFormatterFactorySpi.java @@ -0,0 +1,25 @@ +/* + * Copyright 2021-2023 Aklivity Inc. + * + * Aklivity licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package io.aklivity.zilla.runtime.engine.event; + +import io.aklivity.zilla.runtime.engine.Configuration; +import io.aklivity.zilla.runtime.engine.factory.FactorySpi; + +public interface EventFormatterFactorySpi extends FactorySpi +{ + EventFormatterSpi create( + Configuration config); +} diff --git a/runtime/engine/src/main/java/io/aklivity/zilla/runtime/engine/event/EventFormatterSpi.java b/runtime/engine/src/main/java/io/aklivity/zilla/runtime/engine/event/EventFormatterSpi.java new file mode 100644 index 0000000000..9bc5e24394 --- /dev/null +++ b/runtime/engine/src/main/java/io/aklivity/zilla/runtime/engine/event/EventFormatterSpi.java @@ -0,0 +1,26 @@ +/* + * Copyright 2021-2023 Aklivity Inc. + * + * Aklivity licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package io.aklivity.zilla.runtime.engine.event; + +import org.agrona.DirectBuffer; + +public interface EventFormatterSpi +{ + String format( + DirectBuffer buffer, + int index, + int length); +} diff --git a/runtime/engine/src/main/java/io/aklivity/zilla/runtime/engine/internal/registry/EngineWorker.java b/runtime/engine/src/main/java/io/aklivity/zilla/runtime/engine/internal/registry/EngineWorker.java index f07bfe1a2f..0ff8dab4dc 100644 --- a/runtime/engine/src/main/java/io/aklivity/zilla/runtime/engine/internal/registry/EngineWorker.java +++ b/runtime/engine/src/main/java/io/aklivity/zilla/runtime/engine/internal/registry/EngineWorker.java @@ -99,6 +99,8 @@ import io.aklivity.zilla.runtime.engine.config.BindingConfig; import io.aklivity.zilla.runtime.engine.config.ModelConfig; import io.aklivity.zilla.runtime.engine.config.NamespaceConfig; +import io.aklivity.zilla.runtime.engine.event.EventFormatter; +import io.aklivity.zilla.runtime.engine.event.EventFormatterFactory; import io.aklivity.zilla.runtime.engine.exporter.Exporter; import io.aklivity.zilla.runtime.engine.exporter.ExporterContext; import io.aklivity.zilla.runtime.engine.exporter.ExporterHandler; @@ -216,6 +218,7 @@ public class EngineWorker implements EngineContext, Agent private final HistogramsLayout histogramsLayout; private final EventsLayout eventsLayout; private final Supplier supplyEventReader; + private final EventFormatter eventFormatter; private long initialId; private long promiseId; private long traceId; @@ -239,6 +242,7 @@ public EngineWorker( Collection metricGroups, Collector collector, Supplier supplyEventReader, + EventFormatterFactory eventFormatterFactory, int index, boolean readonly) { @@ -420,6 +424,7 @@ public EngineWorker( this.errorHandler = errorHandler; this.exportersById = new Long2ObjectHashMap<>(); this.supplyEventReader = supplyEventReader; + this.eventFormatter = eventFormatterFactory.create(config, this); } public static int indexOfId( @@ -1608,6 +1613,11 @@ public MessageReader supplyEventReader() return supplyEventReader.get(); } + public EventFormatter supplyEventFormatter() + { + return this.eventFormatter; + } + private MessageConsumer supplyWriter( int index) { diff --git a/runtime/engine/src/main/moditect/module-info.java b/runtime/engine/src/main/moditect/module-info.java index 4c15cb57b3..529ca971b7 100644 --- a/runtime/engine/src/main/moditect/module-info.java +++ b/runtime/engine/src/main/moditect/module-info.java @@ -23,6 +23,7 @@ exports io.aklivity.zilla.runtime.engine.catalog; exports io.aklivity.zilla.runtime.engine.model; exports io.aklivity.zilla.runtime.engine.model.function; + exports io.aklivity.zilla.runtime.engine.event; exports io.aklivity.zilla.runtime.engine.exporter; exports io.aklivity.zilla.runtime.engine.factory; exports io.aklivity.zilla.runtime.engine.guard; @@ -61,6 +62,7 @@ uses io.aklivity.zilla.runtime.engine.binding.BindingFactorySpi; uses io.aklivity.zilla.runtime.engine.catalog.CatalogFactorySpi; uses io.aklivity.zilla.runtime.engine.model.ModelFactorySpi; + uses io.aklivity.zilla.runtime.engine.event.EventFormatterFactorySpi; uses io.aklivity.zilla.runtime.engine.exporter.ExporterFactorySpi; uses io.aklivity.zilla.runtime.engine.guard.GuardFactorySpi; uses io.aklivity.zilla.runtime.engine.metrics.MetricGroupFactorySpi; diff --git a/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/EventIT.java b/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/EventIT.java new file mode 100644 index 0000000000..543bf5ea67 --- /dev/null +++ b/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/EventIT.java @@ -0,0 +1,59 @@ +/* + * Copyright 2021-2023 Aklivity Inc. + * + * Aklivity licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package io.aklivity.zilla.runtime.engine.test; + +import static java.util.concurrent.TimeUnit.SECONDS; +import static org.junit.rules.RuleChain.outerRule; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.DisableOnDebug; +import org.junit.rules.TestRule; +import org.junit.rules.Timeout; +import org.kaazing.k3po.junit.annotation.Specification; +import org.kaazing.k3po.junit.rules.K3poRule; + +import io.aklivity.zilla.runtime.engine.test.annotation.Configuration; + +public class EventIT +{ + private final K3poRule k3po = new K3poRule() + .addScriptRoot("net", "io/aklivity/zilla/specs/engine/streams/network") + .addScriptRoot("app", "io/aklivity/zilla/specs/engine/streams/application"); + + private final TestRule timeout = new DisableOnDebug(new Timeout(5, SECONDS)); + + private final EngineRule engine = new EngineRule() + .directory("target/zilla-itests") + .countersBufferCapacity(4096) + .configurationRoot("io/aklivity/zilla/specs/engine/config") + .external("app0") + .clean(); + + @Rule + public final TestRule chain = outerRule(engine).around(k3po).around(timeout); + + @Test + @Configuration("server.event.yaml") + @Specification({ + "${net}/event/client", + "${app}/event/server" + }) + public void shouldLogEvents() throws Exception + { + k3po.finish(); + } +} diff --git a/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/binding/TestBinding.java b/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/binding/TestBinding.java index 662111251d..98c509264a 100644 --- a/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/binding/TestBinding.java +++ b/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/binding/TestBinding.java @@ -23,6 +23,8 @@ public final class TestBinding implements Binding { + public static final String NAME = "test"; + TestBinding( Configuration config) { diff --git a/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/binding/TestBindingFactory.java b/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/binding/TestBindingFactory.java index 3765997399..a56b723aff 100644 --- a/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/binding/TestBindingFactory.java +++ b/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/binding/TestBindingFactory.java @@ -15,6 +15,9 @@ */ package io.aklivity.zilla.runtime.engine.test.internal.binding; +import java.util.LinkedList; +import java.util.List; + import org.agrona.DirectBuffer; import org.agrona.MutableDirectBuffer; import org.agrona.collections.Long2LongHashMap; @@ -22,8 +25,13 @@ import io.aklivity.zilla.runtime.engine.EngineContext; import io.aklivity.zilla.runtime.engine.binding.BindingHandler; import io.aklivity.zilla.runtime.engine.binding.function.MessageConsumer; +import io.aklivity.zilla.runtime.engine.catalog.CatalogHandler; import io.aklivity.zilla.runtime.engine.config.BindingConfig; import io.aklivity.zilla.runtime.engine.config.RouteConfig; +import io.aklivity.zilla.runtime.engine.guard.GuardHandler; +import io.aklivity.zilla.runtime.engine.namespace.NamespacedId; +import io.aklivity.zilla.runtime.engine.test.internal.binding.config.TestBindingOptionsConfig; +import io.aklivity.zilla.runtime.engine.test.internal.event.TestEventContext; import io.aklivity.zilla.runtime.engine.test.internal.k3po.ext.types.OctetsFW; import io.aklivity.zilla.runtime.engine.test.internal.k3po.ext.types.stream.AbortFW; import io.aklivity.zilla.runtime.engine.test.internal.k3po.ext.types.stream.BeginFW; @@ -62,12 +70,20 @@ final class TestBindingFactory implements BindingHandler private final EngineContext context; private final Long2LongHashMap router; + private final TestEventContext event; + + private List catalogs; + private GuardHandler guard; + private String credentials; + private List events; + private int eventIndex; TestBindingFactory( EngineContext context) { this.context = context; this.router = new Long2LongHashMap(-1L); + this.event = new TestEventContext(context); } public void attach( @@ -82,6 +98,29 @@ public void attach( { router.put(binding.id, exit.id); } + + TestBindingOptionsConfig options = (TestBindingOptionsConfig) binding.options; + if (options != null) + { + if (options.catalogs != null) + { + this.catalogs = new LinkedList<>(); + for (String catalog : options.catalogs) + { + int namespaceId = context.supplyTypeId(binding.namespace); + int catalogId = context.supplyTypeId(catalog); + catalogs.add(context.supplyCatalog(NamespacedId.id(namespaceId, catalogId))); + } + } + if (options.authorization != null) + { + int namespaceId = context.supplyTypeId(binding.namespace); + int guardId = context.supplyTypeId(options.authorization.name); + this.guard = context.supplyGuard(NamespacedId.id(namespaceId, guardId)); + this.credentials = options.authorization.credentials; + } + this.events = options.events; + } } public void detach( @@ -204,6 +243,24 @@ private void onInitialBegin( long traceId = begin.traceId(); target.doInitialBegin(traceId); + + if (catalogs != null) + { + for (CatalogHandler catalog : catalogs) + { + catalog.resolve(0); + } + } + if (guard != null) + { + guard.reauthorize(traceId, routedId, 0, credentials); + } + while (events != null && eventIndex < events.size()) + { + TestBindingOptionsConfig.Event e = events.get(eventIndex); + event.connected(traceId, routedId, e.timestamp, e.message); + eventIndex++; + } } private void onInitialData( diff --git a/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/binding/config/TestAuthorizationConfig.java b/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/binding/config/TestAuthorizationConfig.java new file mode 100644 index 0000000000..6d8069074d --- /dev/null +++ b/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/binding/config/TestAuthorizationConfig.java @@ -0,0 +1,30 @@ +/* + * Copyright 2021-2023 Aklivity Inc. + * + * Aklivity licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package io.aklivity.zilla.runtime.engine.test.internal.binding.config; + +public final class TestAuthorizationConfig +{ + public final String name; + public final String credentials; + + public TestAuthorizationConfig( + String name, + String credentials) + { + this.name = name; + this.credentials = credentials; + } +} diff --git a/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/binding/config/TestBindingOptionsConfig.java b/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/binding/config/TestBindingOptionsConfig.java index b40a76ec60..96e006b403 100644 --- a/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/binding/config/TestBindingOptionsConfig.java +++ b/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/binding/config/TestBindingOptionsConfig.java @@ -15,6 +15,7 @@ */ package io.aklivity.zilla.runtime.engine.test.internal.binding.config; +import java.util.List; import java.util.function.Function; import io.aklivity.zilla.runtime.engine.config.OptionsConfig; @@ -22,6 +23,9 @@ public final class TestBindingOptionsConfig extends OptionsConfig { public final String mode; + public final TestAuthorizationConfig authorization; + public final List catalogs; + public final List events; public static TestBindingOptionsConfigBuilder builder() { @@ -35,8 +39,28 @@ public static TestBindingOptionsConfigBuilder builder( } TestBindingOptionsConfig( - String mode) + String mode, + TestAuthorizationConfig authorization, + List catalogs, + List events) { this.mode = mode; + this.authorization = authorization; + this.catalogs = catalogs; + this.events = events; + } + + public static final class Event + { + public final long timestamp; + public final String message; + + public Event( + long timestamp, + String message) + { + this.timestamp = timestamp; + this.message = message; + } } } diff --git a/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/binding/config/TestBindingOptionsConfigAdapter.java b/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/binding/config/TestBindingOptionsConfigAdapter.java index e4b2b09630..6a0b4878d1 100644 --- a/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/binding/config/TestBindingOptionsConfigAdapter.java +++ b/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/binding/config/TestBindingOptionsConfigAdapter.java @@ -16,8 +16,12 @@ package io.aklivity.zilla.runtime.engine.test.internal.binding.config; import jakarta.json.Json; +import jakarta.json.JsonArray; +import jakarta.json.JsonArrayBuilder; import jakarta.json.JsonObject; import jakarta.json.JsonObjectBuilder; +import jakarta.json.JsonString; +import jakarta.json.JsonValue; import io.aklivity.zilla.runtime.engine.config.OptionsConfig; import io.aklivity.zilla.runtime.engine.config.OptionsConfigAdapterSpi; @@ -25,6 +29,12 @@ public final class TestBindingOptionsConfigAdapter implements OptionsConfigAdapterSpi { private static final String MODE_NAME = "mode"; + private static final String CATALOGS_NAME = "catalogs"; + private static final String AUTHORIZATION_NAME = "authorization"; + private static final String CREDENTIALS_NAME = "credentials"; + private static final String EVENTS_NAME = "events"; + private static final String TIMESTAMP_NAME = "timestamp"; + private static final String MESSAGE_NAME = "message"; @Override public Kind kind() @@ -46,7 +56,39 @@ public JsonObject adaptToJson( JsonObjectBuilder object = Json.createObjectBuilder(); - object.add(MODE_NAME, testOptions.mode); + if (testOptions.mode != null) + { + object.add(MODE_NAME, testOptions.mode); + } + if (testOptions.catalogs != null) + { + JsonArrayBuilder catalogs = Json.createArrayBuilder(); + for (String catalog : testOptions.catalogs) + { + catalogs.add(catalog); + } + object.add(CATALOGS_NAME, catalogs); + } + if (testOptions.authorization != null) + { + JsonObjectBuilder credentials = Json.createObjectBuilder(); + credentials.add(CREDENTIALS_NAME, testOptions.authorization.credentials); + JsonObjectBuilder authorization = Json.createObjectBuilder(); + authorization.add(testOptions.authorization.name, credentials); + object.add(AUTHORIZATION_NAME, authorization); + } + if (testOptions.events != null) + { + JsonArrayBuilder events = Json.createArrayBuilder(); + for (TestBindingOptionsConfig.Event e : testOptions.events) + { + JsonObjectBuilder event = Json.createObjectBuilder(); + event.add(TIMESTAMP_NAME, e.timestamp); + event.add(MESSAGE_NAME, e.message); + events.add(event); + } + object.add(EVENTS_NAME, events); + } return object.build(); } @@ -63,6 +105,40 @@ public OptionsConfig adaptFromJson( { testOptions.mode(object.getString(MODE_NAME)); } + if (object.containsKey(CATALOGS_NAME)) + { + JsonArray catalogs = object.getJsonArray(CATALOGS_NAME); + for (JsonValue catalog : catalogs) + { + testOptions.catalog(((JsonString) catalog).getString()); + } + } + if (object.containsKey(AUTHORIZATION_NAME)) + { + JsonObject authorization = object.getJsonObject(AUTHORIZATION_NAME); + String name = authorization.keySet().stream().findFirst().orElse(null); + if (name != null) + { + JsonObject guard = authorization.getJsonObject(name); + if (guard.containsKey(CREDENTIALS_NAME)) + { + String credentials = guard.getString(CREDENTIALS_NAME); + testOptions.authorization(name, credentials); + } + } + } + if (object.containsKey(EVENTS_NAME)) + { + JsonArray events = object.getJsonArray(EVENTS_NAME); + for (JsonValue e : events) + { + JsonObject e0 = e.asJsonObject(); + if (e0.containsKey(TIMESTAMP_NAME) && e0.containsKey(MESSAGE_NAME)) + { + testOptions.event(e0.getInt(TIMESTAMP_NAME), e0.getString(MESSAGE_NAME)); + } + } + } } return testOptions.build(); diff --git a/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/binding/config/TestBindingOptionsConfigBuilder.java b/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/binding/config/TestBindingOptionsConfigBuilder.java index b8ecf148aa..dadfe4a81f 100644 --- a/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/binding/config/TestBindingOptionsConfigBuilder.java +++ b/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/binding/config/TestBindingOptionsConfigBuilder.java @@ -15,6 +15,8 @@ */ package io.aklivity.zilla.runtime.engine.test.internal.binding.config; +import java.util.LinkedList; +import java.util.List; import java.util.function.Function; import io.aklivity.zilla.runtime.engine.config.ConfigBuilder; @@ -25,6 +27,9 @@ public final class TestBindingOptionsConfigBuilder extends ConfigBuilder mapper; private String mode; + private TestAuthorizationConfig authorization; + private List catalogs; + private List events; TestBindingOptionsConfigBuilder( Function mapper) @@ -46,9 +51,40 @@ public TestBindingOptionsConfigBuilder mode( return this; } + public TestBindingOptionsConfigBuilder catalog( + String catalog) + { + if (this.catalogs == null) + { + this.catalogs = new LinkedList<>(); + } + this.catalogs.add(catalog); + return this; + } + + public TestBindingOptionsConfigBuilder authorization( + String name, + String credentials) + { + this.authorization = new TestAuthorizationConfig(name, credentials); + return this; + } + + public TestBindingOptionsConfigBuilder event( + long timestamp, + String message) + { + if (this.events == null) + { + this.events = new LinkedList<>(); + } + this.events.add(new TestBindingOptionsConfig.Event(timestamp, message)); + return this; + } + @Override public T build() { - return mapper.apply(new TestBindingOptionsConfig(mode)); + return mapper.apply(new TestBindingOptionsConfig(mode, authorization, catalogs, events)); } } diff --git a/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/event/TestEventContext.java b/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/event/TestEventContext.java new file mode 100644 index 0000000000..957bbdcd84 --- /dev/null +++ b/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/event/TestEventContext.java @@ -0,0 +1,64 @@ +/* + * Copyright 2021-2023 Aklivity Inc. + * + * Aklivity licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package io.aklivity.zilla.runtime.engine.test.internal.event; + +import java.nio.ByteBuffer; +import java.time.Clock; + +import org.agrona.concurrent.AtomicBuffer; +import org.agrona.concurrent.UnsafeBuffer; + +import io.aklivity.zilla.runtime.engine.EngineContext; +import io.aklivity.zilla.runtime.engine.binding.function.MessageConsumer; +import io.aklivity.zilla.runtime.engine.internal.types.String8FW; +import io.aklivity.zilla.runtime.engine.internal.types.event.EventFW; +import io.aklivity.zilla.runtime.engine.test.internal.binding.TestBinding; + +public class TestEventContext +{ + private static final int EVENT_BUFFER_CAPACITY = 2048; + + private final AtomicBuffer eventBuffer = new UnsafeBuffer(ByteBuffer.allocate(EVENT_BUFFER_CAPACITY)); + private final EventFW.Builder eventRW = new EventFW.Builder(); + private final int testTypeId; + private final MessageConsumer eventWriter; + private final Clock clock; + + public TestEventContext( + EngineContext context) + { + this.testTypeId = context.supplyTypeId(TestBinding.NAME); + this.eventWriter = context.supplyEventWriter(); + this.clock = context.clock(); + } + + public void connected( + long traceId, + long bindingId, + long timestamp, + String message) + { + String8FW extension = new String8FW(message); + EventFW event = eventRW + .wrap(eventBuffer, 0, eventBuffer.capacity()) + .timestamp(timestamp) + .traceId(traceId) + .namespacedId(bindingId) + .extension(extension.buffer(), extension.offset(), extension.limit()) + .build(); + eventWriter.accept(testTypeId, event.buffer(), event.offset(), event.limit()); + } +} diff --git a/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/event/TestEventFormatter.java b/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/event/TestEventFormatter.java new file mode 100644 index 0000000000..55a02b0111 --- /dev/null +++ b/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/event/TestEventFormatter.java @@ -0,0 +1,45 @@ +/* + * Copyright 2021-2023 Aklivity Inc. + * + * Aklivity licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package io.aklivity.zilla.runtime.engine.test.internal.event; + +import org.agrona.DirectBuffer; + +import io.aklivity.zilla.runtime.engine.Configuration; +import io.aklivity.zilla.runtime.engine.event.EventFormatterSpi; +import io.aklivity.zilla.runtime.engine.internal.types.String8FW; +import io.aklivity.zilla.runtime.engine.internal.types.event.EventFW; + +public final class TestEventFormatter implements EventFormatterSpi +{ + private final EventFW eventRO = new EventFW(); + private final String8FW extensionRO = new String8FW(); + + TestEventFormatter( + Configuration config) + { + } + + @Override + public String format( + DirectBuffer buffer, + int index, + int length) + { + final EventFW event = eventRO.wrap(buffer, index, index + length); + String8FW extension = extensionRO.wrap(event.extension().buffer(), event.extension().offset(), event.extension().limit()); + return extension.asString(); + } +} diff --git a/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/event/TestEventFormatterFactory.java b/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/event/TestEventFormatterFactory.java new file mode 100644 index 0000000000..7f026f5c27 --- /dev/null +++ b/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/event/TestEventFormatterFactory.java @@ -0,0 +1,36 @@ +/* + * Copyright 2021-2023 Aklivity Inc. + * + * Aklivity licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package io.aklivity.zilla.runtime.engine.test.internal.event; + +import io.aklivity.zilla.runtime.engine.Configuration; +import io.aklivity.zilla.runtime.engine.event.EventFormatterFactorySpi; +import io.aklivity.zilla.runtime.engine.test.internal.binding.TestBinding; + +public class TestEventFormatterFactory implements EventFormatterFactorySpi +{ + @Override + public TestEventFormatter create( + Configuration config) + { + return new TestEventFormatter(config); + } + + @Override + public String type() + { + return TestBinding.NAME; + } +} diff --git a/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/exporter/TestExporter.java b/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/exporter/TestExporter.java index c156ad5a20..dfe1576f86 100644 --- a/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/exporter/TestExporter.java +++ b/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/exporter/TestExporter.java @@ -45,6 +45,6 @@ public URL type() public ExporterContext supply( EngineContext context) { - return new TestExporterContext(); + return new TestExporterContext(context); } } diff --git a/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/exporter/TestExporterContext.java b/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/exporter/TestExporterContext.java index 8c87e79390..eb8b353a38 100644 --- a/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/exporter/TestExporterContext.java +++ b/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/exporter/TestExporterContext.java @@ -18,6 +18,7 @@ import java.util.List; import java.util.function.LongFunction; +import io.aklivity.zilla.runtime.engine.EngineContext; import io.aklivity.zilla.runtime.engine.config.AttributeConfig; import io.aklivity.zilla.runtime.engine.config.ExporterConfig; import io.aklivity.zilla.runtime.engine.config.KindConfig; @@ -27,14 +28,22 @@ public class TestExporterContext implements ExporterContext { + private final EngineContext context; + + public TestExporterContext( + EngineContext context) + { + this.context = context; + } + @Override public ExporterHandler attach( - ExporterConfig config, + ExporterConfig exporter, List attributes, Collector collector, LongFunction resolveKind) { - return new TestExporterHandler(); + return new TestExporterHandler(context, exporter); } @Override diff --git a/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/exporter/TestExporterHandler.java b/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/exporter/TestExporterHandler.java index abcca20fd9..d8aa76d1c4 100644 --- a/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/exporter/TestExporterHandler.java +++ b/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/exporter/TestExporterHandler.java @@ -15,10 +15,36 @@ */ package io.aklivity.zilla.runtime.engine.test.internal.exporter; +import org.agrona.DirectBuffer; + +import io.aklivity.zilla.runtime.engine.EngineContext; +import io.aklivity.zilla.runtime.engine.binding.function.MessageReader; +import io.aklivity.zilla.runtime.engine.config.ExporterConfig; +import io.aklivity.zilla.runtime.engine.event.EventFormatter; import io.aklivity.zilla.runtime.engine.exporter.ExporterHandler; +import io.aklivity.zilla.runtime.engine.internal.types.event.EventFW; +import io.aklivity.zilla.runtime.engine.test.internal.exporter.config.TestExporterOptionsConfig; class TestExporterHandler implements ExporterHandler { + private final EngineContext context; + private final TestExporterOptionsConfig options; + private final MessageReader readEvent; + private final EventFormatter formatter; + private final EventFW eventRO = new EventFW(); + + private int eventIndex; + + TestExporterHandler( + EngineContext context, + ExporterConfig exporter) + { + this.context = context; + this.readEvent = context.supplyEventReader(); + this.formatter = context.supplyEventFormatter(); + this.options = (TestExporterOptionsConfig) exporter.options; + } + @Override public void start() { @@ -27,11 +53,32 @@ public void start() @Override public int export() { - return 0; + return readEvent.read(this::handleEvent, 1); } @Override public void stop() { } + + private void handleEvent( + int msgTypeId, + DirectBuffer buffer, + int index, + int length) + { + final EventFW event = eventRO.wrap(buffer, index, index + length); + String qname = context.supplyQName(event.namespacedId()); + String message = formatter.format(msgTypeId, buffer, index, length); + if (options.events != null && eventIndex < options.events.size()) + { + TestExporterOptionsConfig.Event e = options.events.get(eventIndex); + if (!e.qName.equals(qname) || !e.message.equals(message)) + { + throw new IllegalStateException(String.format("event mismatch, expected: %s %s, got: %s %s", + e.qName, e.message, qname, message)); + } + eventIndex++; + } + } } diff --git a/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/exporter/config/TestExporterOptionsConfig.java b/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/exporter/config/TestExporterOptionsConfig.java index 989b155ed7..1ca1597582 100644 --- a/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/exporter/config/TestExporterOptionsConfig.java +++ b/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/exporter/config/TestExporterOptionsConfig.java @@ -15,6 +15,7 @@ */ package io.aklivity.zilla.runtime.engine.test.internal.exporter.config; +import java.util.List; import java.util.function.Function; import io.aklivity.zilla.runtime.engine.config.OptionsConfig; @@ -22,6 +23,7 @@ public final class TestExporterOptionsConfig extends OptionsConfig { public final String mode; + public final List events; public static TestExporterOptionsConfigBuilder builder() { @@ -35,8 +37,24 @@ public static TestExporterOptionsConfigBuilder builder( } TestExporterOptionsConfig( - String mode) + String mode, + List events) { this.mode = mode; + this.events = events; + } + + public static final class Event + { + public final String qName; + public final String message; + + public Event( + String qName, + String message) + { + this.qName = qName; + this.message = message; + } } } diff --git a/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/exporter/config/TestExporterOptionsConfigAdapter.java b/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/exporter/config/TestExporterOptionsConfigAdapter.java index 8694215761..3c31073a31 100644 --- a/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/exporter/config/TestExporterOptionsConfigAdapter.java +++ b/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/exporter/config/TestExporterOptionsConfigAdapter.java @@ -18,8 +18,11 @@ import static java.util.function.Function.identity; import jakarta.json.Json; +import jakarta.json.JsonArray; +import jakarta.json.JsonArrayBuilder; import jakarta.json.JsonObject; import jakarta.json.JsonObjectBuilder; +import jakarta.json.JsonValue; import io.aklivity.zilla.runtime.engine.config.OptionsConfig; import io.aklivity.zilla.runtime.engine.config.OptionsConfigAdapterSpi; @@ -27,6 +30,9 @@ public final class TestExporterOptionsConfigAdapter implements OptionsConfigAdapterSpi { private static final String MODE_NAME = "mode"; + private static final String EVENTS_NAME = "events"; + private static final String QNAME_NAME = "qname"; + private static final String MESSAGE_NAME = "message"; @Override public Kind kind() @@ -48,7 +54,23 @@ public JsonObject adaptToJson( JsonObjectBuilder object = Json.createObjectBuilder(); - object.add(MODE_NAME, testOptions.mode); + if (testOptions.mode != null) + { + object.add(MODE_NAME, testOptions.mode); + } + + if (testOptions.events != null) + { + JsonArrayBuilder events = Json.createArrayBuilder(); + for (TestExporterOptionsConfig.Event e : testOptions.events) + { + JsonObjectBuilder event = Json.createObjectBuilder(); + event.add(QNAME_NAME, e.qName); + event.add(MESSAGE_NAME, e.message); + events.add(event); + } + object.add(EVENTS_NAME, events); + } return object.build(); } @@ -66,6 +88,18 @@ public OptionsConfig adaptFromJson( { testOptions.mode(object.getString(MODE_NAME)); } + if (object.containsKey(EVENTS_NAME)) + { + JsonArray events = object.getJsonArray(EVENTS_NAME); + for (JsonValue e : events) + { + JsonObject e0 = e.asJsonObject(); + if (e0.containsKey(QNAME_NAME) && e0.containsKey(MESSAGE_NAME)) + { + testOptions.event(e0.getString(QNAME_NAME), e0.getString(MESSAGE_NAME)); + } + } + } } return testOptions.build(); diff --git a/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/exporter/config/TestExporterOptionsConfigBuilder.java b/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/exporter/config/TestExporterOptionsConfigBuilder.java index 27abc1cbca..db8432cf1d 100644 --- a/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/exporter/config/TestExporterOptionsConfigBuilder.java +++ b/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/exporter/config/TestExporterOptionsConfigBuilder.java @@ -15,6 +15,8 @@ */ package io.aklivity.zilla.runtime.engine.test.internal.exporter.config; +import java.util.LinkedList; +import java.util.List; import java.util.function.Function; import io.aklivity.zilla.runtime.engine.config.ConfigBuilder; @@ -25,6 +27,7 @@ public final class TestExporterOptionsConfigBuilder extends ConfigBuilder mapper; private String mode; + private List events; TestExporterOptionsConfigBuilder( Function mapper) @@ -46,9 +49,21 @@ public TestExporterOptionsConfigBuilder mode( return this; } + public TestExporterOptionsConfigBuilder event( + String qName, + String message) + { + if (this.events == null) + { + this.events = new LinkedList<>(); + } + this.events.add(new TestExporterOptionsConfig.Event(qName, message)); + return this; + } + @Override public T build() { - return mapper.apply(new TestExporterOptionsConfig(mode)); + return mapper.apply(new TestExporterOptionsConfig(mode, events)); } } diff --git a/runtime/engine/src/test/resources/META-INF/services/io.aklivity.zilla.runtime.engine.event.EventFormatterFactorySpi b/runtime/engine/src/test/resources/META-INF/services/io.aklivity.zilla.runtime.engine.event.EventFormatterFactorySpi new file mode 100644 index 0000000000..1bb290c506 --- /dev/null +++ b/runtime/engine/src/test/resources/META-INF/services/io.aklivity.zilla.runtime.engine.event.EventFormatterFactorySpi @@ -0,0 +1 @@ +io.aklivity.zilla.runtime.engine.test.internal.event.TestEventFormatterFactory diff --git a/runtime/guard-jwt/src/main/java/io/aklivity/zilla/runtime/guard/jwt/internal/JwtEventContext.java b/runtime/guard-jwt/src/main/java/io/aklivity/zilla/runtime/guard/jwt/internal/JwtEventContext.java index 99d0fa6146..3eb93da4f0 100644 --- a/runtime/guard-jwt/src/main/java/io/aklivity/zilla/runtime/guard/jwt/internal/JwtEventContext.java +++ b/runtime/guard-jwt/src/main/java/io/aklivity/zilla/runtime/guard/jwt/internal/JwtEventContext.java @@ -14,22 +14,27 @@ */ package io.aklivity.zilla.runtime.guard.jwt.internal; +import static io.aklivity.zilla.runtime.guard.jwt.internal.types.event.JwtEventType.AUTHORIZATION_FAILED; + import java.nio.ByteBuffer; import java.time.Clock; -import org.agrona.MutableDirectBuffer; +import org.agrona.concurrent.AtomicBuffer; import org.agrona.concurrent.UnsafeBuffer; import io.aklivity.zilla.runtime.engine.EngineContext; import io.aklivity.zilla.runtime.engine.binding.function.MessageConsumer; -import io.aklivity.zilla.runtime.guard.jwt.internal.types.event.JwtEventFW; +import io.aklivity.zilla.runtime.guard.jwt.internal.types.event.EventFW; +import io.aklivity.zilla.runtime.guard.jwt.internal.types.event.JwtEventExFW; public class JwtEventContext { private static final int EVENT_BUFFER_CAPACITY = 1024; - private final JwtEventFW.Builder jwtEventRW = new JwtEventFW.Builder(); - private final MutableDirectBuffer eventBuffer = new UnsafeBuffer(ByteBuffer.allocate(EVENT_BUFFER_CAPACITY)); + private final AtomicBuffer eventBuffer = new UnsafeBuffer(ByteBuffer.allocate(EVENT_BUFFER_CAPACITY)); + private final AtomicBuffer extensionBuffer = new UnsafeBuffer(ByteBuffer.allocate(EVENT_BUFFER_CAPACITY)); + private final EventFW.Builder eventRW = new EventFW.Builder(); + private final JwtEventExFW.Builder jwtEventExRW = new JwtEventExFW.Builder(); private final int jwtTypeId; private final MessageConsumer eventWriter; private final Clock clock; @@ -47,15 +52,20 @@ public void authorizationFailed( long bindingId, String identity) { - JwtEventFW event = jwtEventRW - .wrap(eventBuffer, 0, eventBuffer.capacity()) + JwtEventExFW extension = jwtEventExRW + .wrap(extensionBuffer, 0, extensionBuffer.capacity()) .authorizationFailed(e -> e - .timestamp(clock.millis()) - .traceId(traceId) - .namespacedId(bindingId) + .typeId(AUTHORIZATION_FAILED.value()) .identity(identity) ) .build(); + EventFW event = eventRW + .wrap(eventBuffer, 0, eventBuffer.capacity()) + .timestamp(clock.millis()) + .traceId(traceId) + .namespacedId(bindingId) + .extension(extension.buffer(), extension.offset(), extension.limit()) + .build(); eventWriter.accept(jwtTypeId, event.buffer(), event.offset(), event.limit()); } } diff --git a/runtime/guard-jwt/src/main/java/io/aklivity/zilla/runtime/guard/jwt/internal/JwtEventFormatter.java b/runtime/guard-jwt/src/main/java/io/aklivity/zilla/runtime/guard/jwt/internal/JwtEventFormatter.java new file mode 100644 index 0000000000..36282d3a48 --- /dev/null +++ b/runtime/guard-jwt/src/main/java/io/aklivity/zilla/runtime/guard/jwt/internal/JwtEventFormatter.java @@ -0,0 +1,65 @@ +/* + * Copyright 2021-2023 Aklivity Inc + * + * Licensed under the Aklivity Community License (the "License"); you may not use + * this file except in compliance with the License. You may obtain a copy of the + * License at + * + * https://www.aklivity.io/aklivity-community-license/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package io.aklivity.zilla.runtime.guard.jwt.internal; + +import org.agrona.DirectBuffer; + +import io.aklivity.zilla.runtime.engine.Configuration; +import io.aklivity.zilla.runtime.engine.event.EventFormatterSpi; +import io.aklivity.zilla.runtime.guard.jwt.internal.types.StringFW; +import io.aklivity.zilla.runtime.guard.jwt.internal.types.event.EventFW; +import io.aklivity.zilla.runtime.guard.jwt.internal.types.event.JwtAuthorizationFailedExFW; +import io.aklivity.zilla.runtime.guard.jwt.internal.types.event.JwtEventExFW; + +public final class JwtEventFormatter implements EventFormatterSpi +{ + private static final String AUTHORIZATION_FAILED_FORMAT = "AUTHORIZATION_FAILED %s"; + + private final EventFW eventRO = new EventFW(); + private final JwtEventExFW jwtEventExRO = new JwtEventExFW(); + + JwtEventFormatter( + Configuration config) + { + } + + public String format( + DirectBuffer buffer, + int index, + int length) + { + final EventFW event = eventRO.wrap(buffer, index, index + length); + final JwtEventExFW extension = jwtEventExRO + .wrap(event.extension().buffer(), event.extension().offset(), event.extension().limit()); + String result = null; + switch (extension.kind()) + { + case AUTHORIZATION_FAILED: + { + JwtAuthorizationFailedExFW ex = extension.authorizationFailed(); + result = String.format(AUTHORIZATION_FAILED_FORMAT, identity(ex.identity())); + break; + } + } + return result; + } + + private static String identity( + StringFW identity) + { + int length = identity.length(); + return length <= 0 ? "-" : identity.asString(); + } +} diff --git a/runtime/guard-jwt/src/main/java/io/aklivity/zilla/runtime/guard/jwt/internal/JwtEventFormatterFactory.java b/runtime/guard-jwt/src/main/java/io/aklivity/zilla/runtime/guard/jwt/internal/JwtEventFormatterFactory.java new file mode 100644 index 0000000000..264f316173 --- /dev/null +++ b/runtime/guard-jwt/src/main/java/io/aklivity/zilla/runtime/guard/jwt/internal/JwtEventFormatterFactory.java @@ -0,0 +1,34 @@ +/* + * Copyright 2021-2023 Aklivity Inc + * + * Licensed under the Aklivity Community License (the "License"); you may not use + * this file except in compliance with the License. You may obtain a copy of the + * License at + * + * https://www.aklivity.io/aklivity-community-license/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package io.aklivity.zilla.runtime.guard.jwt.internal; + +import io.aklivity.zilla.runtime.engine.Configuration; +import io.aklivity.zilla.runtime.engine.event.EventFormatterFactorySpi; + +public final class JwtEventFormatterFactory implements EventFormatterFactorySpi +{ + @Override + public JwtEventFormatter create( + Configuration config) + { + return new JwtEventFormatter(config); + } + + @Override + public String type() + { + return JwtGuard.NAME; + } +} diff --git a/runtime/guard-jwt/src/main/moditect/module-info.java b/runtime/guard-jwt/src/main/moditect/module-info.java index 0d9410c4d4..e49b3bc5cf 100644 --- a/runtime/guard-jwt/src/main/moditect/module-info.java +++ b/runtime/guard-jwt/src/main/moditect/module-info.java @@ -24,4 +24,7 @@ provides io.aklivity.zilla.runtime.engine.config.OptionsConfigAdapterSpi with io.aklivity.zilla.runtime.guard.jwt.internal.config.JwtOptionsConfigAdapter; + + provides io.aklivity.zilla.runtime.engine.event.EventFormatterFactorySpi + with io.aklivity.zilla.runtime.guard.jwt.internal.JwtEventFormatterFactory; } diff --git a/runtime/guard-jwt/src/main/resources/META-INF/services/io.aklivity.zilla.runtime.engine.event.EventFormatterFactorySpi b/runtime/guard-jwt/src/main/resources/META-INF/services/io.aklivity.zilla.runtime.engine.event.EventFormatterFactorySpi new file mode 100644 index 0000000000..0ff19451b8 --- /dev/null +++ b/runtime/guard-jwt/src/main/resources/META-INF/services/io.aklivity.zilla.runtime.engine.event.EventFormatterFactorySpi @@ -0,0 +1 @@ +io.aklivity.zilla.runtime.guard.jwt.internal.JwtEventFormatterFactory diff --git a/runtime/guard-jwt/src/test/java/io/aklivity/zilla/runtime/guard/jwt/internal/EventIT.java b/runtime/guard-jwt/src/test/java/io/aklivity/zilla/runtime/guard/jwt/internal/EventIT.java new file mode 100644 index 0000000000..d6dc34cf9c --- /dev/null +++ b/runtime/guard-jwt/src/test/java/io/aklivity/zilla/runtime/guard/jwt/internal/EventIT.java @@ -0,0 +1,59 @@ +/* + * Copyright 2021-2023 Aklivity Inc + * + * Licensed under the Aklivity Community License (the "License"); you may not use + * this file except in compliance with the License. You may obtain a copy of the + * License at + * + * https://www.aklivity.io/aklivity-community-license/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package io.aklivity.zilla.runtime.guard.jwt.internal; + +import static java.util.concurrent.TimeUnit.SECONDS; +import static org.junit.rules.RuleChain.outerRule; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.DisableOnDebug; +import org.junit.rules.TestRule; +import org.junit.rules.Timeout; +import org.kaazing.k3po.junit.annotation.Specification; +import org.kaazing.k3po.junit.rules.K3poRule; + +import io.aklivity.zilla.runtime.engine.test.EngineRule; +import io.aklivity.zilla.runtime.engine.test.annotation.Configuration; + +public class EventIT +{ + private final K3poRule k3po = new K3poRule() + .addScriptRoot("net", "io/aklivity/zilla/specs/engine/streams/network") + .addScriptRoot("app", "io/aklivity/zilla/specs/engine/streams/application"); + + private final TestRule timeout = new DisableOnDebug(new Timeout(10, SECONDS)); + + private final EngineRule engine = new EngineRule() + .directory("target/zilla-itests") + .countersBufferCapacity(4096) + .configurationRoot("io/aklivity/zilla/specs/guard/jwt/config") + .external("app0") + .clean(); + + @Rule + public final TestRule chain = outerRule(engine).around(k3po).around(timeout); + + @Test + @Configuration("event.yaml") + @Specification({ + "${net}/event/client", + "${app}/event/server" + }) + public void shouldLogEvents() throws Exception + { + k3po.finish(); + } +} diff --git a/specs/binding-http.spec/src/main/resources/META-INF/zilla/http.idl b/specs/binding-http.spec/src/main/resources/META-INF/zilla/http.idl index 5bffe232f1..ee3d167cfc 100644 --- a/specs/binding-http.spec/src/main/resources/META-INF/zilla/http.idl +++ b/specs/binding-http.spec/src/main/resources/META-INF/zilla/http.idl @@ -57,7 +57,7 @@ scope http REQUEST_ACCEPTED (1) } - struct HttpRequestAccepted extends core::event::Event + struct HttpRequestAcceptedEx extends core::stream::Extension { string8 identity; string8 scheme; @@ -66,9 +66,9 @@ scope http string16 path; } - union HttpEvent switch (HttpEventType) + union HttpEventEx switch (HttpEventType) { - case REQUEST_ACCEPTED: HttpRequestAccepted requestAccepted; + case REQUEST_ACCEPTED: HttpRequestAcceptedEx requestAccepted; } } } diff --git a/specs/binding-http.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/config/v1.1/server.event.yaml b/specs/binding-http.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/config/v1.1/server.event.yaml new file mode 100644 index 0000000000..7f3236d01b --- /dev/null +++ b/specs/binding-http.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/config/v1.1/server.event.yaml @@ -0,0 +1,38 @@ +# +# Copyright 2021-2023 Aklivity Inc. +# +# Aklivity licenses this file to you under the Apache License, +# version 2.0 (the "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# + +--- +name: test +telemetry: + exporters: + exporter0: + type: test + options: + events: + - qname: test.net0 + message: REQUEST_ACCEPTED - http GET localhost:8080 / +bindings: + net0: + type: http + kind: server + options: + versions: + - http/1.1 + routes: + - exit: app0 + when: + - headers: + :authority: localhost:8080 diff --git a/specs/binding-http.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/config/v2/server.event.yaml b/specs/binding-http.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/config/v2/server.event.yaml new file mode 100644 index 0000000000..8ee2f34140 --- /dev/null +++ b/specs/binding-http.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/config/v2/server.event.yaml @@ -0,0 +1,38 @@ +# +# Copyright 2021-2023 Aklivity Inc. +# +# Aklivity licenses this file to you under the Apache License, +# version 2.0 (the "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# + +--- +name: test +telemetry: + exporters: + exporter0: + type: test + options: + events: + - qname: test.net0 + message: REQUEST_ACCEPTED - http GET localhost:8080 / +bindings: + net0: + type: http + kind: server + options: + versions: + - h2 + routes: + - exit: app0 + when: + - headers: + :authority: localhost:8080 diff --git a/specs/binding-kafka.spec/src/main/resources/META-INF/zilla/kafka.idl b/specs/binding-kafka.spec/src/main/resources/META-INF/zilla/kafka.idl index 5c66e319b4..0377305825 100644 --- a/specs/binding-kafka.spec/src/main/resources/META-INF/zilla/kafka.idl +++ b/specs/binding-kafka.spec/src/main/resources/META-INF/zilla/kafka.idl @@ -542,16 +542,21 @@ scope kafka API_VERSION_REJECTED (2) } - struct KafkaApiVersionRejected extends core::event::Event + struct KafkaAuthorizationFailedEx extends core::stream::Extension + { + string8 identity; + } + + struct KafkaApiVersionRejectedEx extends core::stream::Extension { int32 apiKey; int32 apiVersion; } - union KafkaEvent switch (KafkaEventType) + union KafkaEventEx switch (KafkaEventType) { - case AUTHORIZATION_FAILED: core::event::Event authorizationFailed; - case API_VERSION_REJECTED: KafkaApiVersionRejected apiVersionRejected; + case AUTHORIZATION_FAILED: KafkaAuthorizationFailedEx authorizationFailed; + case API_VERSION_REJECTED: KafkaApiVersionRejectedEx apiVersionRejected; } } } diff --git a/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/config/client.event.yaml b/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/config/client.event.yaml new file mode 100644 index 0000000000..5b2129098a --- /dev/null +++ b/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/config/client.event.yaml @@ -0,0 +1,31 @@ +# +# Copyright 2021-2023 Aklivity Inc. +# +# Aklivity licenses this file to you under the Apache License, +# version 2.0 (the "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# + +--- +name: test +telemetry: + exporters: + exporter0: + type: test + options: + events: + - qname: test.app0 + message: API_VERSION_REJECTED 32 0 +bindings: + app0: + type: kafka + kind: client + exit: net0 diff --git a/specs/binding-tcp.spec/src/main/resources/META-INF/zilla/tcp.idl b/specs/binding-tcp.spec/src/main/resources/META-INF/zilla/tcp.idl index a796c117f5..13dcdfe173 100644 --- a/specs/binding-tcp.spec/src/main/resources/META-INF/zilla/tcp.idl +++ b/specs/binding-tcp.spec/src/main/resources/META-INF/zilla/tcp.idl @@ -22,14 +22,14 @@ scope tcp DNS_FAILED (1) } - struct TcpDnsFailed extends core::event::Event + struct TcpDnsFailedEx extends core::stream::Extension { string16 address; } - union TcpEvent switch (TcpEventType) + union TcpEventEx switch (TcpEventType) { - case DNS_FAILED: TcpDnsFailed dnsFailed; + case DNS_FAILED: TcpDnsFailedEx dnsFailed; } } } diff --git a/specs/binding-tcp.spec/src/main/scripts/io/aklivity/zilla/specs/binding/tcp/config/client.event.yaml b/specs/binding-tcp.spec/src/main/scripts/io/aklivity/zilla/specs/binding/tcp/config/client.event.yaml new file mode 100644 index 0000000000..9144628d29 --- /dev/null +++ b/specs/binding-tcp.spec/src/main/scripts/io/aklivity/zilla/specs/binding/tcp/config/client.event.yaml @@ -0,0 +1,33 @@ +# +# Copyright 2021-2023 Aklivity Inc. +# +# Aklivity licenses this file to you under the Apache License, +# version 2.0 (the "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# + +--- +name: test +telemetry: + exporters: + exporter0: + type: test + options: + events: + - qname: test.app0 + message: DNS_FAILED localhost +bindings: + app0: + type: tcp + kind: client + options: + host: localhost + port: 8080 diff --git a/specs/binding-tls.spec/src/main/resources/META-INF/zilla/tls.idl b/specs/binding-tls.spec/src/main/resources/META-INF/zilla/tls.idl index c81e96e2c7..baa53655f6 100644 --- a/specs/binding-tls.spec/src/main/resources/META-INF/zilla/tls.idl +++ b/specs/binding-tls.spec/src/main/resources/META-INF/zilla/tls.idl @@ -26,13 +26,13 @@ scope tls TLS_HANDSHAKE_FAILED (5) } - union TlsEvent switch (TlsEventType) + union TlsEventEx switch (TlsEventType) { - case TLS_FAILED: core::event::Event tlsFailed; - case TLS_PROTOCOL_REJECTED: core::event::Event tlsProtocolRejected; - case TLS_KEY_REJECTED: core::event::Event tlsKeyRejected; - case TLS_PEER_NOT_VERIFIED: core::event::Event tlsPeerNotVerified; - case TLS_HANDSHAKE_FAILED: core::event::Event tlsHandshakeFailed; + case TLS_FAILED: core::stream::Extension tlsFailed; + case TLS_PROTOCOL_REJECTED: core::stream::Extension tlsProtocolRejected; + case TLS_KEY_REJECTED: core::stream::Extension tlsKeyRejected; + case TLS_PEER_NOT_VERIFIED: core::stream::Extension tlsPeerNotVerified; + case TLS_HANDSHAKE_FAILED: core::stream::Extension tlsHandshakeFailed; } } } diff --git a/specs/binding-tls.spec/src/main/scripts/io/aklivity/zilla/specs/binding/tls/config/client.event.yaml b/specs/binding-tls.spec/src/main/scripts/io/aklivity/zilla/specs/binding/tls/config/client.event.yaml new file mode 100644 index 0000000000..82acb65425 --- /dev/null +++ b/specs/binding-tls.spec/src/main/scripts/io/aklivity/zilla/specs/binding/tls/config/client.event.yaml @@ -0,0 +1,43 @@ +# +# Copyright 2021-2023 Aklivity Inc. +# +# Aklivity licenses this file to you under the Apache License, +# version 2.0 (the "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# + +--- +name: test +telemetry: + exporters: + exporter0: + type: test + options: + events: + - qname: test.app0 + message: HANDSHAKE_FAILED +vaults: + client: + type: filesystem + options: + trust: + store: stores/client/trust + type: pkcs12 + password: generated +bindings: + app0: + type: tls + kind: client + vault: client + options: + trust: + - serverca + exit: net0 diff --git a/specs/binding-tls.spec/src/main/scripts/io/aklivity/zilla/specs/binding/tls/config/server.event.handshake.failed.yaml b/specs/binding-tls.spec/src/main/scripts/io/aklivity/zilla/specs/binding/tls/config/server.event.handshake.failed.yaml new file mode 100644 index 0000000000..ddc6fd50a3 --- /dev/null +++ b/specs/binding-tls.spec/src/main/scripts/io/aklivity/zilla/specs/binding/tls/config/server.event.handshake.failed.yaml @@ -0,0 +1,43 @@ +# +# Copyright 2021-2023 Aklivity Inc. +# +# Aklivity licenses this file to you under the Apache License, +# version 2.0 (the "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# + +--- +name: test +telemetry: + exporters: + exporter0: + type: test + options: + events: + - qname: test.net0 + message: HANDSHAKE_FAILED +vaults: + server: + type: filesystem + options: + keys: + store: stores/server/keys + type: pkcs12 + password: generated +bindings: + net0: + type: tls + kind: server + vault: server + options: + keys: + - localhost + exit: app0 diff --git a/specs/binding-tls.spec/src/main/scripts/io/aklivity/zilla/specs/binding/tls/config/server.event.tls.failed.yaml b/specs/binding-tls.spec/src/main/scripts/io/aklivity/zilla/specs/binding/tls/config/server.event.tls.failed.yaml new file mode 100644 index 0000000000..3057400b82 --- /dev/null +++ b/specs/binding-tls.spec/src/main/scripts/io/aklivity/zilla/specs/binding/tls/config/server.event.tls.failed.yaml @@ -0,0 +1,43 @@ +# +# Copyright 2021-2023 Aklivity Inc. +# +# Aklivity licenses this file to you under the Apache License, +# version 2.0 (the "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# + +--- +name: test +telemetry: + exporters: + exporter0: + type: test + options: + events: + - qname: test.net0 + message: TLS_FAILED +vaults: + server: + type: filesystem + options: + keys: + store: stores/server/keys + type: pkcs12 + password: generated +bindings: + net0: + type: tls + kind: server + vault: server + options: + keys: + - localhost + exit: app0 diff --git a/specs/engine.spec/src/main/resources/META-INF/zilla/core.idl b/specs/engine.spec/src/main/resources/META-INF/zilla/core.idl index 05dfc800aa..e64e934b69 100644 --- a/specs/engine.spec/src/main/resources/META-INF/zilla/core.idl +++ b/specs/engine.spec/src/main/resources/META-INF/zilla/core.idl @@ -108,6 +108,7 @@ scope core int64 timestamp; int64 traceId; int64 namespacedId; + octets extension; } } } diff --git a/specs/engine.spec/src/main/scripts/io/aklivity/zilla/specs/engine/config/server.event.yaml b/specs/engine.spec/src/main/scripts/io/aklivity/zilla/specs/engine/config/server.event.yaml new file mode 100644 index 0000000000..1ff1010393 --- /dev/null +++ b/specs/engine.spec/src/main/scripts/io/aklivity/zilla/specs/engine/config/server.event.yaml @@ -0,0 +1,35 @@ +# +# Copyright 2021-2023 Aklivity Inc. +# +# Aklivity licenses this file to you under the Apache License, +# version 2.0 (the "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# + +--- +name: test +telemetry: + exporters: + exporter0: + type: test + options: + events: + - qname: test.net0 + message: test event message +bindings: + net0: + type: test + kind: server + options: + events: + - timestamp: 42 + message: test event message + exit: app0 diff --git a/specs/engine.spec/src/main/scripts/io/aklivity/zilla/specs/engine/schema/binding/test.schema.patch.json b/specs/engine.spec/src/main/scripts/io/aklivity/zilla/specs/engine/schema/binding/test.schema.patch.json index 069578e870..e5166b771e 100644 --- a/specs/engine.spec/src/main/scripts/io/aklivity/zilla/specs/engine/schema/binding/test.schema.patch.json +++ b/specs/engine.spec/src/main/scripts/io/aklivity/zilla/specs/engine/schema/binding/test.schema.patch.json @@ -70,6 +70,55 @@ } } ] + }, + "catalogs": + { + "type": "array", + "items": + { + "type": "string" + } + }, + "authorization": + { + "type": "object", + "properties": + { + "type": "object", + "patternProperties": + { + "^[a-zA-Z]+[a-zA-Z0-9\\._\\-]*$": + { + "type": "object", + "properties": + { + "credentials": + { + "type": "string" + } + } + } + } + } + }, + "events": + { + "type": "array", + "items": + { + "type": "object", + "properties": + { + "timestamp": + { + "type": "integer" + }, + "message": + { + "type": "string" + } + } + } } }, "additionalProperties": false diff --git a/specs/engine.spec/src/main/scripts/io/aklivity/zilla/specs/engine/schema/exporter/test.schema.patch.json b/specs/engine.spec/src/main/scripts/io/aklivity/zilla/specs/engine/schema/exporter/test.schema.patch.json index 44e3271eda..0f6644dafe 100644 --- a/specs/engine.spec/src/main/scripts/io/aklivity/zilla/specs/engine/schema/exporter/test.schema.patch.json +++ b/specs/engine.spec/src/main/scripts/io/aklivity/zilla/specs/engine/schema/exporter/test.schema.patch.json @@ -26,8 +26,35 @@ "type": { "const": "test" + }, + "options": + { + "type": "object", + "properties": + { + "events": + { + "type": "array", + "items": + { + "type": "object", + "properties": + { + "timestamp": + { + "type": "integer" + }, + "message": + { + "type": "string" + } + } + } + } + } } - } + }, + "additionalProperties": false } } } diff --git a/specs/engine.spec/src/main/scripts/io/aklivity/zilla/specs/engine/streams/application/event/client.rpt b/specs/engine.spec/src/main/scripts/io/aklivity/zilla/specs/engine/streams/application/event/client.rpt new file mode 100644 index 0000000000..500aa3c174 --- /dev/null +++ b/specs/engine.spec/src/main/scripts/io/aklivity/zilla/specs/engine/streams/application/event/client.rpt @@ -0,0 +1,20 @@ +# +# Copyright 2021-2023 Aklivity Inc. +# +# Aklivity licenses this file to you under the Apache License, +# version 2.0 (the "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# + +connect "zilla://streams/app0" + option zilla:window 8192 + +connected diff --git a/specs/engine.spec/src/main/scripts/io/aklivity/zilla/specs/engine/streams/application/event/server.rpt b/specs/engine.spec/src/main/scripts/io/aklivity/zilla/specs/engine/streams/application/event/server.rpt new file mode 100644 index 0000000000..e50a264e14 --- /dev/null +++ b/specs/engine.spec/src/main/scripts/io/aklivity/zilla/specs/engine/streams/application/event/server.rpt @@ -0,0 +1,21 @@ +# +# Copyright 2021-2023 Aklivity Inc. +# +# Aklivity licenses this file to you under the Apache License, +# version 2.0 (the "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# + +accept "zilla://streams/app0" + option zilla:window 8192 + +accepted +connected diff --git a/specs/engine.spec/src/main/scripts/io/aklivity/zilla/specs/engine/streams/network/event/client.rpt b/specs/engine.spec/src/main/scripts/io/aklivity/zilla/specs/engine/streams/network/event/client.rpt new file mode 100644 index 0000000000..73deb25750 --- /dev/null +++ b/specs/engine.spec/src/main/scripts/io/aklivity/zilla/specs/engine/streams/network/event/client.rpt @@ -0,0 +1,20 @@ +# +# Copyright 2021-2023 Aklivity Inc. +# +# Aklivity licenses this file to you under the Apache License, +# version 2.0 (the "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# + +connect "zilla://streams/net0" + option zilla:window 8192 + +connected diff --git a/specs/engine.spec/src/main/scripts/io/aklivity/zilla/specs/engine/streams/network/event/server.rpt b/specs/engine.spec/src/main/scripts/io/aklivity/zilla/specs/engine/streams/network/event/server.rpt new file mode 100644 index 0000000000..f48bc644a1 --- /dev/null +++ b/specs/engine.spec/src/main/scripts/io/aklivity/zilla/specs/engine/streams/network/event/server.rpt @@ -0,0 +1,21 @@ +# +# Copyright 2021-2023 Aklivity Inc. +# +# Aklivity licenses this file to you under the Apache License, +# version 2.0 (the "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# + +accept "zilla://streams/net0" + option zilla:window 8192 + +accepted +connected diff --git a/specs/engine.spec/src/test/java/io/aklivity/zilla/specs/engine/streams/ApplicationIT.java b/specs/engine.spec/src/test/java/io/aklivity/zilla/specs/engine/streams/ApplicationIT.java index 65c49ae5a6..e079e617ce 100644 --- a/specs/engine.spec/src/test/java/io/aklivity/zilla/specs/engine/streams/ApplicationIT.java +++ b/specs/engine.spec/src/test/java/io/aklivity/zilla/specs/engine/streams/ApplicationIT.java @@ -128,4 +128,14 @@ public void shouldNotReconfigureWhen500Returned() throws Exception { k3po.finish(); } + + @Test + @Specification({ + "${app}/event/server", + "${app}/event/client", + }) + public void shouldConnect() throws Exception + { + k3po.finish(); + } } diff --git a/specs/engine.spec/src/test/java/io/aklivity/zilla/specs/engine/streams/NetworkIT.java b/specs/engine.spec/src/test/java/io/aklivity/zilla/specs/engine/streams/NetworkIT.java index ff59b85799..4837938048 100644 --- a/specs/engine.spec/src/test/java/io/aklivity/zilla/specs/engine/streams/NetworkIT.java +++ b/specs/engine.spec/src/test/java/io/aklivity/zilla/specs/engine/streams/NetworkIT.java @@ -128,4 +128,14 @@ public void shouldNotReconfigureWhen500Returned() throws Exception { k3po.finish(); } + + @Test + @Specification({ + "${net}/event/server", + "${net}/event/client" + }) + public void shouldConnect() throws Exception + { + k3po.finish(); + } } diff --git a/specs/guard-jwt.spec/src/main/resources/META-INF/zilla/jwt.idl b/specs/guard-jwt.spec/src/main/resources/META-INF/zilla/jwt.idl index 997f9bf859..937f7f2cf7 100644 --- a/specs/guard-jwt.spec/src/main/resources/META-INF/zilla/jwt.idl +++ b/specs/guard-jwt.spec/src/main/resources/META-INF/zilla/jwt.idl @@ -21,14 +21,14 @@ scope jwt AUTHORIZATION_FAILED (1) } - struct JwtAuthorizationFailed extends core::event::Event + struct JwtAuthorizationFailedEx extends core::stream::Extension { string8 identity; } - union JwtEvent switch (JwtEventType) + union JwtEventEx switch (JwtEventType) { - case AUTHORIZATION_FAILED: JwtAuthorizationFailed authorizationFailed; + case AUTHORIZATION_FAILED: JwtAuthorizationFailedEx authorizationFailed; } } } diff --git a/specs/guard-jwt.spec/src/main/scripts/io/aklivity/zilla/specs/guard/jwt/config/event.yaml b/specs/guard-jwt.spec/src/main/scripts/io/aklivity/zilla/specs/guard/jwt/config/event.yaml new file mode 100644 index 0000000000..eed8bb3001 --- /dev/null +++ b/specs/guard-jwt.spec/src/main/scripts/io/aklivity/zilla/specs/guard/jwt/config/event.yaml @@ -0,0 +1,46 @@ +# +# Copyright 2021-2023 Aklivity Inc +# +# Licensed under the Aklivity Community License (the "License"); you may not use +# this file except in compliance with the License. You may obtain a copy of the +# License at +# +# https://www.aklivity.io/aklivity-community-license/ +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. +# + +--- +name: test +telemetry: + exporters: + exporter0: + type: test + options: + events: + - qname: test.net0 + message: AUTHORIZATION_FAILED user +guards: + jwt0: + type: jwt + options: + issuer: https://auth.example.com + audience: https://api.example.com + keys: + - kty: RSA + n: qqEu50hX+43Bx4W1UYWnAVKwFm+vDbP0kuIOSLVNa+HKQdHTf+3Sei5UCnkskn796izA29D0DdCy3ET9oaKRHIJyKbqFl0rv6f516QzOoXKC6N01sXBHBE/ovs0wwDvlaW+gFGPgkzdcfUlyrWLDnLV7LcuQymhTND2uH0oR3wJnNENN/OFgM1KGPPDOe19YsIKdLqARgxrhZVsh06OurEviZTXOBFI5r+yac7haDwOQhLHXNv+Y9MNvxs5QLWPFIM3bNUWfYrJnLrs4hGJS+y/KDM9Si+HL30QAFXy4YNO33J8DHjZ7ddG5n8/FqplOKvRtUgjcKWlxoGY4VdVaDQ== + e: AQAB + alg: RS256 + kid: example +bindings: + net0: + type: test + kind: server + options: + authorization: + jwt0: + credentials: eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6ImV4YW1wbGUifQ.eyJhdWQiOiJodHRwczovL2FwaS5leGFtcGxlLmNvbSIsImV4cCI6MTcwODk0MDQ0MCwiaXNzIjoiaHR0cHM6Ly9hdXRoLmV4YW1wbGUuY29tIiwic3ViIjoidXNlciJ9.KwZt_rDTDEOQ33URwZ8Gd1WqQjAIJESbt5Et309Yz7AJm1wWWyFhWm7AV6lt1rkX-eD-jVh0wHAsy7L4kdzBOErCdwFcdaB4u2jFDGn_9IK28lCedxIYmYtI4qn6eY916IIqRpwZcqzw08OEljfYUKo4UeX7JPAtha0GQmfZY1-NNcncg06xw3xkKSZ1SnIh9MZM1FNH_5QPZPL4NHP7DRXtaMn2w6YpO7n695Sc_3LuSDlfDDMVIUWuEreOzOXem6jheGIbJ-eDKhIXXPrOz1NBAJmvizbugMR7m_bodiEzzqt5ttKDs1974alrR_sYP8OYmR_rCqXc5N3lp_SW3A + exit: app0