Skip to content

Commit

Permalink
Merge pull request kafka4beam#499 from spencerdcarlson/sdc/ex-doc
Browse files Browse the repository at this point in the history
Use ex_doc to generate docs
  • Loading branch information
zmstone authored May 9, 2022
2 parents 35b0dc0 + 0555503 commit 81fc7c7
Show file tree
Hide file tree
Showing 11 changed files with 360 additions and 88 deletions.
158 changes: 85 additions & 73 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,84 +8,96 @@ on:
- master

jobs:
lint:
runs-on: ubuntu-latest
name: Lint
steps:
- name: Checkout
uses: actions/checkout@v2
- name: OTP
uses: erlef/setup-beam@v1
with:
version-type: strict
otp-version: '24.1'
rebar3-version: '3.17.0'
- name: Cache Hex packages
id: cache-lint-hex
uses: actions/cache@v3
with:
path: ~/.cache/rebar3/hex/hexpm/packages
key: lint-hex-${{ hashFiles(format('{0}{1}', github.workspace, '/rebar.lock')) }}
restore-keys: lint-hex
- name: Lint
run: rebar3 lint
build:
runs-on: ubuntu-latest
name: OTP ${{matrix.otp}} / Kafka ${{matrix.kafka}}
strategy:
fail-fast: false
matrix:
otp:
- '24.1'
- '23.3.4.7'
- '22.3.4.21'
kafka:
- '2.4'
- '1.1'
- '0.11'
runs-on: ubuntu-20.04
otp: ['24.1', '23.3.4.7', '22.3.4.21']
kafka: ['2.4', '1.1', '0.11']
steps:

# Setup
- name: Checkout
uses: actions/checkout@v2
- name: Cache Hex packages
uses: actions/cache@v2
with:
path: ~/.cache/rebar3/hex/hexpm/packages
key: ${{ runner.os }}-hex-${{ hashFiles(format('{0}{1}', github.workspace, '/rebar.lock')) }}
restore-keys: |
${{ runner.os }}-hex-
- name: Cache Dialyzer PLTs
uses: actions/cache@v2
with:
path: ~/.cache/rebar3/rebar3_*_plt
key: ${{ runner.os }}-dialyzer-${{ hashFiles(format('{0}{1}', github.workspace, '/rebar.config')) }}
restore-keys: |
${{ runner.os }}-dialyzer-
# Install Erlang
- uses: erlef/setup-beam@v1
with:
version-type: strict
otp-version: ${{matrix.otp}}
rebar3-version: '3.17.0'

# Inspect rebar3 version
- name: Rebar version
run: rebar3 --version

# Compile
- name: Compile
run: rebar3 do compile,lint,edoc
- name: Make brod_cli script
run: rebar3 as brod_cli escriptize

# Tests
- name: Run tests
run: |
- name: Checkout
uses: actions/checkout@v2
- name: Cache Hex packages
uses: actions/cache@v3
with:
path: ~/.cache/rebar3/hex/hexpm/packages
key: ${{ runner.os }}-hex-${{ hashFiles(format('{0}{1}', github.workspace, '/rebar.lock')) }}
restore-keys: ${{ runner.os }}-hex-
- name: Cache Dialyzer PLTs
uses: actions/cache@v3
with:
path: ~/.cache/rebar3/rebar3_*_plt
key: ${{ runner.os }}-dialyzer-${{ hashFiles(format('{0}{1}', github.workspace, '/rebar.config')) }}
restore-keys: ${{ runner.os }}-dialyzer-
- name: Install Erlang
uses: erlef/setup-beam@v1
with:
version-type: strict
otp-version: ${{matrix.otp}}
rebar3-version: '3.17.0'
- name: Rebar version
run: rebar3 --version
- name: Compile
run: rebar3 do compile
- name: Make brod_cli script
run: rebar3 as brod_cli escriptize
- name: Run tests
run: |
export KAFKA_VERSION=${{ matrix.kafka }}
echo "Running Kafka ${KAFKA_VERSION}"
scripts/setup-test-env.sh && rebar3 do ct,eunit
- name: Store test logs
uses: actions/upload-artifact@v1
if: always()
with:
name: ct-logs
path: _build/test/logs

# Cover reports
- name: Create Cover Reports
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: rebar3 do cover,coveralls send

# Checks
- name: Checks
run: rebar3 do dialyzer,xref

# Documentation
- name: Documentation
run: rebar3 do edoc
- name: Publish documentation
uses: actions/upload-artifact@v1
with:
name: edoc
path: doc
- name: Store test logs
uses: actions/upload-artifact@v1
if: always()
with:
name: ct-logs
path: _build/test/logs
- name: Create Cover Reports
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: rebar3 do cover,coveralls send
- name: Checks
run: rebar3 do dialyzer,xref
docs:
needs: build
runs-on: ubuntu-latest
name: Publish Documentation
steps:
- name: Checkout
uses: actions/checkout@v2
- name: OTP
uses: erlef/setup-beam@v1
with:
version-type: strict
otp-version: '24.1'
rebar3-version: '3.17.0'
- name: Build Documentation
run: rebar3 do hex build
- name: Publish documentation
uses: actions/upload-artifact@v1
with:
name: edoc
path: doc
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ clean:

hex-publish: clean
@rebar3 hex publish
@rebar3 hex docs
@rebar3 hex build

## tests that require kafka running at localhost
INTEGRATION_CTS = brod_cg_commits brod_client brod_compression brod_consumer brod_producer brod_group_subscriber brod_topic_subscriber brod
Expand Down
1 change: 1 addition & 0 deletions elvis.config
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
}
]
}
, {verbose, true}
]
}
].
Expand Down
102 changes: 102 additions & 0 deletions guides/examples/Authentication.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
# Authentication



## SASL/PLAIN

### Erlang

```erlang
[{brod,
[{clients
, [{kafka_client
, [ { endpoints, [{"localhost", 9092}] }
, { ssl, true}
, { sasl, {plain, "GFRW5BSQHKEH0TSG", "GrL3CNTkLhsvtBr8srGn0VilMpgDb4lPD"}}
]
}
]
}
]
}]
```

### Elixir

```elixir
import Config

config :brod,
clients: [
kafka_client: [
endpoints: [
localhost: 9092
],
ssl: true,
sasl: {
:plain,
System.get_env("KAFKA_USERNAME"),
System.get_env("KAFKA_PASSWORD")
}
]
]
```

## SSL Certificate Validation
Erlang's default configuration for SSL is [verify_none](https://github.com/erlang/otp/blob/OTP-24.3.4/lib/ssl/src/ssl_internal.hrl#L120-L218)
which means that certificates are accepted but not validated. brod passes SSL options to the [kafka_protocol](https://hex.pm/packages/kafka_protocol) library
where they are used to create the [SSL connection](https://github.com/kafka4beam/kafka_protocol/blob/4.0.3/src/kpro_connection.erl#L305).

For more info see the Erlang Ecosystem Foundation's [server certificate verification](https://erlef.github.io/security-wg/secure_coding_and_deployment_hardening/ssl.html#server-certificate-verification) recommendations.

## Erlang
```erlang
[{brod,
[{clients
, [{kafka_client
, [ { endpoints, [{"localhost", 9092}] }
, { ssl, [ { verify, verify_peer }
, { cacertfile, "/etc/ssl/certs/ca-certificates.crt" }
, { depth, 3 }
, { customize_hostname_check,
[{match_fun, public_key:pkix_verify_hostname_match_fun(https)}]}
]}
, { sasl, {plain, "GFRW5BSQHKEH0TSG", "GrL3CNTkLhsvtBr8srGn0VilMpgDb4lPD"}}
]
}
]
}
]
}]
```

## Elixir
```elixir
import Config

config :brod,
clients: [
kafka_client: [
endpoints: [
localhost: 9092
],
ssl: [
verify: :verify_peer,
cacertfile: "/etc/ssl/certs/ca-certificates.crt",
depth: 3,
customize_hostname_check: [
match_fun: :public_key.pkix_verify_hostname_match_fun(:https)
],
],
sasl: {
:plain,
System.get_env("KAFKA_USERNAME"),
System.get_env("KAFKA_PASSWORD")
}
]
]
```

The examples above are using `/etc/ssl/certs/ca-certificates.crt` which is the certificate authority that comes
with [alpine](https://hub.docker.com/_/alpine) linux. You will need to provide a path to a valid certificate authority
certificate or use [certifi](https://hex.pm/packages/certifi)
68 changes: 68 additions & 0 deletions guides/examples/elixir/Consumer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# Consumer Example

Ensure `:brod` is added to your deps on `mix.exs`

```elixir
defp deps do
[
{:brod, "~> 3.10.0"}
]
end
```

## Consumer

Either the `brod_group_subscriber_v2` or `brod_group_subscriber` behaviours can be used
to consume messages. The key difference is that the v2 subscriber runs a worker for each
partition in a separate Erlang process, allowing parallel message processing.

Here is an example of callback module that implements the `brod_group_subscriber_v2` behaviour to consume messages.

```elixir
defmodule BrodSample.GroupSubscriberV2 do
@behaviour :brod_group_subscriber_v2

def child_spec(_arg) do
config = %{
client: :kafka_client,
group_id: "consumer_group_name",
topics: ["streaming.events"],
cb_module: __MODULE__,
consumer_config: [{:begin_offset, :earliest}],
init_data: [],
message_type: :message_set,
group_config: [
offset_commit_policy: :commit_to_kafka_v2,
offset_commit_interval_seconds: 5,
rejoin_delay_seconds: 60,
reconnect_cool_down_seconds: 60
]
}

%{
id: __MODULE__,
start: {brod_group_subscriber_v2, :start_link, [config]},
type: :worker,
restart: :temporary,
shutdown: 5000
}
end

@impl :brod_group_subscriber_v2
def init(_group_id, _init_data), do: {:ok, []}

@impl :brod_group_subscriber_v2
def handle_message(message, _state) do
IO.inspect(message, label: "message")
{:ok, :commit, []}
end
end
```

The example module implements `child_spec/1` so that our consumer can be started by a Supervisor. The restart policy is set to `:temporary`
because, in this case, if a message can not be processed, then there is no point in restarting. This might not always
be the case.

See `brod_group_subscriber_v2:start_link/1` for details on the configuration options.

See docs for more details about the required or optional callbacks.
Loading

0 comments on commit 81fc7c7

Please sign in to comment.