You are browsing a read-only backup copy of Wikitech. The primary site can be found at wikitech.wikimedia.org

Tool:Bridgebot: Difference between revisions

From Wikitech-static
Jump to navigation Jump to search
imported>Majavah
(:()
imported>BryanDavis
(→‎Telegram: Remove description of old method for getting a Telegram channel id)
 
(3 intermediate revisions by the same user not shown)
Line 20: Line 20:
== Bot accounts ==
== Bot accounts ==
The bot must be invited/added to chat channels in order to create bridges. Currently the bot has these accounts on various chat platforms:
The bot must be invited/added to chat channels in order to create bridges. Currently the bot has these accounts on various chat platforms:
; IRC
; libera.chat IRC
:* account: wm-bridgebot
:* account: wm-bridgebot
:* nicks: wm-bridgebot, wm-bb
:* nicks: wm-bridgebot, wm-bb
Line 30: Line 30:


== Maintenance ==
== Maintenance ==
The bot runs from [[Portal:Toolforge|Toolforge]] under the "bridgebot" account as a [[Help:Toolforge/Kubernetes|kubernetes]] pod. The Kubernetes container is managed by a custom deployment.
The bot runs from [[Portal:Toolforge|Toolforge]] under the "bridgebot" account as a [[Help:Toolforge/Kubernetes|kubernetes]] pod.
 
{{Codesample|lang=shell-session|code=
$ ssh login.toolforge.org
$ become bridgebot
 
:# Deploying
$ bin/bb.sh start
Starting bridgebot k8s deployment...
 
:# Quick restart (pod delete)
$ bin/bb.sh restart
Restarting bridgebot pod...
 
:# "Full" restart (Deployment delete; Deployment create)
$ bin/bb.sh stop
Stopping bridgebot k8s deployment...
$ bin/bb.sh start
Starting bridgebot k8s deployment...
 
:# Upgrading the golang binary
$ bin/bb.sh download $version
$ vim bb.sh
  update the MATTERBRIDGE=... line to the new version
  :wq
$ bin/bb.sh restart "Upgrading matterbridge to $version"
}}
 
=== Joining a new channel ===
Maintainers of the tool can configure the bot to join a new channel:
<syntaxhighlight lang="console">
$ ssh login.tools.wmflabs.org
$ become bridgebot
$ vim etc/matterbridge.toml
:# Add a new "[[gateway]]" section defining the gateway name and the channels to bridge
$ bin/bb.sh restart
</syntaxhighlight>
 
==== Telegram ====
If one side of the bridge is Telegram you will need these things to be done:
# Have an admin of the Telegram channel invite the "@wmtelegram_bot" user to the channel
# Have someone in the Telegram channel post the message <code>/chatId</code> (This command is case-sensitive.)
# Collect the Telegram "Channel" id number from @wmtelegram_bot's reply to the bot command
 
==== Discord ====
If one side of the bridge is Discord you will need these things to be done:
# Have an admin of the Discord server invite the bot to their server using [https://discord.com/oauth2/authorize?client_id=744713247218860063&scope=bot&permissions=19456 the bot's invite link]
 
== Common problems ==
=== Duplicate messages being sent from irc to other bridges ===
{{Tracked|T305487}}
 
The bot can get into a state where every message that it sees from irc gets sent multiple times to other bridged channels. This is caused by incorrect handling of irc server connection messages by the bot when the intermediate ZNC service reconnects to libra.chat. The fix is simply to restart the bot:
<syntaxhighlight lang=shell-session>
$ ssh login.toolforge.org
$ become bridgebot
$ bb.sh restart 'Double IRC messages to other bridges'
</syntaxhighlight>
 
== Technical details ==
 
=== bin/bb.sh ===
To make operating the bot less complicated for maintainers, we have a ''bin/bb.sh'' script to wrap the various Kubernetes commands. This same script is used as the command inside the bot's container to setup and run the matterbridge software when invoked as <code>bin/bb.sh run</code>. The ''run'' action copies the matterbridge binary and it's configuration into the container's /tmp directory so that while running there is no need to read or write to the tool's $HOME.
 
{{Codesample|name=$HOME/bin/bb.sh|lang=bash|scheme=light|line=1|highlight=28-40|code=
#!/usr/bin/env bash
# Management script for bridgebot kubernetes processes
 
set -e
 
MATTERBRIDGE=matterbridge-1.23.0-linux-64bit
 
DEPLOYMENT=bridgebot.bot
POD_NAME=bridgebot.bot
 
TOOL_DIR=$(cd $(dirname $0)/.. && pwd -P)
BIN_DIR=$TOOL_DIR/bin
CONFIG_DIR=$TOOL_DIR/etc
 
KUBECTL=/usr/bin/kubectl
_get_pod() {
    $KUBECTL get pods \
        --output=jsonpath={.items..metadata.name} \
        --selector=name=${POD_NAME}
}
 
case "$1" in
    start)
        echo "Starting bridgebot k8s deployment..."
        $KUBECTL create --validate=true -f ${CONFIG_DIR}/deployment.yaml
        [[ -n $2 ]] && dologmsg "$2"
        ;;
    run)
        # Execute bot inside container
        date +%Y-%m-%dT%H:%M:%S
        echo "Bootstrapping container..."
        cd ${TOOL_DIR}
        cp ${BIN_DIR}/${MATTERBRIDGE} /tmp
        chmod a+x /tmp/${MATTERBRIDGE}
        cp ${CONFIG_DIR}/matterbridge.toml /tmp
        cp ${CONFIG_DIR}/remotenickformat.tengo /tmp
        echo "Starting bridgebot..."
        cd /tmp
        exec /tmp/${MATTERBRIDGE} -debug -conf /tmp/matterbridge.toml
        ;;
    stop)
        echo "Stopping bridgebot k8s deployment..."
        $KUBECTL delete deployment ${DEPLOYMENT}
        [[ -n $2 ]] && dologmsg "$2"
        ;;
    restart)
        echo "Restarting bridgebot pod..."
        $KUBECTL delete pod $(_get_pod)
        [[ -n $2 ]] && dologmsg "$2"
        ;;
    status)
        echo "Active pods:"
        $KUBECTL get pods -l name=${POD_NAME}
        ;;
    tail)
        exec $KUBECTL logs -f $(_get_pod)
        ;;
    attach)
        echo "Attaching to pod..."
        exec $KUBECTL exec -i -t $(_get_pod) -- /bin/bash
        ;;
    version)
        echo "${BIN_DIR}/${MATTERBRIDGE}"
        "${BIN_DIR}/${MATTERBRIDGE}" -version
        ;;
    download)
        version=${2:?No version specified. Expected something like '1.22.1'}
        baseurl="https://github.com/42wim/matterbridge/releases/download"
        new="matterbridge-${version}-linux-64bit"
        if [[ -f "${BIN_DIR}/${new}" ]]; then
            read -p "${new} exists. Overwrite? [y/N]: " -n 1 -r
            if [[ ! $REPLY =~ ^[Yy]$ ]]; then
                exit 1
            fi
            echo
        fi
        echo "Downloading ${new}..."
        wget -O "${BIN_DIR}/${new}" "${baseurl}/v${version}/${new}"
        chmod a+x "${BIN_DIR}/${new}"
        echo "Downloaded $("${BIN_DIR}/${new}" -version)"
        ;;
    *)
        echo "Usage: $0 {start|stop|restart|status|tail|attach}"
        exit 1
        ;;
esac
exit 0
# vim:ft=sh:sw=4:ts=4:sts=4:et:
}}
 
=== deployment.apps/bridgebot.bot ===
The bot's Kubernetes container is managed by a custom deployment defined in ''$HOME/etc/deployment.yaml'' and applied by ''bin/bb.sh''.


{{Codesample|name=$HOME/etc/deployment.yaml|lang=yaml|scheme=light|line=1|code=
{{Codesample|name=$HOME/etc/deployment.yaml|lang=yaml|scheme=light|line=1|code=
Line 74: Line 230:
}}
}}


{{Codesample|lang=shell-session|code=
=== deployment.apps/bridgebot.bnc ===
$ ssh login.toolforge.org
{{Tracked|T264212|Resolved}}{{Tracked|T292640|Resolved}}
$ become bridgebot


:# Deploying
After many issues with matterbridge's IRC client, we decided to place a [[w:BNC_(software)|bouncer]] (BNC) between matterbridge and libera.chat. This bouncer is running as a pod inside the tool's namespace and connected to a Kubernetes Service which allows the bot's pod to connect to it.
$ bin/bb.sh start
Starting bridgebot k8s deployment...


:# Quick restart (pod delete)
The specific BNC software currently used is [[w:ZNC|ZNC]]. ZNC was compiled from inside a <code>webservice ruby27 shell</code> (ruby27 just happened to have all the -dev packages needed) and installed to ''$HOME/.local/bin/znc''. ZNC's runtime configuration is stored in ''$HOME/.znc''.
$ bin/bb.sh restart
Restarting bridgebot pod...


:# "Full" restart (Deployment delete; Deployment create)
Configuration for ZNC can be managed by connecting to it with an IRC client running inside the tool's namespace. [https://github.com/mcpcpc/kirc kirc] has been compiled and installed to ''$HOME/.local/bin/kirc'' for this purpose. The password used to connect to the bouncer can be found in the ''$HOME/etc/matterbridge.toml'' configuration file.
$ bin/bb.sh stop
{{Codesample|lang=shell-session|code=
Stopping bridgebot k8s deployment...
$ webservice shell
$ bin/bb.sh start
$ .local/bin/kirc -s bnc -p 6667 -n wm-bb -u wm-bridgebot/libera -k $password
Starting bridgebot k8s deployment...
?> @*status help
                  *status In the following list all occurrences of <#chan>
                          support wildcards (* and ?) except ListNicks
                  *status Version: Print which version of ZNC this is
                  *status ListMods: List all loaded modules
...
                  *status Shutdown [message]: Shut down ZNC completely
                  *status Restart [message]: Restart ZNC
?>
}}


:# Upgrading the golang binary
{{Codesample|name=$HOME/etc/bnc-deployment.yaml|lang=yaml|scheme=light|line=1|code=
$ cd $HOME/bin
---
$ wget https://github.com/42wim/matterbridge/releases/download/v{$version}/matterbridge-{$version}-linux-64bit
kind: Deployment
$ chmod a+x matterbridge-{$version}-linux-64bit
apiVersion: apps/v1
$ vim bb.sh
metadata:
  update the MATTERBRIDGE=... line to the new version
  name: bridgebot.bnc
  :wq
  namespace: tool-bridgebot
$ $HOME/bin/bb.sh restart
  labels:
    name: bridgebot.bnc
    toolforge: tool
spec:
  replicas: 1
  selector:
    matchLabels:
      name: bridgebot.bnc
      toolforge: tool
  template:
    metadata:
      labels:
        name: bridgebot.bnc
        toolforge: tool
    spec:
      containers:
        - name: bnc
          image: docker-registry.tools.wmflabs.org/toolforge-bullseye-sssd:latest
          resources:
            limits:
              cpu: 250m
              memory: 256Mi
            requests:
              cpu: 100m
              memory: 100Mi
          command:
            - /data/project/bridgebot/.local/bin/znc
            - --foreground
            - --datadir
            - /data/project/bridgebot/.znc
          workingDir: /data/project/bridgebot
          env:
            - name: HOME
              value: /data/project/bridgebot
          imagePullPolicy: Always
---
kind: Service
apiVersion: v1
metadata:
  name: bnc
spec:
  selector:
    name: bridgebot.bnc
  ports:
    - protocol: TCP
      port: 6667
      targetPort: 6667
}}
}}
=== Joining a new channel ===
Maintainers of the tool can configure the bot to join a new channel;
<syntaxhighlight lang="console">
$ ssh login.tools.wmflabs.org
$ become bridgebot
$ vim matterbridge.toml
:# Add a new "[[gateway]]" section defining the gateway name and the channels to bridge
$ kubectl delete po/$(kubectl get pods | grep Running | awk '{print $1}')
</syntaxhighlight>
==== Telegram ====
If one side of the bridge is Telegram you will need these things to be done:
# Have an admin of the Telegram channel invite the "@wmtelegram_bot" user to the channel
# Follow the log output of the bot: `kubectl logs -f $(kubectl get pods | grep Running | awk '{print $1}')`
# Have someone in the Telegram channel talk to the bot
# Collect the Telegram "Channel" id number from the DEBUG log output <pre>[85656] DEBUG telegram:    <= Message is config.Message{Text:"@wmtelegram_bot I need you to see this message so I can finish https://phabricator.wikimedia.org/T258078", Channel:"-1001308089610", Username:"bd808", UserID:"419968011", Avatar:"https://tools-static.wmflabs.org/bridgebot/4a263e14/419968011.png", Account:"telegram.bridgebot", Event:"", Protocol:"", Gateway:"", ParentID:"", Timestamp:time.Time{wall:0x0, ext:0, loc:(*time.Location)(nil)}, ID:"86", Extra:map[string][]interface {}{}}</pre>
==== Discord ====
If one side of the bridge is Discord you will need these things to be done:
# Have an admin of the Discord server invite the bot to their server using [https://discord.com/oauth2/authorize?client_id=744713247218860063&scope=bot&permissions=19456 the bot's invite link]


== remotenickformat.tengo ==
== remotenickformat.tengo ==
Line 128: Line 312:
A [https://github.com/d5/tengo tengo] script is used to do per-channel customization of nick formats used when cross-posting messages between services.
A [https://github.com/d5/tengo tengo] script is used to do per-channel customization of nick formats used when cross-posting messages between services.


Note: this script is read from disk each time the bot needs to send a message across a bridge, so edits should be made carefully. Any syntax errors in the script will stop messages from passing across all bridges until they are corrected.
Note: Any syntax errors in the script will stop messages from passing across all bridges until they are corrected.


{{Codesample|name=$HOME/remotenickformat.tengo|lang=go|scheme=light|code=
{{Codesample|name=$HOME/etc/remotenickformat.tengo|lang=go|scheme=light|code=
/**
/**
  * The script will have the following global variables:
  * The script will have the following global variables:

Latest revision as of 22:40, 5 August 2022

Toolforge tools
Crystal Clear app package utilities.png
Description A bot for bridging IRC and other chat platform channels
Keywords irc, golang
Maintainer(s) BryanDavis (View all)
Source code https://github.com/42wim/matterbridge
License Apache License 2.0
Issues Open tasks · Report a bug
Admin log Tools.bridgebot/SAL

Bridgebot is a deployment of the FLOSS matterbridge software. It can be used to relay messages between multiple different chat systems. The current deployment in Toolforge is bridging various Wikimedia related channels across platforms including Libera.Chat, Telegram, Discord, and Mattermost.

Bot accounts

The bot must be invited/added to chat channels in order to create bridges. Currently the bot has these accounts on various chat platforms:

libera.chat IRC
  • account: wm-bridgebot
  • nicks: wm-bridgebot, wm-bb
Telegram
Discord

Maintenance

The bot runs from Toolforge under the "bridgebot" account as a kubernetes pod.


$ ssh login.toolforge.org
$ become bridgebot

:# Deploying
$ bin/bb.sh start
Starting bridgebot k8s deployment...

:# Quick restart (pod delete)
$ bin/bb.sh restart
Restarting bridgebot pod...

:# "Full" restart (Deployment delete; Deployment create)
$ bin/bb.sh stop
Stopping bridgebot k8s deployment...
$ bin/bb.sh start
Starting bridgebot k8s deployment...

:# Upgrading the golang binary
$ bin/bb.sh download $version
$ vim bb.sh
  update the MATTERBRIDGE=... line to the new version
  :wq
$ bin/bb.sh restart "Upgrading matterbridge to $version"

Joining a new channel

Maintainers of the tool can configure the bot to join a new channel:

$ ssh login.tools.wmflabs.org
$ become bridgebot
$ vim etc/matterbridge.toml
:# Add a new "[[gateway]]" section defining the gateway name and the channels to bridge
$ bin/bb.sh restart

Telegram

If one side of the bridge is Telegram you will need these things to be done:

  1. Have an admin of the Telegram channel invite the "@wmtelegram_bot" user to the channel
  2. Have someone in the Telegram channel post the message /chatId (This command is case-sensitive.)
  3. Collect the Telegram "Channel" id number from @wmtelegram_bot's reply to the bot command

Discord

If one side of the bridge is Discord you will need these things to be done:

  1. Have an admin of the Discord server invite the bot to their server using the bot's invite link

Common problems

Duplicate messages being sent from irc to other bridges

The bot can get into a state where every message that it sees from irc gets sent multiple times to other bridged channels. This is caused by incorrect handling of irc server connection messages by the bot when the intermediate ZNC service reconnects to libra.chat. The fix is simply to restart the bot:

$ ssh login.toolforge.org
$ become bridgebot
$ bb.sh restart 'Double IRC messages to other bridges'

Technical details

bin/bb.sh

To make operating the bot less complicated for maintainers, we have a bin/bb.sh script to wrap the various Kubernetes commands. This same script is used as the command inside the bot's container to setup and run the matterbridge software when invoked as bin/bb.sh run. The run action copies the matterbridge binary and it's configuration into the container's /tmp directory so that while running there is no need to read or write to the tool's $HOME.

$HOME/bin/bb.sh
#!/usr/bin/env bash
# Management script for bridgebot kubernetes processes

set -e

MATTERBRIDGE=matterbridge-1.23.0-linux-64bit

DEPLOYMENT=bridgebot.bot
POD_NAME=bridgebot.bot

TOOL_DIR=$(cd $(dirname $0)/.. && pwd -P)
BIN_DIR=$TOOL_DIR/bin
CONFIG_DIR=$TOOL_DIR/etc

KUBECTL=/usr/bin/kubectl
_get_pod() {
    $KUBECTL get pods \
        --output=jsonpath={.items..metadata.name} \
        --selector=name=${POD_NAME}
}

case "$1" in
    start)
        echo "Starting bridgebot k8s deployment..."
        $KUBECTL create --validate=true -f ${CONFIG_DIR}/deployment.yaml
        [[ -n $2 ]] && dologmsg "$2"
        ;;
    run)
        # Execute bot inside container
        date +%Y-%m-%dT%H:%M:%S
        echo "Bootstrapping container..."
        cd ${TOOL_DIR}
        cp ${BIN_DIR}/${MATTERBRIDGE} /tmp
        chmod a+x /tmp/${MATTERBRIDGE}
        cp ${CONFIG_DIR}/matterbridge.toml /tmp
        cp ${CONFIG_DIR}/remotenickformat.tengo /tmp
        echo "Starting bridgebot..."
        cd /tmp
        exec /tmp/${MATTERBRIDGE} -debug -conf /tmp/matterbridge.toml
        ;;
    stop)
        echo "Stopping bridgebot k8s deployment..."
        $KUBECTL delete deployment ${DEPLOYMENT}
        [[ -n $2 ]] && dologmsg "$2"
        ;;
    restart)
        echo "Restarting bridgebot pod..."
        $KUBECTL delete pod $(_get_pod)
        [[ -n $2 ]] && dologmsg "$2"
        ;;
    status)
        echo "Active pods:"
        $KUBECTL get pods -l name=${POD_NAME}
        ;;
    tail)
        exec $KUBECTL logs -f $(_get_pod)
        ;;
    attach)
        echo "Attaching to pod..."
        exec $KUBECTL exec -i -t $(_get_pod) -- /bin/bash
        ;;
    version)
        echo "${BIN_DIR}/${MATTERBRIDGE}"
        "${BIN_DIR}/${MATTERBRIDGE}" -version
        ;;
    download)
        version=${2:?No version specified. Expected something like '1.22.1'}
        baseurl="https://github.com/42wim/matterbridge/releases/download"
        new="matterbridge-${version}-linux-64bit"
        if [[ -f "${BIN_DIR}/${new}" ]]; then
            read -p "${new} exists. Overwrite? [y/N]: " -n 1 -r
            if [[ ! $REPLY =~ ^[Yy]$ ]]; then
                exit 1
            fi
            echo
        fi
        echo "Downloading ${new}..."
        wget -O "${BIN_DIR}/${new}" "${baseurl}/v${version}/${new}"
        chmod a+x "${BIN_DIR}/${new}"
        echo "Downloaded $("${BIN_DIR}/${new}" -version)"
        ;;
    *)
        echo "Usage: $0 {start

deployment.apps/bridgebot.bot

The bot's Kubernetes container is managed by a custom deployment defined in $HOME/etc/deployment.yaml and applied by bin/bb.sh.

$HOME/etc/deployment.yaml
---
kind: Deployment
apiVersion: apps/v1
metadata:
  name: bridgebot.bot
  namespace: tool-bridgebot
  labels:
    name: bridgebot.bot
    toolforge: tool
spec:
  replicas: 1
  selector:
    matchLabels:
      name: bridgebot.bot
      toolforge: tool
  template:
    metadata:
      labels:
        name: bridgebot.bot
        toolforge: tool
    spec:
      containers:
        - name: bot
          image: docker-registry.tools.wmflabs.org/toolforge-buster-sssd:latest
          resources:
            limits:
              cpu: 1
              memory: 1Gi
            requests:
              cpu: 1
              memory: 1Gi
          command:
            - "/data/project/bridgebot/bin/bb.sh"
            - "run"
          workingDir: /data/project/bridgebot
          env:
            - name: HOME
              value: /data/project/bridgebot
          imagePullPolicy: Always

deployment.apps/bridgebot.bnc

After many issues with matterbridge's IRC client, we decided to place a bouncer (BNC) between matterbridge and libera.chat. This bouncer is running as a pod inside the tool's namespace and connected to a Kubernetes Service which allows the bot's pod to connect to it.

The specific BNC software currently used is ZNC. ZNC was compiled from inside a webservice ruby27 shell (ruby27 just happened to have all the -dev packages needed) and installed to $HOME/.local/bin/znc. ZNC's runtime configuration is stored in $HOME/.znc.

Configuration for ZNC can be managed by connecting to it with an IRC client running inside the tool's namespace. kirc has been compiled and installed to $HOME/.local/bin/kirc for this purpose. The password used to connect to the bouncer can be found in the $HOME/etc/matterbridge.toml configuration file.


$ webservice shell
$ .local/bin/kirc -s bnc -p 6667 -n wm-bb -u wm-bridgebot/libera -k $password
?> @*status help
                   *status In the following list all occurrences of <#chan>
                           support wildcards (* and ?) except ListNicks
                   *status Version: Print which version of ZNC this is
                   *status ListMods: List all loaded modules
...
                   *status Shutdown [message]: Shut down ZNC completely
                   *status Restart [message]: Restart ZNC
?>
$HOME/etc/bnc-deployment.yaml
---
kind: Deployment
apiVersion: apps/v1
metadata:
  name: bridgebot.bnc
  namespace: tool-bridgebot
  labels:
    name: bridgebot.bnc
    toolforge: tool
spec:
  replicas: 1
  selector:
    matchLabels:
      name: bridgebot.bnc
      toolforge: tool
  template:
    metadata:
      labels:
        name: bridgebot.bnc
        toolforge: tool
    spec:
      containers:
        - name: bnc
          image: docker-registry.tools.wmflabs.org/toolforge-bullseye-sssd:latest
          resources:
            limits:
              cpu: 250m
              memory: 256Mi
            requests:
              cpu: 100m
              memory: 100Mi
          command:
            - /data/project/bridgebot/.local/bin/znc
            - --foreground
            - --datadir
            - /data/project/bridgebot/.znc
          workingDir: /data/project/bridgebot
          env:
            - name: HOME
              value: /data/project/bridgebot
          imagePullPolicy: Always
---
kind: Service
apiVersion: v1
metadata:
  name: bnc
spec:
  selector:
    name: bridgebot.bnc
  ports:
    - protocol: TCP
      port: 6667
      targetPort: 6667

remotenickformat.tengo

A tengo script is used to do per-channel customization of nick formats used when cross-posting messages between services.

Note: Any syntax errors in the script will stop messages from passing across all bridges until they are corrected.

$HOME/etc/remotenickformat.tengo
/**
 * The script will have the following global variables:
 * to modify: result
 * to read: channel, bridge, gateway, protocol, nick
 */

ret := "[" + protocol + "] <" + nick + "> "

if gateway == "ukwiki-discord-telegram" {
  protos := immutable({
    discord: "дс",
    telegram: "тг"
  })
  proto := protos[protocol]
  ret = "[" + (proto == undefined ? protocol : proto) + "] <" + nick + "> "

} else if gateway == "wikipedia-abstract-irc-telegram" {
  ret = "<" + nick + "> "

}

result = ret