Publish RabbitMQ-Stream dashboard to grafana.com
Removed the Dockerfile and slimmed down the Makefile, all of this is now handled by https://github.com/rabbitmq/rabbitmq-server/blob/master/.github/workflows/oci.yaml cc @Zerpet @pjk25 More details here (including the steps used to publish to grafana.com): https://github.com/rabbitmq/release-engineering/issues/11#issuecomment-887627938 I don't want to hold up this PR, will invest in automating the steps described in the previous link another time. Time to 🚀 Signed-off-by: Gerhard Lazu <gerhard@lazu.co.uk>
This commit is contained in:
parent
2aeaf06bcd
commit
6f5c4118ea
|
@ -1,8 +0,0 @@
|
|||
.erlang.mk
|
||||
.git
|
||||
ebin
|
||||
logs
|
||||
prometheus
|
||||
src
|
||||
test
|
||||
tmp
|
|
@ -1,328 +0,0 @@
|
|||
# The official Canonical Ubuntu Bionic image is ideal from a security perspective,
|
||||
# especially for the enterprises that we, the RabbitMQ team, have to deal with
|
||||
FROM ubuntu:18.04
|
||||
|
||||
RUN set -eux; \
|
||||
apt-get update; \
|
||||
apt-get install -y --no-install-recommends \
|
||||
# grab gosu for easy step-down from root
|
||||
gosu \
|
||||
; \
|
||||
rm -rf /var/lib/apt/lists/*; \
|
||||
# verify that the "gosu" binary works
|
||||
gosu nobody true
|
||||
|
||||
# Default to a PGP keyserver that pgp-happy-eyeballs recognizes, but allow for substitutions locally
|
||||
ARG PGP_KEYSERVER=ha.pool.sks-keyservers.net
|
||||
# If you are building this image locally and are getting `gpg: keyserver receive failed: No data` errors,
|
||||
# run the build with a different PGP_KEYSERVER, e.g. docker build --tag rabbitmq:3.7 --build-arg PGP_KEYSERVER=pgpkeys.eu 3.7/ubuntu
|
||||
# For context, see https://github.com/docker-library/official-images/issues/4252
|
||||
|
||||
# Using the latest OpenSSL LTS release, with support until September 2023 - https://www.openssl.org/source/
|
||||
ENV OPENSSL_VERSION 1.1.1g
|
||||
ENV OPENSSL_SOURCE_SHA256="ddb04774f1e32f0c49751e21b67216ac87852ceb056b75209af2443400636d46"
|
||||
# https://www.openssl.org/community/omc.html
|
||||
ENV OPENSSL_PGP_KEY_IDS="0x8657ABB260F056B1E5190839D9C4D26D0E604491 0x5B2545DAB21995F4088CEFAA36CEE4DEB00CFE33 0xED230BEC4D4F2518B9D7DF41F0DB4D21C1D35231 0xC1F33DD8CE1D4CC613AF14DA9195C48241FBF7DD 0x7953AC1FBC3DC8B3B292393ED5E9E43F7DF9EE8C 0xE5E52560DD91C556DDBDA5D02064C53641C25E5D"
|
||||
|
||||
# Use the latest stable Erlang/OTP release - make find-latest-otp - https://github.com/erlang/otp/tags
|
||||
ARG OTP_VERSION
|
||||
ENV OTP_VERSION ${OTP_VERSION}
|
||||
# TODO add PGP checking when the feature will be added to Erlang/OTP's build system
|
||||
# http://erlang.org/pipermail/erlang-questions/2019-January/097067.html
|
||||
ARG OTP_SHA256
|
||||
ENV OTP_SOURCE_SHA256=${OTP_SHA256}
|
||||
|
||||
# Install dependencies required to build Erlang/OTP from source
|
||||
# http://erlang.org/doc/installation_guide/INSTALL.html
|
||||
# autoconf: Required to configure Erlang/OTP before compiling
|
||||
# dpkg-dev: Required to set up host & build type when compiling Erlang/OTP
|
||||
# gnupg: Required to verify OpenSSL artefacts
|
||||
# libncurses5-dev: Required for Erlang/OTP new shell & observer_cli - https://github.com/zhongwencool/observer_cli
|
||||
RUN set -eux; \
|
||||
\
|
||||
savedAptMark="$(apt-mark showmanual)"; \
|
||||
apt-get update; \
|
||||
apt-get install --yes --no-install-recommends \
|
||||
autoconf \
|
||||
ca-certificates \
|
||||
dpkg-dev \
|
||||
gcc \
|
||||
gnupg \
|
||||
libncurses5-dev \
|
||||
make \
|
||||
wget \
|
||||
; \
|
||||
rm -rf /var/lib/apt/lists/*; \
|
||||
\
|
||||
OPENSSL_SOURCE_URL="https://www.openssl.org/source/openssl-$OPENSSL_VERSION.tar.gz"; \
|
||||
OPENSSL_PATH="/usr/local/src/openssl-$OPENSSL_VERSION"; \
|
||||
OPENSSL_CONFIG_DIR=/usr/local/etc/ssl; \
|
||||
\
|
||||
# Required by the crypto & ssl Erlang/OTP applications
|
||||
wget --progress dot:giga --output-document "$OPENSSL_PATH.tar.gz.asc" "$OPENSSL_SOURCE_URL.asc"; \
|
||||
wget --progress dot:giga --output-document "$OPENSSL_PATH.tar.gz" "$OPENSSL_SOURCE_URL"; \
|
||||
export GNUPGHOME="$(mktemp -d)"; \
|
||||
for key in $OPENSSL_PGP_KEY_IDS; do \
|
||||
gpg --batch --keyserver "$PGP_KEYSERVER" --recv-keys "$key" || true; \
|
||||
done; \
|
||||
gpg --batch --verify "$OPENSSL_PATH.tar.gz.asc" "$OPENSSL_PATH.tar.gz"; \
|
||||
gpgconf --kill all; \
|
||||
rm -rf "$GNUPGHOME"; \
|
||||
echo "$OPENSSL_SOURCE_SHA256 *$OPENSSL_PATH.tar.gz" | sha256sum --check --strict -; \
|
||||
mkdir -p "$OPENSSL_PATH"; \
|
||||
tar --extract --file "$OPENSSL_PATH.tar.gz" --directory "$OPENSSL_PATH" --strip-components 1; \
|
||||
\
|
||||
# Configure OpenSSL for compilation
|
||||
cd "$OPENSSL_PATH"; \
|
||||
# OpenSSL's "config" script uses a lot of "uname"-based target detection...
|
||||
MACHINE="$(dpkg-architecture --query DEB_BUILD_GNU_CPU)" \
|
||||
RELEASE="4.x.y-z" \
|
||||
SYSTEM='Linux' \
|
||||
BUILD='???' \
|
||||
./config \
|
||||
--openssldir="$OPENSSL_CONFIG_DIR" \
|
||||
# add -rpath to avoid conflicts between our OpenSSL's "libssl.so" and the libssl package by making sure /usr/local/lib is searched first (but only for Erlang/OpenSSL to avoid issues with other tools using libssl; https://github.com/docker-library/rabbitmq/issues/364)
|
||||
-Wl,-rpath=/usr/local/lib \
|
||||
; \
|
||||
# Compile, install OpenSSL, verify that the command-line works & development headers are present
|
||||
make -j "$(getconf _NPROCESSORS_ONLN)"; \
|
||||
make install_sw install_ssldirs; \
|
||||
cd ..; \
|
||||
rm -rf "$OPENSSL_PATH"*; \
|
||||
ldconfig; \
|
||||
# use Debian's CA certificates
|
||||
rmdir "$OPENSSL_CONFIG_DIR/certs" "$OPENSSL_CONFIG_DIR/private"; \
|
||||
ln -sf /etc/ssl/certs /etc/ssl/private "$OPENSSL_CONFIG_DIR"; \
|
||||
# smoke test
|
||||
openssl version; \
|
||||
\
|
||||
OTP_SOURCE_URL="https://github.com/erlang/otp/archive/OTP-$OTP_VERSION.tar.gz"; \
|
||||
OTP_PATH="/usr/local/src/otp-$OTP_VERSION"; \
|
||||
\
|
||||
# Download, verify & extract OTP_SOURCE
|
||||
mkdir -p "$OTP_PATH"; \
|
||||
wget --progress dot:giga --output-document "$OTP_PATH.tar.gz" "$OTP_SOURCE_URL"; \
|
||||
echo "$OTP_SOURCE_SHA256 *$OTP_PATH.tar.gz" | sha256sum --check --strict -; \
|
||||
tar --extract --file "$OTP_PATH.tar.gz" --directory "$OTP_PATH" --strip-components 1; \
|
||||
\
|
||||
# Configure Erlang/OTP for compilation, disable unused features & applications
|
||||
# http://erlang.org/doc/applications.html
|
||||
# ERL_TOP is required for Erlang/OTP makefiles to find the absolute path for the installation
|
||||
cd "$OTP_PATH"; \
|
||||
export ERL_TOP="$OTP_PATH"; \
|
||||
./otp_build autoconf; \
|
||||
CFLAGS="$(dpkg-buildflags --get CFLAGS)"; export CFLAGS; \
|
||||
# add -rpath to avoid conflicts between our OpenSSL's "libssl.so" and the libssl package by making sure /usr/local/lib is searched first (but only for Erlang/OpenSSL to avoid issues with other tools using libssl; https://github.com/docker-library/rabbitmq/issues/364)
|
||||
export CFLAGS="$CFLAGS -Wl,-rpath=/usr/local/lib"; \
|
||||
hostArch="$(dpkg-architecture --query DEB_HOST_GNU_TYPE)"; \
|
||||
buildArch="$(dpkg-architecture --query DEB_BUILD_GNU_TYPE)"; \
|
||||
dpkgArch="$(dpkg --print-architecture)"; dpkgArch="${dpkgArch##*-}"; \
|
||||
./configure \
|
||||
--host="$hostArch" \
|
||||
--build="$buildArch" \
|
||||
--disable-dynamic-ssl-lib \
|
||||
--disable-hipe \
|
||||
--disable-sctp \
|
||||
--disable-silent-rules \
|
||||
--enable-clock-gettime \
|
||||
--enable-hybrid-heap \
|
||||
--enable-kernel-poll \
|
||||
--enable-shared-zlib \
|
||||
--enable-smp-support \
|
||||
--enable-threads \
|
||||
--with-microstate-accounting=extra \
|
||||
--without-common_test \
|
||||
--without-debugger \
|
||||
--without-dialyzer \
|
||||
--without-diameter \
|
||||
--without-edoc \
|
||||
--without-erl_docgen \
|
||||
--without-erl_interface \
|
||||
--without-et \
|
||||
--without-eunit \
|
||||
--without-ftp \
|
||||
--without-hipe \
|
||||
--without-jinterface \
|
||||
--without-megaco \
|
||||
--without-observer \
|
||||
--without-odbc \
|
||||
--without-reltool \
|
||||
--without-ssh \
|
||||
--without-tftp \
|
||||
--without-wx \
|
||||
; \
|
||||
# Compile & install Erlang/OTP
|
||||
make -j "$(getconf _NPROCESSORS_ONLN)" GEN_OPT_FLGS="-O2 -fno-strict-aliasing"; \
|
||||
make install; \
|
||||
cd ..; \
|
||||
rm -rf \
|
||||
"$OTP_PATH"* \
|
||||
/usr/local/lib/erlang/lib/*/examples \
|
||||
/usr/local/lib/erlang/lib/*/src \
|
||||
; \
|
||||
\
|
||||
# reset apt-mark's "manual" list so that "purge --auto-remove" will remove all build dependencies
|
||||
apt-mark auto '.*' > /dev/null; \
|
||||
[ -z "$savedAptMark" ] || apt-mark manual $savedAptMark; \
|
||||
find /usr/local -type f -executable -exec ldd '{}' ';' \
|
||||
| awk '/=>/ { print $(NF-1) }' \
|
||||
| sort -u \
|
||||
| xargs -r dpkg-query --search \
|
||||
| cut -d: -f1 \
|
||||
| sort -u \
|
||||
| xargs -r apt-mark manual \
|
||||
; \
|
||||
apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false; \
|
||||
\
|
||||
# Check that OpenSSL still works after purging build dependencies
|
||||
openssl version; \
|
||||
# Check that Erlang/OTP crypto & ssl were compiled against OpenSSL correctly
|
||||
erl -noshell -eval 'io:format("~p~n~n~p~n~n", [crypto:supports(), ssl:versions()]), init:stop().'
|
||||
|
||||
ENV RABBITMQ_DATA_DIR=/var/lib/rabbitmq
|
||||
# Create rabbitmq system user & group, fix permissions & allow root user to connect to the RabbitMQ Erlang VM
|
||||
RUN set -eux; \
|
||||
groupadd --gid 999 --system rabbitmq; \
|
||||
useradd --uid 999 --system --home-dir "$RABBITMQ_DATA_DIR" --gid rabbitmq rabbitmq; \
|
||||
mkdir -p "$RABBITMQ_DATA_DIR" /etc/rabbitmq /tmp/rabbitmq-ssl /var/log/rabbitmq; \
|
||||
chown -fR rabbitmq:rabbitmq "$RABBITMQ_DATA_DIR" /etc/rabbitmq /tmp/rabbitmq-ssl /var/log/rabbitmq; \
|
||||
chmod 777 "$RABBITMQ_DATA_DIR" /etc/rabbitmq /tmp/rabbitmq-ssl /var/log/rabbitmq; \
|
||||
ln -sf "$RABBITMQ_DATA_DIR/.erlang.cookie" /root/.erlang.cookie
|
||||
|
||||
# Use the latest alpha RabbitMQ 3.8 release - https://dl.bintray.com/rabbitmq/all-dev/rabbitmq-server/
|
||||
ARG RABBITMQ_VERSION
|
||||
ENV RABBITMQ_VERSION=${RABBITMQ_VERSION}
|
||||
ARG RABBITMQ_BUILD_NUMBER
|
||||
ENV RABBITMQ_BUILD_NUMBER=${RABBITMQ_BUILD_NUMBER}
|
||||
# https://www.rabbitmq.com/signatures.html#importing-gpg
|
||||
ENV RABBITMQ_PGP_KEY_ID="0x0A9AF2115F4687BD29803A206B73A36E6026DFCA"
|
||||
ENV RABBITMQ_HOME=/opt/rabbitmq
|
||||
|
||||
# Add RabbitMQ to PATH, send all logs to TTY
|
||||
ENV PATH=$RABBITMQ_HOME/sbin:$PATH \
|
||||
RABBITMQ_LOGS=- RABBITMQ_SASL_LOGS=-
|
||||
|
||||
# Install RabbitMQ
|
||||
RUN set -eux; \
|
||||
\
|
||||
savedAptMark="$(apt-mark showmanual)"; \
|
||||
apt-get update; \
|
||||
apt-get install --yes --no-install-recommends \
|
||||
ca-certificates \
|
||||
gnupg \
|
||||
wget \
|
||||
xz-utils \
|
||||
; \
|
||||
rm -rf /var/lib/apt/lists/*; \
|
||||
\
|
||||
RABBITMQ_SOURCE_URL="https://s3-eu-west-1.amazonaws.com/server-release-pipeline/v3.9.x/unverified-packages/rabbitmq-server-${RABBITMQ_VERSION}-build-${RABBITMQ_BUILD_NUMBER}-generic-unix-latest-toolchain.tar"; \
|
||||
RABBITMQ_PATH="/usr/local/src/rabbitmq-$RABBITMQ_VERSION"; \
|
||||
\
|
||||
# wget --progress dot:giga --output-document "$RABBITMQ_PATH.tar.xz.asc" "$RABBITMQ_SOURCE_URL.asc"; \
|
||||
wget --progress dot:giga --output-document "$RABBITMQ_PATH.tar" "$RABBITMQ_SOURCE_URL"; \
|
||||
tar --extract --file "$RABBITMQ_PATH.tar"; \
|
||||
\
|
||||
# export GNUPGHOME="$(mktemp -d)"; \
|
||||
# gpg --batch --keyserver "$PGP_KEYSERVER" --recv-keys "$RABBITMQ_PGP_KEY_ID"; \
|
||||
# gpg --batch --verify "$RABBITMQ_PATH.tar.xz.asc" "$RABBITMQ_PATH.tar.xz"; \
|
||||
# gpgconf --kill all; \
|
||||
# rm -rf "$GNUPGHOME"; \
|
||||
\
|
||||
mkdir -p "$RABBITMQ_HOME"; \
|
||||
tar --extract --file "rabbitmq-server-generic-unix-latest-toolchain-${RABBITMQ_VERSION}.tar.xz" --directory "$RABBITMQ_HOME" --strip-components 1; \
|
||||
rm -rf "$RABBITMQ_PATH"* rabbitmq-server-generic-unix*; \
|
||||
# Do not default SYS_PREFIX to RABBITMQ_HOME, leave it empty
|
||||
grep -qE '^SYS_PREFIX=\$\{RABBITMQ_HOME\}$' "$RABBITMQ_HOME/sbin/rabbitmq-defaults"; \
|
||||
sed -i 's/^SYS_PREFIX=.*$/SYS_PREFIX=/' "$RABBITMQ_HOME/sbin/rabbitmq-defaults"; \
|
||||
grep -qE '^SYS_PREFIX=$' "$RABBITMQ_HOME/sbin/rabbitmq-defaults"; \
|
||||
chown -R rabbitmq:rabbitmq "$RABBITMQ_HOME"; \
|
||||
\
|
||||
apt-mark auto '.*' > /dev/null; \
|
||||
apt-mark manual $savedAptMark; \
|
||||
apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false; \
|
||||
\
|
||||
# verify assumption of no stale cookies
|
||||
[ ! -e "$RABBITMQ_DATA_DIR/.erlang.cookie" ]; \
|
||||
# Ensure RabbitMQ was installed correctly by running a few commands that do not depend on a running server, as the rabbitmq user
|
||||
# If they all succeed, it's safe to assume that things have been set up correctly
|
||||
gosu rabbitmq rabbitmqctl help; \
|
||||
gosu rabbitmq rabbitmqctl list_ciphers; \
|
||||
gosu rabbitmq rabbitmq-plugins list; \
|
||||
# no stale cookies
|
||||
rm "$RABBITMQ_DATA_DIR/.erlang.cookie"
|
||||
|
||||
# Added for backwards compatibility - users can simply COPY custom plugins to /plugins
|
||||
RUN ln -sf /opt/rabbitmq/plugins /plugins
|
||||
|
||||
# set home so that any `--user` knows where to put the erlang cookie
|
||||
ENV HOME $RABBITMQ_DATA_DIR
|
||||
# Hint that the data (a.k.a. home dir) dir should be separate volume
|
||||
VOLUME $RABBITMQ_DATA_DIR
|
||||
|
||||
# warning: the VM is running with native name encoding of latin1 which may cause Elixir to malfunction as it expects utf8. Please ensure your locale is set to UTF-8 (which can be verified by running "locale" in your shell)
|
||||
# Setting all environment variables that control language preferences, behaviour differs - https://www.gnu.org/software/gettext/manual/html_node/The-LANGUAGE-variable.html#The-LANGUAGE-variable
|
||||
# https://docs.docker.com/samples/library/ubuntu/#locales
|
||||
ENV LANG=C.UTF-8 LANGUAGE=C.UTF-8 LC_ALL=C.UTF-8
|
||||
|
||||
COPY docker/docker-entrypoint.sh /usr/local/bin/
|
||||
ENTRYPOINT ["docker-entrypoint.sh"]
|
||||
|
||||
EXPOSE 4369 5671 5672 25672
|
||||
CMD ["rabbitmq-server"]
|
||||
|
||||
# rabbitmq_management
|
||||
RUN rabbitmq-plugins enable --offline rabbitmq_management && \
|
||||
rabbitmq-plugins is_enabled rabbitmq_management --offline
|
||||
# extract "rabbitmqadmin" from inside the "rabbitmq_management-X.Y.Z.ez" plugin zipfile
|
||||
# see https://github.com/docker-library/rabbitmq/issues/207
|
||||
RUN set -eux; \
|
||||
rabbitmqadmin_path="$(find -L /plugins -name rabbitmqadmin -type f)"; \
|
||||
if [ -f "$rabbitmqadmin_path" ]; \
|
||||
then \
|
||||
cp "$rabbitmqadmin_path" /usr/local/bin/rabbitmqadmin; \
|
||||
else \
|
||||
erl -noinput -eval ' \
|
||||
{ ok, AdminBin } = zip:foldl(fun(FileInArchive, GetInfo, GetBin, Acc) -> \
|
||||
case Acc of \
|
||||
"" -> \
|
||||
case lists:suffix("/rabbitmqadmin", FileInArchive) of \
|
||||
true -> GetBin(); \
|
||||
false -> Acc \
|
||||
end; \
|
||||
_ -> Acc \
|
||||
end \
|
||||
end, "", init:get_plain_arguments()), \
|
||||
io:format("~s", [ AdminBin ]), \
|
||||
init:stop(). \
|
||||
' -- /plugins/rabbitmq_management-*.ez > /usr/local/bin/rabbitmqadmin; \
|
||||
fi; \
|
||||
[ -s /usr/local/bin/rabbitmqadmin ]; \
|
||||
chmod +x /usr/local/bin/rabbitmqadmin; \
|
||||
apt-get update; apt-get install -y --no-install-recommends python3; rm -rf /var/lib/apt/lists/*; \
|
||||
rabbitmqadmin --version
|
||||
EXPOSE 15671 15672
|
||||
|
||||
# rabbitmq_top
|
||||
RUN rabbitmq-plugins enable --offline rabbitmq_top && \
|
||||
rabbitmq-plugins is_enabled rabbitmq_top --offline
|
||||
|
||||
# rabbitmq_prometheus
|
||||
# We copy all local plugins to a temporary directory so that
|
||||
# we replace only the prometheus & rabbitmq_prometheus plugins in the image.
|
||||
# If we don't do this, things get very weird with globs,
|
||||
# and we either copy the the contents of those directories (e.g. ebin & priv) inside plugins,
|
||||
# or we end up with prometheus* & rabbitmq_prometheus directories (I know! 🙄)
|
||||
# This has been an ongoing issue since 2015, still not solved in 2021:
|
||||
# https://github.com/moby/moby/issues/15858
|
||||
COPY plugins /plugins-tmp
|
||||
RUN rm -fr /plugins/prometheus* && mv /plugins-tmp/prometheus* /plugins/
|
||||
RUN rm -fr /plugins/rabbitmq_prometheus* && mv /plugins-tmp/rabbitmq_prometheus* /plugins/
|
||||
RUN rm -fr /plugins-tmp
|
||||
|
||||
ARG RABBITMQ_PROMETHEUS_VERSION
|
||||
RUN chmod --recursive --verbose a+r /plugins/* && \
|
||||
chown --recursive --verbose rabbitmq:rabbitmq /plugins && \
|
||||
rabbitmq-plugins enable --offline rabbitmq_prometheus && \
|
||||
rabbitmq-plugins is_enabled rabbitmq_prometheus --offline && \
|
||||
rabbitmq-plugins list | grep "rabbitmq_prometheus.*${RABBITMQ_PROMETHEUS_VERSION}"
|
||||
EXPOSE 15692
|
|
@ -1,16 +1,3 @@
|
|||
TODAY := $(shell date -u +'%Y.%m.%d')
|
||||
# Use the latest alpha RabbitMQ 3.9 release - https://ci.rabbitmq.com/teams/main/pipelines/server-release:v3.9.x/jobs/build-test-package-generic-unix-latest-toolchain
|
||||
BASED_ON_RABBITMQ_VERSION := 3.9.0-alpha.465
|
||||
DOCKER_IMAGE_NAME := pivotalrabbitmq/rabbitmq-prometheus
|
||||
DOCKER_IMAGE_VERSION := $(BASED_ON_RABBITMQ_VERSION)-$(TODAY)
|
||||
# RABBITMQ_VERSION is used in rabbitmq-components.mk to set PROJECT_VERSION
|
||||
RABBITMQ_VERSION ?= $(DOCKER_IMAGE_VERSION)
|
||||
# This is taken from the CI job above
|
||||
RABBITMQ_BUILD_NUMBER := 499
|
||||
# make find-latest-otp
|
||||
OTP_VERSION := 23.2.2
|
||||
OTP_SHA256 := 04994a2dffee0170554797b3d258b4f4727e54c772e721202e9fb22d6827e4de
|
||||
|
||||
define PROJECT_ENV
|
||||
[
|
||||
{return_per_object_metrics, false}
|
||||
|
@ -20,8 +7,6 @@ endef
|
|||
PROJECT := rabbitmq_prometheus
|
||||
PROJECT_MOD := rabbit_prometheus_app
|
||||
DEPS = accept rabbit rabbitmq_management_agent prometheus rabbitmq_web_dispatch
|
||||
# Deps that are not applications
|
||||
# rabbitmq_management is added so that we build a custom version, for the Docker image
|
||||
BUILD_DEPS = amqp_client rabbit_common rabbitmq_management
|
||||
TEST_DEPS = rabbitmq_ct_helpers rabbitmq_ct_client_helpers eunit_formatters
|
||||
|
||||
|
@ -37,7 +22,6 @@ ERLANG_MK_REPO = https://github.com/rabbitmq/erlang.mk.git
|
|||
ERLANG_MK_COMMIT = rabbitmq-tmp
|
||||
|
||||
ifneq ($(DISABLE_METRICS_COLLECTOR),)
|
||||
BUILD_DEPS = accept amqp_client rabbit_common
|
||||
RABBITMQ_CONFIG_FILE = $(CURDIR)/rabbitmq-disable-metrics-collector.conf
|
||||
export RABBITMQ_CONFIG_FILE
|
||||
endif
|
||||
|
@ -45,104 +29,20 @@ endif
|
|||
include ../../rabbitmq-components.mk
|
||||
include ../../erlang.mk
|
||||
|
||||
define MAKE_TARGETS
|
||||
awk -F: '/^[^\.%\t][a-zA-Z\._\-]*:+.*$$/ { printf "%s\n", $$1 }' $(MAKEFILE_LIST)
|
||||
endef
|
||||
define BASH_AUTOCOMPLETE
|
||||
complete -W \"$$($(MAKE_TARGETS) | sort | uniq)\" make gmake m
|
||||
endef
|
||||
.PHONY: autocomplete
|
||||
autocomplete: ## ac | Configure shell for autocompletion - eval "$(gmake autocomplete)"
|
||||
@echo "$(BASH_AUTOCOMPLETE)"
|
||||
.PHONY: ac
|
||||
ac: autocomplete
|
||||
# Continuous Feedback for the ac target - run in a separate pane while iterating on it
|
||||
.PHONY: CFac
|
||||
CFac:
|
||||
@watch -c $(MAKE) ac
|
||||
|
||||
.PHONY: clean-docker
|
||||
clean-docker: ## cd | Clean all Docker containers & volumes
|
||||
@docker system prune -f && \
|
||||
docker volume prune -f
|
||||
.PHONY: cd
|
||||
cd: clean-docker
|
||||
|
||||
.PHONY: readme
|
||||
readme: ## r | Preview README & live reload on edit
|
||||
readme: # Preview README & live reload on edit
|
||||
@docker run --interactive --tty --rm --name changelog_md \
|
||||
--volume $(CURDIR):/data \
|
||||
--volume $(HOME)/.grip:/.grip \
|
||||
--expose 5000 --publish 5000:5000 \
|
||||
mbentley/grip --context=. 0.0.0.0:5000
|
||||
.PHONY: pre
|
||||
pre: preview-readme
|
||||
|
||||
define CTOP_CONTAINER
|
||||
docker pull quay.io/vektorlab/ctop:latest && \
|
||||
docker run --rm --interactive --tty \
|
||||
--cpus 0.5 --memory 128M \
|
||||
--volume /var/run/docker.sock:/var/run/docker.sock \
|
||||
--name ctop_$(USER) \
|
||||
quay.io/vektorlab/ctop:latest
|
||||
endef
|
||||
.PHONY: ctop
|
||||
ctop: ## c | Interact with all containers via a top-like utility
|
||||
@$(CTOP_CONTAINER)
|
||||
.PHONY: c
|
||||
c: ctop
|
||||
|
||||
.PHONY: dockerhub-login
|
||||
dockerhub-login: ## dl | Login to Docker Hub as pivotalrabbitmq
|
||||
@echo "$$(lpass show --password 7672183166535202820)" | \
|
||||
docker login --username pivotalrabbitmq --password-stdin
|
||||
.PHONY: dl
|
||||
dl: dockerhub-login
|
||||
|
||||
.PHONY: docker-image
|
||||
docker-image: docker-image-build docker-image-push ## di | Build & push Docker image to Docker Hub
|
||||
.PHONY: di
|
||||
di: docker-image
|
||||
|
||||
.PHONY: docker-image-build
|
||||
docker-image-build: ## dib | Build Docker image locally - make tests
|
||||
@docker build --pull \
|
||||
--build-arg PGP_KEYSERVER=pgpkeys.uk \
|
||||
--build-arg OTP_VERSION=$(OTP_VERSION) \
|
||||
--build-arg OTP_SHA256=$(OTP_SHA256) \
|
||||
--build-arg RABBITMQ_VERSION=$(BASED_ON_RABBITMQ_VERSION) \
|
||||
--build-arg RABBITMQ_BUILD_NUMBER=$(RABBITMQ_BUILD_NUMBER) \
|
||||
--build-arg RABBITMQ_PROMETHEUS_VERSION=$(RABBITMQ_VERSION) \
|
||||
--tag $(DOCKER_IMAGE_NAME):$(DOCKER_IMAGE_VERSION) \
|
||||
--tag $(DOCKER_IMAGE_NAME):latest .
|
||||
.PHONY: dib
|
||||
dib: docker-image-build
|
||||
|
||||
.PHONY: docker-image-bump
|
||||
docker-image-bump: ## diu | Bump Docker image version across all docker-compose-* files
|
||||
docker-image-bump: # Bump Docker image version across all docker-compose-* files
|
||||
@sed -i '' \
|
||||
-e 's|$(DOCKER_IMAGE_NAME):.*|$(DOCKER_IMAGE_NAME):$(DOCKER_IMAGE_VERSION)|g' \
|
||||
-e 's|pivotalrabbitmq/perf-test:.*|pivotalrabbitmq/perf-test:2.11.0-ubuntu|g' \
|
||||
docker/docker-compose-{overview,dist-tls,qq,dist-metrics}.yml
|
||||
.PHONY: diu
|
||||
diu: docker-image-bump
|
||||
|
||||
.PHONY: docker-image-push
|
||||
docker-image-push: ## dip | Push local Docker image to Docker Hub
|
||||
@docker push $(DOCKER_IMAGE_NAME):$(DOCKER_IMAGE_VERSION) && \
|
||||
docker push $(DOCKER_IMAGE_NAME):latest
|
||||
.PHONY: dip
|
||||
dip: docker-image-push
|
||||
|
||||
.PHONY: docker-image-run
|
||||
docker-image-run: ## dir | Run container with local Docker image
|
||||
@docker run --interactive --tty \
|
||||
--publish=5672:5672 \
|
||||
--publish=15672:15672 \
|
||||
--publish=15692:15692 \
|
||||
$(DOCKER_IMAGE_NAME):$(DOCKER_IMAGE_VERSION)
|
||||
.PHONY: dir
|
||||
dir: docker-image-run
|
||||
|
||||
RUN ?= up --detach && docker-compose --file $(@F) logs --follow
|
||||
DOCKER_COMPOSE_FILES := $(wildcard docker/docker-compose-*.yml)
|
||||
|
@ -153,30 +53,7 @@ $(DOCKER_COMPOSE_FILES):
|
|||
true
|
||||
.PHONY: down
|
||||
down: RUN = down
|
||||
down: $(DOCKER_COMPOSE_FILES) ## d | Stop all containers
|
||||
.PHONY: d
|
||||
d: down
|
||||
|
||||
JQ := /usr/local/bin/jq
|
||||
$(JQ):
|
||||
@brew install jq
|
||||
|
||||
OTP_CURRENT_STABLE_MAJOR := 23
|
||||
define LATEST_STABLE_OTP_VERSION
|
||||
curl --silent --fail https://api.github.com/repos/erlang/otp/git/refs/tags | \
|
||||
$(JQ) -r '.[].ref | sub("refs/tags/OTP.{1}";"") | match("^$(OTP_CURRENT_STABLE_MAJOR)[0-9.]+$$") | .string' | \
|
||||
tail -n 1
|
||||
endef
|
||||
.PHONY: find-latest-otp
|
||||
find-latest-otp: $(JQ) ## flo | Find latest OTP version archive + sha1
|
||||
@printf "Version: " && \
|
||||
export VERSION="$$($(LATEST_STABLE_OTP_VERSION))" && \
|
||||
echo "$$VERSION" && \
|
||||
printf "Checksum: " && \
|
||||
wget --continue --quiet --output-document="/tmp/OTP-$$VERSION.tar.gz" "https://github.com/erlang/otp/archive/OTP-$$VERSION.tar.gz" && \
|
||||
shasum -a 256 "/tmp/OTP-$$VERSION.tar.gz"
|
||||
.PHONY: flo
|
||||
flo: find-latest-otp
|
||||
down: $(DOCKER_COMPOSE_FILES) # Stop all containers
|
||||
|
||||
# Defined as explicit, individual targets so that autocompletion works
|
||||
define DOCKER_COMPOSE_UP
|
||||
|
@ -184,40 +61,25 @@ cd docker && \
|
|||
docker-compose --file docker-compose-$(@F).yml up --detach
|
||||
endef
|
||||
.PHONY: metrics
|
||||
metrics: ## m | Run all metrics containers: Grafana, Prometheus & friends
|
||||
metrics: # Run all metrics containers: Grafana, Prometheus & friends
|
||||
@$(DOCKER_COMPOSE_UP)
|
||||
.PHONY: m
|
||||
m: metrics
|
||||
.PHONY: overview
|
||||
overview: ## o | Make RabbitMQ Overview panels come alive
|
||||
overview: # Make RabbitMQ Overview panels come alive
|
||||
@$(DOCKER_COMPOSE_UP)
|
||||
.PHONY: o
|
||||
o: overview
|
||||
.PHONY: dist-tls
|
||||
dist-tls: ## dt | Make Erlang-Distribution panels come alive - HIGH LOAD
|
||||
dist-tls: # Make Erlang-Distribution panels come alive - HIGH LOAD
|
||||
@$(DOCKER_COMPOSE_UP)
|
||||
.PHONY: dt
|
||||
dt: dist-tls
|
||||
.PHONY: qq
|
||||
qq: ## q | Make RabbitMQ-Quorum-Queues-Raft panels come alive - HIGH LOAD
|
||||
qq: # Make RabbitMQ-Quorum-Queues-Raft panels come alive - HIGH LOAD
|
||||
@$(DOCKER_COMPOSE_UP)
|
||||
.PHONY: q
|
||||
q: qq
|
||||
|
||||
.PHONY: dist-metrics
|
||||
dist-metrics: ## dm | Make inet_tcp_metrics come alive
|
||||
dist-metrics: # Make inet_tcp_metrics come alive
|
||||
@$(DOCKER_COMPOSE_UP)
|
||||
.PHONY: dm
|
||||
dm: dist-metrics
|
||||
|
||||
.PHONY: h
|
||||
h:
|
||||
@awk -F"[:#]" '/^[^\.][a-zA-Z\._\-]+:+.+##.+$$/ { printf "\033[36m%-24s\033[0m %s\n", $$1, $$4 }' $(MAKEFILE_LIST) \
|
||||
| sort
|
||||
# Continuous Feedback for the h target - run in a separate pane while iterating on it
|
||||
.PHONY: CFh
|
||||
CFh:
|
||||
@watch -c $(MAKE) h
|
||||
JQ := /usr/local/bin/jq
|
||||
$(JQ):
|
||||
@brew install jq
|
||||
|
||||
# Defined as explicit, individual targets so that autocompletion works
|
||||
DASHBOARDS_TO_PATH := $(CURDIR)/docker/grafana/dashboards
|
||||
|
@ -248,4 +110,7 @@ RabbitMQ-Quorum-Queues-Raft.json: $(JQ)
|
|||
.PHONY: rabbitmq-exporter_vs_rabbitmq-prometheus.json
|
||||
rabbitmq-exporter_vs_rabbitmq-prometheus.json: $(JQ)
|
||||
@$(GENERATE_DASHBOARD)
|
||||
.PHONY: RabbitMQ-Stream.json
|
||||
RabbitMQ-Stream.json: $(JQ)
|
||||
@$(GENERATE_DASHBOARD)
|
||||
|
||||
|
|
|
@ -15,11 +15,10 @@ services:
|
|||
# https://network.pivotal.io/products/rabbitmq/
|
||||
# This is a commercial edition of RabbitMQ that requires a valid Tanzu Network account
|
||||
# Learn more: https://rabbitmq.com/tanzu
|
||||
image: dev.registry.pivotal.io/rabbitmq/vmware-tanzu-rabbitmq:2021.06
|
||||
image: dev.registry.pivotal.io/rabbitmq/vmware-tanzu-rabbitmq:1.0.0
|
||||
networks:
|
||||
- "rabbitmq-prometheus"
|
||||
ports:
|
||||
- "5680:5672"
|
||||
- "15680:15672"
|
||||
- "15700:15692"
|
||||
# https://unix.stackexchange.com/questions/71940/killing-tcp-connection-in-linux
|
||||
|
@ -48,19 +47,17 @@ services:
|
|||
<< : *rabbitmq
|
||||
hostname: rmq1-dist-metrics
|
||||
ports:
|
||||
- "5681:5672"
|
||||
- "15681:15672"
|
||||
- "15701:15692"
|
||||
rmq2-dist-metrics:
|
||||
<< : *rabbitmq
|
||||
hostname: rmq2-dist-metrics
|
||||
ports:
|
||||
- "5682:5672"
|
||||
- "15682:15672"
|
||||
- "15702:15692"
|
||||
|
||||
qq:
|
||||
image: &perf-test-image pivotalrabbitmq/perf-test:2.11.0-ubuntu
|
||||
image: &perf-test-image pivotalrabbitmq/perf-test:2.15.0-ubuntu
|
||||
networks:
|
||||
- "rabbitmq-prometheus"
|
||||
environment:
|
||||
|
|
|
@ -12,12 +12,11 @@ volumes:
|
|||
|
||||
services:
|
||||
rmq0-dist-tls: &rabbitmq
|
||||
# https://hub.docker.com/r/pivotalrabbitmq/rabbitmq-prometheus/tags
|
||||
image: pivotalrabbitmq/rabbitmq-prometheus:3.9.0-alpha.465-2021.01.18
|
||||
# https://hub.docker.com/r/pivotalrabbitmq/rabbitmq/tags
|
||||
image: pivotalrabbitmq/rabbitmq:master-otp-max
|
||||
networks:
|
||||
- "rabbitmq-prometheus"
|
||||
ports:
|
||||
- "5676:5672"
|
||||
- "15676:15672"
|
||||
- "15696:15692"
|
||||
# https://unix.stackexchange.com/questions/71940/killing-tcp-connection-in-linux
|
||||
|
@ -48,19 +47,17 @@ services:
|
|||
<< : *rabbitmq
|
||||
hostname: rmq1-dist-tls
|
||||
ports:
|
||||
- "5677:5672"
|
||||
- "15677:15672"
|
||||
- "15697:15692"
|
||||
rmq2-dist-tls:
|
||||
<< : *rabbitmq
|
||||
hostname: rmq2-dist-tls
|
||||
ports:
|
||||
- "5678:5672"
|
||||
- "15678:15672"
|
||||
- "15698:15692"
|
||||
stress-dist-tls:
|
||||
# https://hub.docker.com/r/pivotalrabbitmq/perf-test/tags
|
||||
image: &perf-test-image pivotalrabbitmq/perf-test:2.11.0-ubuntu
|
||||
image: &perf-test-image pivotalrabbitmq/perf-test:2.15.0-ubuntu
|
||||
networks:
|
||||
- "rabbitmq-prometheus"
|
||||
environment:
|
||||
|
@ -79,7 +76,7 @@ services:
|
|||
METRICS_PROMETHEUS: "true"
|
||||
rabbitmq-exporter:
|
||||
# https://hub.docker.com/r/kbudde/rabbitmq-exporter/tags
|
||||
image: kbudde/rabbitmq-exporter:v0.29.0
|
||||
image: kbudde/rabbitmq-exporter:v1.0.0-RC9
|
||||
networks:
|
||||
- "rabbitmq-prometheus"
|
||||
environment:
|
||||
|
|
|
@ -13,7 +13,7 @@ volumes:
|
|||
services:
|
||||
grafana:
|
||||
# https://hub.docker.com/r/grafana/grafana/tags
|
||||
image: grafana/grafana:7.3.2
|
||||
image: grafana/grafana:8.0.6
|
||||
ports:
|
||||
- "3000:3000"
|
||||
networks:
|
||||
|
@ -34,7 +34,7 @@ services:
|
|||
GF_INSTALL_PLUGINS: "flant-statusmap-panel,grafana-piechart-panel"
|
||||
prometheus:
|
||||
# https://hub.docker.com/r/prom/prometheus/tags
|
||||
image: prom/prometheus:v2.22.1
|
||||
image: prom/prometheus:v2.28.1
|
||||
networks:
|
||||
- "rabbitmq-prometheus"
|
||||
ports:
|
||||
|
@ -51,7 +51,7 @@ services:
|
|||
expose:
|
||||
- 9100
|
||||
# https://hub.docker.com/r/prom/node-exporter/tags
|
||||
image: prom/node-exporter:v1.0.1
|
||||
image: prom/node-exporter:v1.2.0
|
||||
networks:
|
||||
- "rabbitmq-prometheus"
|
||||
volumes:
|
||||
|
|
|
@ -12,12 +12,11 @@ volumes:
|
|||
|
||||
services:
|
||||
rmq0: &rabbitmq
|
||||
# https://hub.docker.com/r/pivotalrabbitmq/rabbitmq-prometheus/tags
|
||||
image: pivotalrabbitmq/rabbitmq-prometheus:3.9.0-alpha.465-2021.01.18
|
||||
# https://hub.docker.com/r/pivotalrabbitmq/rabbitmq/tags
|
||||
image: pivotalrabbitmq/rabbitmq:master-otp-max
|
||||
networks:
|
||||
- "rabbitmq-prometheus"
|
||||
ports:
|
||||
- "5673:5672"
|
||||
- "15673:15672"
|
||||
- "15693:15692"
|
||||
# https://unix.stackexchange.com/questions/71940/killing-tcp-connection-in-linux
|
||||
|
@ -45,20 +44,18 @@ services:
|
|||
<< : *rabbitmq
|
||||
hostname: rmq1
|
||||
ports:
|
||||
- "5674:5672"
|
||||
- "15674:15672"
|
||||
- "15694:15692"
|
||||
rmq2:
|
||||
<< : *rabbitmq
|
||||
hostname: rmq2
|
||||
ports:
|
||||
- "5675:5672"
|
||||
- "15675:15672"
|
||||
- "15695:15692"
|
||||
|
||||
basic-get:
|
||||
# https://hub.docker.com/r/pivotalrabbitmq/perf-test/tags
|
||||
image: &perf-test-image pivotalrabbitmq/perf-test:2.11.0-ubuntu
|
||||
image: &perf-test-image pivotalrabbitmq/perf-test:2.15.0-ubuntu
|
||||
networks:
|
||||
- "rabbitmq-prometheus"
|
||||
environment:
|
||||
|
@ -173,6 +170,11 @@ services:
|
|||
CONSUMERS: 0
|
||||
SERVERS_STARTUP_TIMEOUT: *startup_timeout
|
||||
METRICS_PROMETHEUS: "true"
|
||||
stream:
|
||||
image: pivotalrabbitmq/stream-perf-test
|
||||
networks:
|
||||
- "rabbitmq-prometheus"
|
||||
command: "--uris rabbitmq-stream://guest:guest@rmq2:5552/%2f --max-length-bytes 100mb --rate 1000"
|
||||
# many-queues:
|
||||
# image: *perf-test-image
|
||||
# networks:
|
||||
|
|
|
@ -12,12 +12,11 @@ volumes:
|
|||
|
||||
services:
|
||||
rmq0-qq: &rabbitmq
|
||||
# https://hub.docker.com/r/pivotalrabbitmq/rabbitmq-prometheus/tags
|
||||
image: pivotalrabbitmq/rabbitmq-prometheus:3.9.0-alpha.465-2021.01.18
|
||||
# https://hub.docker.com/r/pivotalrabbitmq/rabbitmq/tags
|
||||
image: pivotalrabbitmq/rabbitmq:master-otp-max
|
||||
networks:
|
||||
- "rabbitmq-prometheus"
|
||||
ports:
|
||||
- "5679:5672"
|
||||
- "15679:15672"
|
||||
- "15699:15692"
|
||||
# https://unix.stackexchange.com/questions/71940/killing-tcp-connection-in-linux
|
||||
|
@ -41,18 +40,16 @@ services:
|
|||
<< : *rabbitmq
|
||||
hostname: rmq1-qq
|
||||
ports:
|
||||
- "5680:5672"
|
||||
- "15680:15672"
|
||||
- "15700:15692"
|
||||
rmq2-qq:
|
||||
<< : *rabbitmq
|
||||
hostname: rmq2-qq
|
||||
ports:
|
||||
- "5681:5672"
|
||||
- "15681:15672"
|
||||
- "15701:15692"
|
||||
qq-moderate-load:
|
||||
image: &perf-test-image pivotalrabbitmq/perf-test:2.11.0-ubuntu
|
||||
image: &perf-test-image pivotalrabbitmq/perf-test:2.15.0-ubuntu
|
||||
networks:
|
||||
- "rabbitmq-prometheus"
|
||||
environment:
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
"type": "datasource",
|
||||
"id": "prometheus",
|
||||
"name": "prometheus",
|
||||
"version": "2.0.0"
|
||||
"version": "1.0.0"
|
||||
},
|
||||
{
|
||||
"type": "table",
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,32 @@
|
|||
# RabbitMQ-Stream
|
||||
|
||||
The stream protocol has been introduced in RabbitMQ 3.9.0, and is meant to be used in conjuction with Streams.
|
||||
|
||||
Streams are a new persistent and replicated data structure which models an append-only log with non-destructive consumer semantics.
|
||||
|
||||
Learn more about [RabbitMQ Streams](https://www.rabbitmq.com/streams.html).
|
||||
|
||||
These blog posts expand on the documentation:
|
||||
- [Streams Overview](https://blog.rabbitmq.com/posts/2021/07/rabbitmq-streams-overview/) (includes slides)
|
||||
- [First Application with Streams](https://blog.rabbitmq.com/posts/2021/07/rabbitmq-streams-first-application/) (includes video)
|
||||
- [Connecting to Streams](https://blog.rabbitmq.com/posts/2021/07/connecting-to-streams/) (includes diagrams)
|
||||
|
||||
## Metrics displayed
|
||||
|
||||
- Stream publishers
|
||||
- Stream messages received / s
|
||||
- Stream messages confirmed to publishers / s
|
||||
- Stream consumers
|
||||
- Stream messages delivered / s
|
||||
- Errors since boot
|
||||
|
||||
## Filter by
|
||||
|
||||
- Namespace
|
||||
- RabbitMQ Cluster
|
||||
|
||||
|
||||
## Requires
|
||||
|
||||
- `rabbitmq-stream` plugin to be enabled
|
||||
- `rabbitmq-prometheus` plugin to be enabled
|
BIN
deps/rabbitmq_prometheus/docker/grafana/publish/rabbitmq-stream-bottom-2021-07-29-original.png
vendored
Normal file
BIN
deps/rabbitmq_prometheus/docker/grafana/publish/rabbitmq-stream-bottom-2021-07-29-original.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 980 KiB |
BIN
deps/rabbitmq_prometheus/docker/grafana/publish/rabbitmq-stream-bottom-2021-07-29.jpg
vendored
Normal file
BIN
deps/rabbitmq_prometheus/docker/grafana/publish/rabbitmq-stream-bottom-2021-07-29.jpg
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 488 KiB |
BIN
deps/rabbitmq_prometheus/docker/grafana/publish/rabbitmq-stream-logo-2021-07-29-original.jpg
vendored
Normal file
BIN
deps/rabbitmq_prometheus/docker/grafana/publish/rabbitmq-stream-logo-2021-07-29-original.jpg
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 414 KiB |
BIN
deps/rabbitmq_prometheus/docker/grafana/publish/rabbitmq-stream-top-2021-07-29-original.png
vendored
Normal file
BIN
deps/rabbitmq_prometheus/docker/grafana/publish/rabbitmq-stream-top-2021-07-29-original.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.3 MiB |
BIN
deps/rabbitmq_prometheus/docker/grafana/publish/rabbitmq-stream-top-2021-07-29.jpg
vendored
Normal file
BIN
deps/rabbitmq_prometheus/docker/grafana/publish/rabbitmq-stream-top-2021-07-29.jpg
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 487 KiB |
Loading…
Reference in New Issue