Merge branch 'master' of git.deuxfleurs.fr:Deuxfleurs/infrastructure

This commit is contained in:
LUXEY Adrien 2021-01-29 10:57:42 +01:00
commit 9a263b762b
52 changed files with 991 additions and 218 deletions

View File

@ -0,0 +1 @@
USER_LONG Private ed25519 key of the container doing the backup

View File

@ -0,0 +1 @@
USER Public ed25519 key of the container doing the backup (this key must be in authorized_keys on the backup target host)

View File

@ -0,0 +1 @@
USER Directory where to store backups on target host

View File

@ -0,0 +1 @@
USER SSH fingerprint of the target machine (format: copy here the corresponding line from your known_hosts file)

View File

@ -0,0 +1 @@
USER Hostname of the backup target host

View File

@ -0,0 +1 @@
USER SSH port number to connect to the target host

View File

@ -0,0 +1 @@
USER SSH username to log in as on the target host

View File

@ -48,33 +48,35 @@ services:
args:
# https://github.com/jitsi/jitsi-meet
PREFIXV: stable/jitsi-meet_
VERSION: 5390
image: superboum/amd64_jitsi_meet:v3
VERSION: 5463
image: superboum/amd64_jitsi_meet:v4
jitsi-conference-focus:
build:
context: ./jitsi/build/jitsi-conference-focus
args:
# https://github.com/jitsi/jicofo
PREFIXV: stable/jitsi-meet_
VERSION: 5390
image: superboum/amd64_jitsi_conference_focus:v6
PREFIXV: jitsi-meet_
VERSION: 5463
image: superboum/amd64_jitsi_conference_focus:v7
jitsi-videobridge:
build:
context: ./jitsi/build/jitsi-videobridge
args:
# https://github.com/jitsi/jitsi-videobridge
PREFIXV: stable/jitsi-meet_
VERSION: 5390
image: superboum/amd64_jitsi_videobridge:v16
PREFIXV: jitsi-meet_
VERSION: 5463
image: superboum/amd64_jitsi_videobridge:v17
jitsi-xmpp:
build:
context: ./jitsi/build/jitsi-xmpp
args:
VERSION: 0.11.2-1
image: superboum/amd64_jitsi_xmpp:v8
PREFIXV: jitsi-meet_
MEET_VERSION: 5463
PROSODY_VERSION: 0.11.7-1~buster4
image: superboum/amd64_jitsi_xmpp:v9
plume:
build:

View File

@ -0,0 +1 @@
USER_LONG garage-ca.crt (generated with Garage's genkeys.sh script)

View File

@ -0,0 +1 @@
USER_LONG garage-ca.key (generated with Garage's genkeys.sh script)

View File

@ -0,0 +1 @@
USER_LONG garage.crt (generated with Garage's genkeys.sh script)

View File

@ -0,0 +1 @@
USER_LONG garage.key (generated with Garage's genkeys.sh script)

View File

@ -0,0 +1 @@
CMD openssl rand -hex 32

View File

@ -0,0 +1 @@
SERVICE_PASSWORD easybridge

View File

@ -0,0 +1 @@
CONST easybridge

View File

@ -0,0 +1 @@
CMD openssl rand -hex 32

View File

@ -0,0 +1,2 @@
CMD openssl rand -hex 32

View File

@ -1 +1 @@
USER fb2mx API server token
CMD openssl rand -hex 32

View File

@ -1 +1 @@
USER fb2mx homeserver token
CMD openssl rand -hex 32

View File

@ -0,0 +1 @@
USER Synapse homeserver ed25519 signing key

View File

@ -1 +1 @@
USER Shared secret for homeserver registrations (?)
CMD head -c 32 /dev/urandom | base64

View File

@ -1,11 +1,10 @@
FROM debian:buster AS builder
FROM fedora:33 AS builder
RUN dnf install -y java-latest-openjdk-headless maven wget unzip
ARG PREFIXV
ARG VERSION
RUN apt-get update && \
apt-get install -y openjdk-11-jdk maven wget unzip && \
wget https://github.com/jitsi/jicofo/archive/${PREFIXV}${VERSION}.zip -O jicofo.zip
RUN wget https://github.com/jitsi/jicofo/archive/${PREFIXV}${VERSION}.zip -O jicofo.zip
RUN unzip jicofo.zip && \
mv jicofo*${VERSION} jicofo && \
cd jicofo && \
@ -13,15 +12,12 @@ RUN unzip jicofo.zip && \
unzip target/jicofo-1.1-SNAPSHOT-archive.zip && \
mv jicofo-1.1-SNAPSHOT /srv/build
FROM debian:buster
FROM debian:bullseye
RUN apt-get update && \
apt-get install -y openjdk-11-jre-headless ca-certificates
ENV JAVA_SYS_PROPS="-Dnet.java.sip.communicator.SC_HOME_DIR_LOCATION=/root -Dnet.java.sip.communicator.SC_HOME_DIR_NAME=.sip-communicator -Dnet.java.sip.communicator.SC_LOG_DIR_LOCATION=/var/log/jitsi"
COPY --from=builder /srv/build /srv/jicofo
COPY jicofo /usr/local/bin/jicofo
COPY sip-communicator.properties /root/.sip-communicator/sip-communicator.properties
COPY --from=builder /srv/build /usr/share/jicofo
COPY jicofo /usr/local/bin
CMD ["/usr/local/bin/jicofo"]

View File

@ -1,16 +1,13 @@
#!/bin/bash
cp ${JITSI_CERTS_FOLDER}/auth.jitsi.deuxfleurs.fr.crt /usr/local/share/ca-certificates/auth.jitsi.deuxfleurs.fr.crt
update-ca-certificates -f
cat >> /etc/hosts <<EOF
${JITSI_PROSODY_HOST} jitsi.deuxfleurs.fr conference.jitsi.deuxfleurs.fr jitsi-videobridge.jitsi.deuxfleurs.fr focus.jitsi.deuxfleurs.fr auth.jitsi.deuxfleurs.fr
127.0.0.1 `hostname`
EOF
/srv/jicofo/jicofo.sh \
--host=${JITSI_PROSODY_HOST} \
--domain=jitsi.deuxfleurs.fr \
--secret=${JITSI_SECRET_JICOFO_COMPONENT} \
--user_domain=auth.jitsi.deuxfleurs.fr \
--user_password=${JITSI_SECRET_JICOFO_USER}
exec java \
-Xmx400m \
-XX:+HeapDumpOnOutOfMemoryError \
-XX:HeapDumpPath=/tmp \
-Djdk.tls.ephemeralDHKeySize=2048 \
-Djava.util.logging.config.file=/usr/share/jicofo/lib/logging.properties \
-Dconfig.file=/etc/jitsi/jicofo.conf \
-cp "/usr/share/jicofo/*:/usr/share/jicofo/lib/*" \
org.jitsi.jicofo.Main

View File

@ -1,2 +0,0 @@
org.jitsi.jicofo.SHORT_ID=1
org.jitsi.jicofo.BRIDGE_MUC=JvbBrewery@internal.auth.jitsi.deuxfleurs.fr

View File

@ -1,13 +1,38 @@
FROM debian:buster as builder
WORKDIR /tmp
ARG MEET_VERSION
ARG PREFIXV
RUN apt-get update && \
apt-get install -y wget unzip
RUN wget https://github.com/jitsi/jitsi-meet/archive/${PREFIXV}${MEET_VERSION}.zip -O meet.zip
RUN unzip meet.zip && \
mv jitsi-meet-* jitsi-meet
FROM debian:buster
ARG VERSION
ARG PROSODY_VERSION
RUN apt-get update && \
apt-get install -y prosody=${VERSION}
apt-get install -y wget gnupg2 && \
echo deb http://packages.prosody.im/debian buster main \
| tee -a /etc/apt/sources.list && \
wget https://prosody.im/files/prosody-debian-packages.key -O - \
| apt-key add - && \
apt-get update && \
apt-get install -y prosody=${PROSODY_VERSION} lua-event
COPY external_components.cfg.lua /etc/prosody/conf.d/external_components.cfg.lua
COPY xmpp_conf /usr/local/bin/xmpp_conf
COPY xmpp_gen /usr/local/bin/xmpp_gen
COPY xmpp_run /usr/local/bin/xmpp_run
RUN mkdir -p /usr/local/share/ca-certificates/ && \
ln -sf \
/var/lib/prosody/certs/auth.jitsi.crt \
/usr/local/share/ca-certificates/auth.jitsi.crt && \
mkdir /run/prosody && \
touch /run/prosody/prosody.pid && \
mkdir -p /var/lib/prosody && \
chown -R prosody:prosody /var/lib/prosody /run/prosody
CMD ["/usr/local/bin/xmpp_run"]
COPY --from=builder /tmp/jitsi-meet/resources/prosody-plugins /usr/share/jitsi-meet/prosody-plugins/
COPY xmpp_prosody /usr/local/bin/xmpp_prosody
WORKDIR /var/lib/prosody
USER prosody
CMD ["/usr/local/bin/xmpp_prosody"]

View File

@ -1,2 +0,0 @@
component_ports = { 5347 }
component_interface = "0.0.0.0"

View File

@ -1,49 +0,0 @@
#!/bin/bash
cat >> /etc/hosts <<EOF
${JITSI_PROSODY_HOST} jitsi.deuxfleurs.fr conference.jitsi.deuxfleurs.fr jitsi-videobridge.jitsi.deuxfleurs.fr focus.jitsi.deuxfleurs.fr auth.jitsi.deuxfleurs.fr
127.0.0.1 `hostname`
EOF
mkdir -p /etc/prosody/conf.{d,avail}/
cat > /etc/prosody/conf.avail/jitsi.deuxfleurs.fr.cfg.lua <<EOF
http_ports = { ${JITSI_PROSODY_BOSH_PORT} }
VirtualHost "jitsi.deuxfleurs.fr"
authentication = "anonymous"
ssl = {
key = "/var/lib/prosody/jitsi.deuxfleurs.fr.key";
certificate = "/var/lib/prosody/jitsi.deuxfleurs.fr.crt";
}
modules_enabled = {
"bosh";
"pubsub";
}
c2s_require_encryption = false
VirtualHost "auth.jitsi.deuxfleurs.fr"
ssl = {
key = "/var/lib/prosody/auth.jitsi.deuxfleurs.fr.key";
certificate = "/var/lib/prosody/auth.jitsi.deuxfleurs.fr.crt";
}
authentication = "internal_plain"
admins = { "focus@auth.jitsi.deuxfleurs.fr"}
Component "conference.jitsi.deuxfleurs.fr" "muc"
Component "internal.auth.jitsi.deuxfleurs.fr" "muc"
storage = "memory"
modules_enabled = { "ping"; }
admins = { "focus@auth.jitsi.deuxfleurs.fr", "jvb@auth.jitsi.deuxfleurs.fr" }
Component "jitsi-videobridge.jitsi.deuxfleurs.fr"
component_secret = "${JITSI_SECRET_VIDEOBRIDGE}"
Component "focus.jitsi.deuxfleurs.fr"
component_secret = "${JITSI_SECRET_JICOFO_COMPONENT}"
EOF
ln -sf \
/etc/prosody/conf.avail/jitsi.deuxfleurs.fr.cfg.lua \
/etc/prosody/conf.d/jitsi.deuxfleurs.fr.cfg.lua

View File

@ -1,9 +0,0 @@
#!/bin/bash
/usr/local/bin/xmpp_conf
prosodyctl cert generate jitsi.deuxfleurs.fr
prosodyctl cert generate auth.jitsi.deuxfleurs.fr
cp /var/lib/prosody/*.crt ${JITSI_CERTS_FOLDER}
cp /var/lib/prosody/*.key ${JITSI_CERTS_FOLDER}

View File

@ -0,0 +1,9 @@
#!/bin/bash
prosodyctl register focus auth.jitsi ${JICOFO_AUTH_PASSWORD}
prosodyctl register jvb auth.jitsi ${JVB_AUTH_PASSWORD}
# copied from jitsi-meet.postinst
# Make sure the focus@auth user's roster includes the proxy component (this is idempotent)
prosodyctl mod_roster_command subscribe focus.jitsi focus@auth.jitsi
exec prosody

View File

@ -1,20 +0,0 @@
#!/bin/bash
/usr/local/bin/xmpp_conf
cp ${JITSI_CERTS_FOLDER}/* /var/lib/prosody/
chown -R prosody:prosody /var/lib/prosody
mkdir -p /usr/local/share/ca-certificates/
ln -sf \
/var/lib/prosody/auth.jitsi.deuxfleurs.fr.crt \
/usr/local/share/ca-certificates/auth.jitsi.deuxfleurs.fr.crt
prosodyctl register focus auth.jitsi.deuxfleurs.fr ${JITSI_SECRET_JICOFO_USER}
prosodyctl register jvb auth.jitsi.deuxfleurs.fr ${JITSI_SECRET_VIDEOBRIDGE}
mkdir /run/prosody
touch /run/prosody/prosody.pid
chown -R prosody:prosody /run/prosody
cd /var/lib/prosody
su - prosody -s /bin/bash -c prosody

View File

@ -5,6 +5,6 @@ JITSI_PROSODY_BOSH_PORT={{ env "NOMAD_PORT_bosh_port" }}
JITSI_PROSODY_BOSH_HOST=127.0.0.1
JITSI_PROSODY_HOST=127.0.0.1
JITSI_CERTS_FOLDER=/secrets/certs/
JITSI_NAT_PUBLIC_IP=82.253.205.190
JITSI_NAT_PUBLIC_IP=78.197.205.190
JITSI_NAT_LOCAL_IP={{ env "NOMAD_IP_video1_port" }}
NGINX_PORT={{ env "NOMAD_PORT_https_port" }}

View File

@ -14,7 +14,7 @@ job "jitsi" {
port "ext_port" { static = 5347 }
port "xmpp_port" { static = 5222 }
port "https_port" { }
port "video1_port" { static = 8080 }
port "video1_port" { static = 8081 }
port "video2_port" { static = 10000 }
}
@ -189,7 +189,7 @@ job "jitsi" {
env {
#JITSI_DEBUG = 1
JITSI_VIDEO_TCP = 8080
JITSI_VIDEO_TCP = 8081
VIDEOBRIDGE_MAX_MEMORY = "1450m"
}
@ -205,7 +205,7 @@ job "jitsi" {
}
service {
tags = [ "jitsi", "(diplonat (tcp_port 8080))" ]
tags = [ "jitsi", "(diplonat (tcp_port 8081))" ]
port = "video1_port"
address_mode = "host"
name = "jitsi-videobridge-video1"

View File

@ -1,8 +0,0 @@
version: '3'
services:
jitsi-xmpp:
image: superboum/amd64_jitsi_xmpp:v2
command: ["/usr/local/bin/xmpp_gen"]
volumes: [ './jitsi-certs/:/certs:rw' ]
env_file: [ 'dev.env' ]

View File

@ -1,27 +0,0 @@
version: '3.4'
services:
jitsi-xmpp:
image: superboum/amd64_jitsi_xmpp:v3
ports:
- "5222:5222"
- "5347:5347"
- "5280:5280"
env_file: [ 'dev.env' ]
volumes: [ './jitsi-certs/:/certs:ro' ]
jitsi-meet:
image: superboum/amd64_jitsi_meet:v1
ports:
- "443:443"
env_file: [ 'dev.env' ]
volumes: [ './jitsi-certs/:/certs:ro' ]
jitsi-conference-focus:
image: superboum/amd64_jitsi_conference_focus:v4
env_file: [ 'dev.env' ]
volumes: [ './jitsi-certs/:/certs:ro' ]
jitsi-videobridge:
image: superboum/amd64_jitsi_videobridge:v14
ports:
- "8080:8080/tcp"
- "10000:10000/udp"
env_file: [ 'dev.env' ]
volumes: [ './jitsi-certs/:/certs:ro' ]

View File

@ -1,26 +0,0 @@
This installation is inspired by: https://github.com/jitsi/jitsi-meet/blob/master/doc/manual-install.md
To build images:
```
docker-compose -f 02_run.yml build
```
To gen the certs:
```
docker-compose -f 01_gen_certs.yml up --force-recreate
```
To run the stack:
```
docker-compose -f 02_run.yml up --force-recreate
```
To push the stack on the docker registry:
```
docker-compose -f 02_run.yml push
```

View File

@ -1,10 +0,0 @@
JITSI_SECRET_VIDEOBRIDGE=S3CR3T01
JITSI_SECRET_JICOFO_COMPONENT=S3CR3T02
JITSI_SECRET_JICOFO_USER=S3CR3T03
JITSI_PROSODY_BOSH_PORT=5280
JITSI_PROSODY_BOSH_HOST=172.17.0.1
JITSI_PROSODY_HOST=172.17.0.1
JITSI_CERTS_FOLDER=/certs/
JITSI_NAT_PUBLIC_IP=37.164.35.154
JITSI_NAT_LOCAL_IP=192.168.0.231
JITSI_VIDEO_TCP=8080

View File

@ -1,2 +0,0 @@
*
!.gitignore

View File

@ -0,0 +1,68 @@
## About Jitsi
Several server components:
- prosody XMPP (ext)
- jitsi videobridge aka JVB
- jitsi conference focus aka jicofo aka focus
- jitsi meet
- octo
- jigasi
- jibri
- etc.
Some libs:
- libjitsi
- jicoco
- jitsi-utils
- etc.
Client components:
- jitsi meet electron
- jitsi android/ios
- etc.
## Conf
Base conf:
- [videobridge.conf](https://github.com/jitsi/jitsi-videobridge/blob/master/jvb/src/main/resources/reference.conf)
- [jicofo.conf](https://github.com/jitsi/jicofo/blob/master/src/main/resources/reference.conf)
the following is used in videobridge.conf:
[jicoco/MucClientConfiguration](https://github.com/jitsi/jicoco/blob/master/jicoco/src/main/java/org/jitsi/xmpp/mucclient/MucClientConfiguration.java)
How the new configuration is read in jicoco:
https://github.com/jitsi/jicoco/blob/master/jicoco-config/src/main/kotlin/org/jitsi/config/JitsiConfig.kt#L83-L91
They use this library: https://github.com/lightbend/config
We are particularly interested by: https://github.com/lightbend/config#standard-behavior
Using 'application.conf' with classpath does not seem to work.
But, specifying the file path as `-Dconfig.file=/etc/jitsi/jicofo.conf` works!
Some parameters are also set independently of lightbend hocon config.
They are seen in jicofo entrypoint:
https://github.com/jitsi/jicofo/blob/master/src/main/java/org/jitsi/jicofo/Main.java
Many of these parameters can be in fact read from the HOCON file except one: the `--secret` parameter or the `JICOFO_SECRET` env variable.
But we can see this is a deprecated thing, it has been already removed from master: https://github.com/jitsi/jicofo/commit/c9e5b50a8b4e77f8b8cb8831a4a044a53edfcf48
For now (as per v5390) we will keep `JICOFO_SECRET` environment variable but will assume no other environment variable is set
But maybe this value is deprecated: the check is still here but it is not used anymore?!
## Generate certs with prosody
```
prosodyctl cert generate auth.jitsi
prosodyctl cert generate jitsi
```
## An example prosody configuration file
https://github.com/jitsi/jitsi-meet/blob/master/doc/example-config-files/prosody.cfg.lua.example
but this one is not the one used by the [debian postinst script](https://github.com/jitsi/jitsi-meet/blob/master/debian/jitsi-meet-prosody.postinst)
instead, we should look at this one: https://github.com/jitsi/jitsi-meet/blob/master/doc/debian/jitsi-meet-prosody/prosody.cfg.lua-jvb.example
Jitsi can be configured to authenticated through tokens,
the postinst file is here: https://github.com/jitsi/jitsi-meet/blob/master/debian/jitsi-meet-tokens.postinst
## Resources to understand jitsi
- [jicofo/debian/postinst](https://github.com/jitsi/jicofo/blob/master/debian/postinst)
- [videobridge/debian/postinst](https://github.com/jitsi/jitsi-videobridge/blob/master/debian/postinst)

View File

@ -0,0 +1,37 @@
version: '3.4'
services:
jitsi-xmpp:
image: superboum/amd64_jitsi_xmpp:v9
volumes:
- "./prosody/prosody.cfg.lua:/etc/prosody/prosody.cfg.lua:ro"
- "./prosody/certs/jitsi.crt:/var/lib/prosody/jitsi.crt:ro"
- "./prosody/certs/jitsi.key:/var/lib/prosody/jitsi.key:ro"
- "./prosody/certs/auth.jitsi.crt:/var/lib/prosody/auth.jitsi.crt:ro"
- "./prosody/certs/auth.jitsi.key:/var/lib/prosody/auth.jitsi.key:ro"
environment:
- JICOFO_AUTH_PASSWORD=jicofopass
- JVB_AUTH_PASSWORD=jvbpass
jitsi-conference-focus:
image: superboum/amd64_jitsi_conference_focus:v7
volumes:
- "./prosody/certs/auth.jitsi.crt:/usr/local/share/ca-certificates/auth.jitsi.crt:ro"
- "./jicofo/jicofo.conf:/etc/jitsi/jicofo.conf:ro"
environment:
- JDOMAIN=jitsi
- JHOST=jitsi-xmpp
- JPORT=5347
- JSUBDOMAIN=focus
- JICOFO_SECRET=jicofosecretpass
- JUSERDOMAIN=auth.jitsi
- JUSERNAME=focus
- JICOFO_AUTH_PASSWORD=jicofopass
# jitsi-meet:
# image: superboum/amd64_jitsi_meet:v1
# ports:
# - "443:443"
# jitsi-videobridge:
# image: superboum/amd64_jitsi_videobridge:v14
# ports:
# - "8080:8080/tcp"
# - "10000:10000/udp"

View File

@ -0,0 +1,273 @@
jicofo {
// Authentication with external services
authentication {
enabled = false
// The type of authentication. Supported values are XMPP, JWT or SHIBBOLETH (default).
type = SHIBBOLETH
// The pattern of authentication URL. See ShibbolethAuthAuthority for more information.
# login-url =
# logout-url =
authentication-lifetime = 24 hours
enable-auto-login = true
}
// Configuration related to jitsi-videobridge
bridge {
// The maximum number of participants in a single conference to put on one bridge (use -1 for no maximum).
max-bridge-participants = -1
// The assumed maximum packet rate that a bridge can handle.
max-bridge-packet-rate = 50000
// The assumed average packet rate per participant.
average-participant-packet-rate-pps = 500
// The assumed average stress per participant.
average-participant-stress = 0.01
// The assumed time that an endpoint takes to start contributing fully to the load on a bridge. To avoid allocating
// a burst of endpoints to the same bridge, the bridge stress is adjusted by adding the number of new endpoints
// in the last [participant-rampup-time] multiplied by [average-participant-stress].
participant-rampup-interval = 20 seconds
// The stress level above which a bridge is considered overstressed.
stress-threshold = 0.8
// The amount of to wait before retrying using a failed bridge.
failure-reset-threshold = 1 minute
// The bridge selection strategy. The built-in strategies are:
// SingleBridgeSelectionStrategy: Use the least loaded bridge, do not split a conference between bridges (Octo).
// SplitBridgeSelectionStrategy: Use a separate bridge for each participant (for testing).
// RegionBasedBridgeSelectionStrategy: Attempt to put each participant in a bridge in their local region (i.e. use
// Octo for geo-location).
// IntraRegionBridgeSelectionStrategy: Use additional bridges when a bridge becomes overloaded (i.e. use Octo for
// load balancing).
//
// Additionally, you can use the fully qualified class name for custom BridgeSelectionStrategy implementations.
selection-strategy = SingleBridgeSelectionStrategy
health-checks {
// Whether jicofo should perform periodic health checks to the connected bridges.
enabled = true
// The interval at which to perform health checks.
interval = 10 seconds
// When a health checks times out, jicofo will retry and only consider it fail after the retry fails. This
// configures the delay between the original health check timing out and the second health check being sent.
// It is a duration and defaults to half the [interval].
# retry-delay = 5 seconds
}
// The JID of the MUC to be used as a brewery for bridge instances.
brewery-jid = "jvbbrewery@jitsi"
}
// Configure the codecs and RTP extensions to be used in the offer sent to clients.
codec {
video {
vp8 {
enabled = true
pt = 100
// Payload type for the associated RTX stream. Set to -1 to disable RTX.
rtx-pt = 96
}
vp9 {
enabled = true
pt = 101
// Payload type for the associated RTX stream. Set to -1 to disable RTX.
rtx-pt = 97
}
h264 {
enabled = true
pt = 107
// Payload type for the associated RTX stream. Set to -1 to disable RTX.
rtx-pt = 99
}
}
audio {
isac-16000 {
enabled = true
pt = 103
}
isac-32000 {
enabled = true
pt = 104
}
opus {
enabled = true
pt = 111
minptime = 10
use-inband-fec = true
red {
enabled = false
pt = 112
}
}
telephone-event {
enabled = true
pt = 126
}
}
// RTP header extensions
rtp-extensions {
audio-level {
enabled = true
id = 1
}
tof {
// TOF is currently disabled, because we don't support it in the bridge
// (and currently clients seem to not use it when abs-send-time is
// available).
enabled = false
id = 2
}
abs-send-time {
enabled = true
id = 3
}
rid {
enabled = false
id = 4
}
tcc {
enabled = true
id = 5
}
video-content-type {
enabled = false
id = 7
}
framemarking {
enabled = false
id = 9
}
}
}
conference {
// Whether to automatically grant the 'owner' role to the first participant in the conference (and subsequently to
// the next in line when the current owner leaves).
enable-auto-owner = true
// How long to wait for the initial participant in a conference.
initial-timeout = 15 seconds
// Whether jicofo should inject a random SSRC for endpoints which don't advertise any SSRCs. This is a temporary
// workaround for an issue with signaling endpoints for Octo.
inject-ssrc-for-recv-only-endpoints = false
max-ssrcs-per-user = 20
// How long a participant's media session will be kept alive once it remains the only participant in the room.
single-participant-timeout = 20 seconds
// The minimum number of participants required for the conference to be started.
min-participants = 2
// Experimental.
enable-lip-sync = false
shared-document {
// If `true` the shared document uses a random name. Otherwise, it uses the conference name.
use-random-name = false
}
}
// Configuration for the internal health checks performed by jicofo.
health {
// Whether to perform health checks.
enabled = false
// The interval between health checks. If set to 0, periodic health checks will not be performed.
interval = 10 seconds
# The timeout for a health check
timeout = 30 seconds
# If performing a health check takes longer than this, it is considered unsuccessful.
max-check-duration = 20 seconds
# The prefix to use when creating MUC rooms for the purpose of health checks.
room-name-prefix = "__jicofo-health-check"
}
jibri {
// The JID of the MUC to be used as a brewery for jibri instances for streaming.
# brewery-jid = "jibribrewery@example.com"
// How many times to retry a given Jibri request before giving up. Set to -1 to allow infinite retries.
num-retries = 5
// How long to wait for Jibri to start recording from the time it accepts a START request.
pending-timeout = 90 seconds
}
jibri-sip {
// The JID of the MUC to be used as a brewery for jibri instances for SIP.
# brewery-jid = "jibrisipbrewery@example.com"
}
jigasi {
// The JID of the MUC to be used as a brewery for jigasi instances.
# brewery-jid = "jigasibrewery@example.com"
}
// The region in which the machine is running.
#local-region="us-east-1"
octo {
// Whether or not to use Octo. Note that when enabled, its use will be determined by
// $jicofo.bridge.selection-strategy.
enabled = false
// An identifier of the Jicofo instance, used for the purpose of generating conference IDs unique across a set of
// Jicofo instances. Valid values are [1, 65535]. The value 0 is used when none is explicitly configured.
id = 1
}
rest {
port = 8888
tls-port = 8843
}
sctp {
// Whether to allocate SCTP channels on the bridge (only when the client advertises support, and SCTP is
// enabled in the per-conference configuration).
enabled = true
}
task-pools {
shared-pool-max-threads = 1500
}
xmpp {
// The separate XMPP connection used for communication with clients (endpoints).
client {
enabled = true
hostname = "jitsi-xmpp"
port = 5222
domain = "auth.jitsi"
username = "focus"
password = "jicofopass"
// How long to wait for a response to a stanza before giving up.
reply-timeout = 15 seconds
// The JID/domain of the MUC service used for conferencing.
conference-muc-jid = conference.jitsi
// A flag to suppress the TLS certificate verification.
disable-certificate-verification = false
}
// The separate XMPP connection used for internal services (currently only jitsi-videobridge).
service {
enabled = true
hostname = "jitsi-xmpp"
port = 5222
domain = "auth.jitsi"
username = "focus"
password = "jicofopass"
// How long to wait for a response to a stanza before giving up.
reply-timeout = 15 seconds
// A flag to suppress the TLS certificate verification.
disable-certificate-verification = false
}
}
}

View File

@ -0,0 +1,279 @@
videobridge {
entity-expiration {
# If an entity has no activity after this timeout, it is expired
timeout=1 minute
# The interval at which the videobridge will check for expired entities
check-interval=${videobridge.entity-expiration.timeout}
}
health {
# The interval between health checks
interval=10 seconds
# The timeout for a health check
timeout=30 seconds
# If performing a health check takes longer than this, it is considered unsuccessful.
max-check-duration=3 seconds
# Whether or not health check failures should be 'sticky'
# (i.e. once the bridge becomes unhealthy, it will never
# go back to a healthy state)
sticky-failures=false
}
ep-connection-status {
# How long we'll wait for an endpoint to *start* sending
# data before we consider it 'inactive'
first-transfer-timeout=15 seconds
# How long an endpoint can be 'inactive' before it will
# be considered disconnected
max-inactivity-limit=3 seconds
# How often we check endpoint's connectivity status
check-interval=500 milliseconds
}
cc {
bwe-change-threshold=0.15
thumbnail-max-height-px=180
onstage-ideal-height-px=1080
onstage-preferred-height-px=360
onstage-preferred-framerate=30
enable-onstage-video-suspend=false
trust-bwe=true
# How often we check to send probing data
padding-period=15ms
# How often we'll force recalculations of forwarded
# streams
max-time-between-calculations = 15 seconds
# A JVB-wide last-n value, observed by all endpoints. Endpoints
# will take the minimum of their setting and this one (-1 implies
# no last-n limit)
jvb-last-n = -1
}
# The APIs by which the JVB can be controlled
apis {
xmpp-client {
# The interval at which presence is published in the configured MUCs.
presence-interval = ${videobridge.stats.interval}
configs {
# example-connection-id {
# For the properties which should be
# filled out here, see MucClientConfiguration
# }
}
}
# The COLIBRI REST API
rest {
enabled = false
}
jvb-api {
enabled = false
}
}
# Configuration of the different REST APIs.
# Note that the COLIBRI REST API is configured under videobridge.apis.rest instead.
rest {
debug {
enabled = true
}
health {
enabled = true
}
shutdown {
# Note that the shutdown API requires the COLIBRI API to also be enabled.
enabled = false
}
version {
enabled = true
}
}
http-servers {
# The HTTP server which hosts services intended for 'public' use
# (e.g. websockets for the bridge channel connection)
public {
# See JettyBundleActivatorConfig in Jicoco for values
port = -1
tls-port = -1
}
# The HTTP server which hosts services intended for 'private' use
# (e.g. health or debug stats)
private {
# See JettyBundleActivatorConfig in Jicoco for values
host = 127.0.0.1
}
}
octo {
# Whether or not Octo is enabled
enabled=false
# A string denoting the 'region' of this JVB. This region
# will be used by Jicofo in the selection of a bridge for
# a client by comparing it to the client's region.
# Must be set when 'enabled' is true
#region="us-west-1"
# The address on which the Octo relay should bind
# Must be set when 'enabled' is true
#bind-address=198.51.100.1
# The port to which the Octo relay should bind
bind-port=4096
# The address which controls the public address which
# will be part of the Octo relayId
#public-address=198.51.100.1
# The size of the incoming octo queue. This queue is per-remote-endpoint,
# so it matches what we use for local endpoints
recv-queue-size=1024
# The size of the outgoing octo queue. This is a per-originating-endpoint
# queue, so assuming all packets are routed (as they currently are for Octo)
# it should be the same size as the transceiver recv queue in
# jitsi-media-transform. Repeating the description from there:
# Assuming 300pps for high-definition, 200pps for standard-definition,
# 100pps for low-definition and 50pps for audio, this queue is fed
# 650pps, so its size in terms of millis is 1024/650*1000 ~= 1575ms.
send-queue-size=1024
}
load-management {
# Whether or not the reducer will be enabled to take actions to mitigate load
reducer-enabled = false
load-measurements {
packet-rate {
# The packet rate at which we'll consider the bridge overloaded
load-threshold = 50000
# The packet rate at which we'll consider the bridge 'underloaded' enough
# to start recovery
recovery-threshold = 40000
}
}
load-reducers {
last-n {
# The factor by which we'll reduce the current last-n when trying to reduce load
reduction-scale = .75
# The factor by which we'll increase the current last-n when trying to recover
recover-scale = 1.25
# The minimum time in between runs of the last-n reducer to reduce or recover from
# load
impact-time = 1 minute
# The lowest value we'll set for last-n
minimum-last-n-value = 0
# The highest last-n value we'll enforce. Once the enforced last-n exceeds this value
# we'll remove the limit entirely
maximum-enforced-last-n-value = 40
}
}
}
sctp {
# Whether SCTP data channels are enabled.
enabled=true
}
stats {
# Whether periodic collection of statistics is enabled or not. When enabled they are accessible through the REST
# API (at `/colibri/stats`), and are available to other modules (e.g. to be pushed to callstats or in a MUC).
enabled = false
# The interval at which stats are gathered.
interval = 5 seconds
# Configuration related to pushing statistics to callstats.io.
callstats {
# An integer application ID (use 0 to disable pushing stats to callstats).
app-id = 0
# The shared secred to authentication with callstats.io.
//app-secret = "s3cret"
# ID of the key that was used to generate token.
//key-id = "abcd"
# The path to private key file.
//key-path = "/etc/jitsi/videobridge/ecpriv.jwk"
# The ID of the server instance to be used when reporting to callstats.
bridge-id = "jitsi"
# TODO: document
//conference-id-prefix = "abcd"
# The interval at which statististics will be published to callstats. This affects both per-conference and global
# statistics.
# Note that this value will be overriden if a "callstatsio" transport is defined in the parent "stats" section.
interval = ${videobridge.stats.interval}
}
}
websockets {
enabled=false
server-id="default-id"
# Optional, even when 'enabled' is set to true
# tls=true
# Must be set when enabled = true
#domain="some-domain"
}
ice {
tcp {
# Whether ICE/TCP is enabled.
enabled = true
# The port to bind to for ICE/TCP.
port = 8080
# An optional additional port to advertise.
# mapped-port = 8443
# Whether to use "ssltcp" or plain "tcp".
ssltcp = true
}
udp {
# The port for ICE/UDP.
port = 10000
}
# An optional prefix to include in STUN username fragments generated by the bridge.
#ufrag-prefix = "jvb-123:"
# Which candidate pairs to keep alive. The accepted values are defined in ice4j's KeepAliveStrategy:
# "selected_and_tcp", "selected_only", or "all_succeeded".
keep-alive-strategy = "selected_and_tcp"
# Whether to use the "component socket" feature of ice4j.
use-component-socket = true
# Whether to attempt DNS resolution for remote candidates that contain a non-literal address. When set to 'false'
# such candidates will be ignored.
resolve-remote-candidates = false
# The nomination strategy to use for ICE. THe accepted values are defined in ice4j's NominationStrategy:
# "NominateFirstValid", "NominateHighestPriority", "NominateFirstHostOrReflexiveValid", or "NominateBestRTT".
nomination-strategy = "NominateFirstValid"
}
transport {
send {
# The size of the dtls-transport outgoing queue. This is a per-participant
# queue. Packets from the egress end-up in this queue right before
# transmission by the outgoing srtp pipeline (which mainly consists of the
# packet sender).
#
# Its size needs to be of the same order of magnitude as the rtp sender
# queue. In a 100 participant call, assuming 300pps for the on-stage and
# 100pps for low-definition, last-n 20 and 2 participants talking, so
# 2*50pps for audio, this queue is fed 300+19*100+2*50 = 2300pps, so its
# size in terms of millis is 1024/2300*1000 ~= 445ms.
queue-size=1024
}
}
version {
// Wheather to announe the jitsi-videobridge version to clients in the ServerHello message.
announce = false
}
}

View File

@ -0,0 +1,106 @@
plugin_paths = { "/usr/share/jitsi-meet/prosody-plugins/" }
log = {
--log less on console with warn="*console"; or err="*console" or more with debug="*console"
debug="*console";
}
daemonize = false
use_libevent = true
-- domain mapper options, must at least have domain base set to use the mapper
muc_mapper_domain_base = "jitsi.deuxfleurs.fr";
--@FIXME would be great to configure it
--turncredentials_secret = "__turnSecret__";
--turncredentials = {
-- { type = "stun", host = "jitmeet.example.com", port = "3478" },
-- { type = "turn", host = "jitmeet.example.com", port = "3478", transport = "udp" },
-- { type = "turns", host = "jitmeet.example.com", port = "5349", transport = "tcp" }
--};
cross_domain_bosh = false;
consider_bosh_secure = true;
https_ports = { }; -- Remove this line to prevent listening on port 5284
component_interface = "0.0.0.0"
component_ports = { 5347 }
http_ports = { 5280 }
-- https://ssl-config.mozilla.org/#server=haproxy&version=2.1&config=intermediate&openssl=1.1.0g&guideline=5.4
ssl = {
protocol = "tlsv1_2+";
ciphers = "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384"
}
VirtualHost "jitsi"
enabled = true -- Remove this line to enable this host
authentication = "anonymous"
-- Properties below are modified by jitsi-meet-tokens package config
-- and authentication above is switched to "token"
--app_id="example_app_id"
--app_secret="example_app_secret"
-- Assign this host a certificate for TLS, otherwise it would use the one
-- set in the global section (if any).
-- Note that old-style SSL on port 5223 only supports one certificate, and will always
-- use the global one.
ssl = {
key = "/var/lib/prosody/jitsi.key";
certificate = "/var/lib/prosody/jitsi.crt";
}
speakerstats_component = "speakerstats.jitsi"
conference_duration_component = "conferenceduration.jitsi"
-- we need bosh
modules_enabled = {
"bosh";
"pubsub";
"ping"; -- Enable mod_ping
"speakerstats";
--"turncredentials"; not supported yet
"conference_duration";
"muc_lobby_rooms";
}
c2s_require_encryption = false
lobby_muc = "lobby.jitsi"
main_muc = "conference.jitsi"
-- muc_lobby_whitelist = { "recorder.jitmeet.example.com" } -- Here we can whitelist jibri to enter lobby enabled rooms
Component "conference.jitsi" "muc"
storage = "memory"
modules_enabled = {
"muc_meeting_id";
"muc_domain_mapper";
--"token_verification";
}
admins = { "focus@auth.jitsi" }
muc_room_locking = false
muc_room_default_public_jids = true
-- internal muc component
Component "internal.auth.jitsi" "muc"
storage = "memory"
modules_enabled = {
"ping";
}
admins = { "focus@auth.jitsi", "jvb@auth.jitsi" }
muc_room_locking = false
muc_room_default_public_jids = true
VirtualHost "auth.jitsi"
authentication = "internal_plain"
Component "focus.jitsi"
component_secret = "jicofosecretpass"
Component "speakerstats.jitsi" "speakerstats_component"
muc_component = "conference.jitsi"
Component "conferenceduration.jitsi" "conference_duration_component"
muc_component = "conference.jitsi"
Component "lobby.jitsi" "muc"
storage = "memory"
restrict_room_creation = true
muc_room_locking = false
muc_room_default_public_jids = true

View File

@ -0,0 +1,64 @@
daemonize = false
allow_registration = false
use_libevent = true
component_interface = "0.0.0.0"
component_ports = { 5347 }
http_ports = { 5280 }
https_ports = {}
-- Not sure all modules are required
modules_enabled = {
"roster"; -- Allow users to have a roster. Recommended ;)
"saslauth"; -- Authentication for clients and servers. Recommended if you want to log in.
"tls"; -- Add support for secure TLS on c2s/s2s connections
"dialback"; -- s2s dialback support
"disco"; -- Service discovery
"posix"; -- POSIX functionality, sends server to background, enables syslog, etc.
"version"; -- Replies to server version requests
"uptime"; -- Report how long server has been running
"time"; -- Let others know the time here on this server
"ping"; -- Replies to XMPP pings with pongs
"pep"; -- Enables users to publish their mood, activity, playing music and more
-- jitsi
--"smacks"; -- not shipped with prosody
"carbons";
"mam";
"lastactivity";
"offline";
"pubsub";
"adhoc";
"websocket";
--"http_altconnect"; -- not shipped with prosody
}
log = {
--log less on console with warn="*console"; or err="*console" or more with debug="*console"
debug="*console";
}
VirtualHost "jitsi"
authentication = "anonymous"
ssl = {
key = "/var/lib/prosody/jitsi.key";
certificate = "/var/lib/prosody/jitsi.crt";
}
modules_enabled = {
"bosh";
"pubsub";
}
c2s_require_encryption = false
VirtualHost "auth.jitsi"
ssl = {
key = "/var/lib/prosody/auth.jitsi.key";
certificate = "/var/lib/prosody/auth.jitsi.crt";
}
authentication = "internal_plain"
admins = { "focus@auth.jitsi"}
Component "conference.jitsi" "muc"
Component "internal.auth.jitsi" "muc"
storage = "memory"
modules_enabled = { "ping"; }
admins = { "focus@auth.jitsi", "jvb@auth.jitsi" }

View File

@ -1 +1 @@
CMD openssl rand -base64 32
SERVICE_PASSWORD plume

View File

@ -43,6 +43,9 @@ USER_LONG <description>
CMD <command>
(a secret that is generated by running this command)
CMD_ONCE <command>
(same, but value is not changed when doing a regen)
CONST <constant value>
(the secret has a constant value set here)
@ -81,6 +84,7 @@ consul_server = consul.Consul()
USER = "USER"
USER_LONG = "USER_LONG"
CMD = "CMD"
CMD_ONCE = "CMD_ONCE"
CONST = "CONST"
CONST_LONG = "CONST_LONG"
SERVICE_DN = "SERVICE_DN"
@ -111,7 +115,7 @@ def read_secret(key, file_path):
secret = {"type": stype, "key": key}
if stype in [USER, USER_LONG]:
secret["desc"] = " ".join(l0[1:])
elif stype == CMD:
elif stype in [CMD, CMD_ONCE]:
secret["cmd"] = " ".join(l0[1:])
elif stype == CONST:
secret["value"] = " ".join(l0[1:])
@ -154,6 +158,7 @@ def get_secrets_services(secrets):
if svc not in services:
services[svc] = {
"dn": "cn=%s,%s"%(svc, SERVICE_DN_SUFFIX),
"desc": "(not provided)",
"pass": None,
"dn_at": [],
"pass_at": [],
@ -292,7 +297,7 @@ def gen_secrets_base(secrets, regen):
consul_server.kv.put(key, secret["value"])
print(bcolors.OKCYAN, "Value set.", bcolors.ENDC)
if secret["type"] == CMD:
if secret["type"] == CMD or (secret["type"] == CMD_ONCE and data is None):
print("----")
print(key)
print("Executing command:", secret["cmd"])

View File

@ -8,6 +8,8 @@ Go to guichet.deuxfleurs.fr
4. Hash it with `slappasswd`
5. Add a `userpassword` entry with the hash
This step can also be done using the automated tool `secretmgr.py` in the app folder.
## 2. Connect to postgres with the admin users
```bash

View File

@ -1,3 +1,5 @@
## Creating a new Plume user
1. Bind nomad on your machine with SSH (check the README file at the root of this repo)
2. Go to http://127.0.0.1:4646
3. Select `plume` -> click `exec` button (top right)

View File

@ -0,0 +1,45 @@
Le 20 janvier free a changé mon IP, un peu comme partout en France.
Ça concerne l'IPv4 et le préfixe IPv6.
Ici le bon vieux Bortzmoinsbien qui tweet : https://twitter.com/bortzmeyer/status/1351434290916155394
Max a update tout de suite l'IPv4 mais avec un TTL de 4h le temps de propagation est grand.
J'ai réduit les entrées sur les IP à 300 secondes, soit 5 minutes, le minimum chez Gandi, à voir si c'est une bonne idée.
Reste à update les IPv6, moins critiques pour le front facing mais utilisées pour le signaling en interne...
## Le fameux signaling
Ça pose un gros problème avec Nomad (et en moindre mesure avec Consul).
En effet, Nomad utilise l'IPv6 pour communiquer, il faut donc changer les IPs de tous les noeuds.
Problème ! On peut pas faire la migration au fur et à mesure car, changeant d'IP, les noeuds ne seront plus en mesure de communiquer.
On n'a pas envie de supprimer le cluster et d'en créer un nouveau car ça voudrait dire tout redéployer ce qui est long également (tous les fichiers HCL pour Nomad, tout le KV pour consul).
On ne peut pas non plus la faire à la bourrin en stoppant tous les cluster, changer son IP, puis redémarrer.
Enfin si, Consul accepte mais pas Nomad, qui lui va chercher à communiquer avec les anciennes IP et n'arrivera jamais à un consensus.
Au passage j'en ai profité pour changer le nom des noeuds car la dernière fois, Nomad n'avait PAS DU TOUT apprécié qu'un noeud ayant le même nom change d'IP. Ceci dit, si on utilise de facto le `peers.json` c'est peut être pas problématique. À tester.
Du coup, après moult réflexions, la silver bullet c'est la fonction outage recovery de nomad (consul l'a aussi au besoin).
Elle est ici : https://learn.hashicorp.com/tutorials/consul/recovery-outage
En gros, il faut arrêter tous les nodes.
Ensuite créer un fichier à ce path : `/var/lib/nomad/server/raft/peers.json`
Ne vous laissez pas perturber par le fichier `peers.info` à côté, il ne faut pas le toucher.
Après la grande question c'est de savoir si le cluster est en Raft v2 ou Raft v3.
Bon ben nous on était en Raft v2. Si vous vous trompez, au redémarrage Nomad va crasher avec une sale erreur :
```
nomad: failed to start Raft: error="recovery failed to parse peers.json: json: cannot unmarshal string into Go value of type raft.configEntry"
```
(je me suis trompé bien sûr).
Voilà, après il ne vous reste plus qu'à redémarrer et suivre les logs, cherchez bien la ligne où il dit qu'il a trouvé le peers.json.
## Les trucs à pas oublier
- Reconfigurer le backend KV de traefik (à voir à utiliser des DNS plutôt du coup)
- Reconfigurer l'IPv4 publique annoncée à Jitsi
## Ce qui reste à faire
- Mettre à jour les entrées DNS IPv6, ce qui devrait créer :
- digitale.machine.deuxfleurs.fr
- datura.machine.deuxfleurs.fr
- drosera.machine.deuxfleurs.fr
- Mettre à jour l'instance garage sur io

View File

@ -1,46 +1,46 @@
cluster_nodes:
hosts:
veterini:
datura:
ansible_host: atuin.site.deuxfleurs.fr
ansible_port: 110
ansible_become: true
ipv4: 192.168.1.2
gatewayv4: 192.168.1.254
ipv6: 2a01:e35:2fdc:dbe0::2
gatewayv6: 2a01:e35:2fdc:dbe0::1
ipv6: 2a01:e34:ec5c:dbe0::2
gatewayv6: 2a01:e34:ec5c:dbe0::1
interface: eno1
dns_1: 212.27.40.240
dns_2: 212.27.40.241
ansible_python_interpreter: python3
silicareux:
digitale:
ansible_host: atuin.site.deuxfleurs.fr
ansible_port: 111
ansible_become: true
ipv4: 192.168.1.3
gatewayv4: 192.168.1.254
ipv6: 2a01:e35:2fdc:dbe0::3
gatewayv6: 2a01:e35:2fdc:dbe0::1
ipv6: 2a01:e34:ec5c:dbe0::3
gatewayv6: 2a01:e34:ec5c:dbe0::1
interface: eno1
dns_1: 212.27.40.240
dns_2: 212.27.40.241
ansible_python_interpreter: python3
wonse:
drosera:
ansible_host: atuin.site.deuxfleurs.fr
ansible_port: 112
ansible_become: true
ipv4: 192.168.1.4
gatewayv4: 192.168.1.254
ipv6: 2a01:e35:2fdc:dbe0::4
gatewayv6: 2a01:e35:2fdc:dbe0::1
ipv6: 2a01:e34:ec5c:dbe0::4
gatewayv6: 2a01:e34:ec5c:dbe0::1
interface: eno1
dns_1: 212.27.40.240
dns_2: 212.27.40.241
ansible_python_interpreter: python3
io:
ansible_host: pluton.site.deuxfleurs.fr
ansible_host: jupiter.site.deuxfleurs.fr
ansible_port: 110
ansible_become: true
ipv4: 192.168.1.2

View File

@ -1,6 +1,6 @@
- name: "Set consul version"
set_fact:
consul_version: 1.9.0
consul_version: 1.9.1
- name: "Download and install Consul for x86_64"
unarchive:

View File

@ -1,6 +1,6 @@
- name: "Set nomad version"
set_fact:
nomad_version: 1.0.1
nomad_version: 1.0.2
- name: "Download and install Nomad for x86_64"
unarchive: