Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CTL_OVER_HTTP and containers frictionless #4340

Open
wants to merge 29 commits into
base: master
Choose a base branch
from

Conversation

badlop
Copy link
Member

@badlop badlop commented Jan 13, 2025

This PR includes many commits related to two main features: CTL_OVER_HTTP and container images frictionless. Below is a description of all the relevant changes, suitable for the release notes.

This PR will soon be accompanied by the corresponding PR in docker-ejabberd, and the resulting changes in docs.git


ejabberd_listener: Add support for socket relative path

If the port option is set to "unix:directory/filename" without absolute path, then the directory and file are created in the mnesia spool directory.

ejabberdctl: New option CTL_OVER_HTTP

The ejabberdctl script is useful not only to start and stop ejabberd, it can also execute all the 180+ ejabberd API commands inside the running ejabberd node. For this, the script starts another erlang virtual machine and connects it to the already existing one that is running ejabberd.

This connection method is acceptable for performing a few administrative tasks (reload configuration, register an account, etc). However, ejabberdctl is noticeably slow for performing multiple calls, for example to register 1000 accounts. In that case, it is preferable to send ReST queries over HTTP to mod_http_api.

And now ejabberdctl can do exactly this! ejabberdctl can be configured to use an HTTP connection to execute the command, which is way faster than starting an erlang node, around 20 times faster.

To enable this feature, first configure in ejabberd.yml:

listen:
  -
    port: "unix:sockets/ctl_over_http.socket"
    module: ejabberd_http
    tag: "ctl_over_http"
    unix_socket:
      mode: '0600'
    request_handlers:
      /ctl: ejabberd_ctl

api_permissions:
  "console commands over http":
    from:
      - tag: "ctl_over_http"
    who: all
    what: "*"

Then enable CTL_OVER_HTTP in ejabberdctl.cfg:

CTL_OVER_HTTP=sockets/ctl_over_http.socket

Let's register 100 accounts using the standard method and CTL_OVER_HTTP:

$ time for (( i=100 ; i ; i=i-1 )) ; do ejabberdctl register user$i localhost pass; done
...
real    0m43,929s
user    0m41,878s
sys     0m10,558s

$ time for (( i=100 ; i  ; i=i-1 )) ; do CTL_OVER_HTTP=sockets/ctl_over_http.socket ejabberdctl register user$i localhost pass; done
...
real    0m2,144s
user    0m1,377s
sys     0m0,566s

This feature is enabled by default in the ejabberd and ecs container images.

Container images: Reduce friction when moving from ecs to ejabberd

Several improvements are added in the ejabberd and ecs container images to allow easier migration from one to the other.

This also allows to use the same documentation file for both container images, as now there are very few usability differences between both images. Also, a new comparison table in that documentation describes all the differences between both images.

The improvements are:

  • Adds support for paths from ecs into ejabberd container image, and viceversa
  • Include ejabberdapi also in the ejabberd container image, as does ecs
  • Copy captcha scripts to immutable path /usr/local/bin/ for easy calling
  • Copy sql files to /opt/ejabberd/database/sql/
  • Copy sql also to /opt/ejabberd/database/ for backwards compatibility with ecs
  • Link path to mnesia spool dir for backwards compatibility
  • CONTAINER.md now documents both images, as there are few differences. Also includes a comparison table

Container images: Use macros in default configuration

The default ejabberd.yml configuration file included in the ejabberd and ecs container images now uses macros for defining host, admin account and port numbers.

This way you can overwrite any of them at starttime using environment variables:

     env:
     - name: PORT_HTTP_TLS
       value: 5444

Container images: Listen for WebAdmin in a port number lower than any other

The docker-desktop and podman-desktop applications show a button named "Open Browser". When the user clicks that button, it opens a web browser with / URL and the lowest exposed port number.

The default ejabberd.yml configuration file included in the ejabberd and ecs container images now listens in port number 1880, the lowest of all, so the "Open Browser" button will open directly the ejabberd WebAdmin site.

ejabberd image: Use again direct method to build image

Due to a bug in QEMU, in order to build the ejabberd container image for the arm64 architecture, we have been using a workaround that involves generating binary installers, this is explained in 3983.

Fortunately, now that QEMU is fixed, the ejabberd container image for arm64 can be generated using QEMU again, so the workaround has been removed, this is explained in 4280.

ejabberd image: EJABBERD_MACRO_ADMIN and REGISTER_ADMIN_PASSWORD

In ejabberd container image it is now possible to register an account, and grant it admin rights. If password variable is set, register that account.

Example kubernetes yaml file in podman:

     env:
     - name: EJABBERD_MACRO_ADMIN
       value: [email protected]
     - name: REGISTER_ADMIN_PASSWORD
       value: somePass0rd

If the admin and password variables are not set, it grants admin rights only to a random account name. Notice that admin rights are granted to that variable in the default ejabberd.yml, so if the account was not registered, somebody else could do it.

Alternatively, this can be done with the existing CTL_ON_CREATE variable, and then you would need to modify ejabberd.yml accordingly:

     env:
     - name: CTL_ON_CREATE
       value: register administrator example.org somePass0rd

@coveralls
Copy link

coveralls commented Jan 13, 2025

Coverage Status

coverage: 33.357% (-0.007%) from 33.364%
when pulling d1bede6 on badlop:containers-frictionless
into 0566351 on processone:master.

@badlop badlop force-pushed the containers-frictionless branch from ddb09e6 to d1bede6 Compare January 15, 2025 15:17
badlop added 28 commits January 15, 2025 20:57
If the 'port' option is set to "unix:some-filename" without absolute path,
then the file is created in the mnesia spool directory
This uses an HTTP connection to execute the command,
which is way faster than starting an erlang node
Copy captcha scripts to stable path for referencing in compose files:
  /usr/local/bin/
which is included in $PATH

For backwards compatibility with ecs, link:
  /opt/ -> /home/
  /usr/local/bin/ -> /opt/ejabberd/bin/

Copy sql files to stable path for referencing:
  /opt/ejabberd/sql/
For backwards compatibility with ecs, copy also to
  /opt/ejabberd/database/
ecs image implemented this in ejabberdctl since 2019:
  edb0373fd0ae0b24807a41ba2c3bf04b5b514844
  Keep SQL init scripts in container (#42)
In the docker-desktop and podman-desktop,
when user clicks their "Open Browser" buttons,
those apps open a browser with / URL and the lowest exposed port number.
Code written originally by sando38 for ecs's Dockerfile.
If password variable is set, register that account.
Example kubernetes yaml file in podman:

    env:
    - name: EJABBERD_MACRO_ADMIN
      value: [email protected]
    - name: REGISTER_ADMIN_PASSWORD
      value: somePass0rd

If admin and password are not set,
grant admin rights only to a random account name.
Notice that admin rights are granted to that variable in the default
ejabberd.yml, so if the account is not created, somebody else could do.
The ejabberdctl script in ecs image sets mnesia spool dir as:
: "${SPOOL_DIR:="$HOME_DIR/database/$ERLANG_NODE"}"
Partially revert d15cf99:
  Container: Add METHOD to build container using packages (3983)
Without this, compiling Elixir on arm64 using QEMU fails with:
 <<"could not call Module.put_attribute/3 because the module ExUnit.DocTest
 is already compiled">>

Solution found in:
  https://elixirforum.com/t/elixir-docker-image-wont-build-for-linux-arm64-v8-using-github-actions/56383/13
The expected placement of --auth is not arbitrary,
it should be provided immediately before the command+args
The socket file is useless outside the container, and also
database/ may get mounted as volume, and can't handle socket file
@badlop badlop force-pushed the containers-frictionless branch from d1bede6 to 28d0842 Compare January 16, 2025 17:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants