Skip to content

Commit

Permalink
Merge pull request bigbluebutton#9977 from tdjac0bs/bbb_libreoffice_c…
Browse files Browse the repository at this point in the history
…ontainer

Detach libreoffice from bbb-web ( running as a docker container )
  • Loading branch information
ffdixon authored Jul 2, 2020
2 parents ec94b0f + 9c6daad commit 22f88bf
Show file tree
Hide file tree
Showing 8 changed files with 274 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,21 +20,33 @@
package org.bigbluebutton.presentation.imp;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;

import com.sun.org.apache.xerces.internal.impl.xs.opti.DefaultDocument;
import org.apache.commons.io.FilenameUtils;
import org.bigbluebutton.presentation.UploadedPresentation;
import org.jodconverter.core.document.DefaultDocumentFormatRegistry;
import org.jodconverter.core.document.DocumentFormat;
import org.jodconverter.core.job.AbstractConverter;
import org.jodconverter.local.LocalConverter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.gson.Gson;

public class Office2PdfPageConverter {
public abstract class Office2PdfPageConverter {
private static Logger log = LoggerFactory.getLogger(Office2PdfPageConverter.class);

public boolean convert(File presentationFile, File output, int page, UploadedPresentation pres,
final LocalConverter converter){
public static boolean convert(File presentationFile, File output, int page, UploadedPresentation pres,
LocalConverter converter){

FileInputStream inputStream = null;
FileOutputStream outputStream = null;

try {
Map<String, Object> logData = new HashMap<>();
logData.put("meetingId", pres.getMeetingId());
Expand All @@ -46,7 +58,15 @@ public boolean convert(File presentationFile, File output, int page, UploadedPre
String logStr = gson.toJson(logData);
log.info(" --analytics-- data={}", logStr);

converter.convert(presentationFile).to(output).execute();
final DocumentFormat sourceFormat = DefaultDocumentFormatRegistry.getFormatByExtension(
FilenameUtils.getExtension(presentationFile.getName()));

inputStream = new FileInputStream(presentationFile);
outputStream = new FileOutputStream(output);

converter.convert(inputStream).as(sourceFormat).to(outputStream).as(DefaultDocumentFormatRegistry.PDF).execute();
outputStream.flush();

if (output.exists()) {
return true;
} else {
Expand Down Expand Up @@ -74,6 +94,22 @@ public boolean convert(File presentationFile, File output, int page, UploadedPre
String logStr = gson.toJson(logData);
log.error(" --analytics-- data={}", logStr, e);
return false;
} finally {
if(inputStream!=null) {
try {
inputStream.close();
} catch(Exception e) {

}
}

if(outputStream!=null) {
try {
outputStream.close();
} catch(Exception e) {

}
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,18 @@
package org.bigbluebutton.presentation.imp;

import java.io.File;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import org.bigbluebutton.presentation.ConversionMessageConstants;
import org.bigbluebutton.presentation.SupportedFileTypes;
import org.bigbluebutton.presentation.UploadedPresentation;
import org.jodconverter.core.office.OfficeException;
import org.jodconverter.core.office.OfficeManager;
import org.jodconverter.core.office.OfficeUtils;
import org.jodconverter.local.LocalConverter;
import org.jodconverter.local.office.LocalOfficeManager;
import org.jodconverter.local.office.ExternalOfficeManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand All @@ -39,20 +41,12 @@ public class OfficeToPdfConversionService {
private static Logger log = LoggerFactory.getLogger(OfficeToPdfConversionService.class);

private OfficeDocumentValidator2 officeDocumentValidator;
private final OfficeManager officeManager;
private final LocalConverter documentConverter;
private final ArrayList<ExternalOfficeManager> officeManagers;
private ExternalOfficeManager currentManager = null;
private boolean skipOfficePrecheck = false;

public OfficeToPdfConversionService() throws OfficeException {
officeManager = LocalOfficeManager
.builder()
.portNumbers(8100, 8101, 8102, 8103, 8104)
.build();
documentConverter = LocalConverter
.builder()
.officeManager(officeManager)
.filterChain(new OfficeDocumentConversionFilter())
.build();
officeManagers = new ArrayList<>();
}

/*
Expand Down Expand Up @@ -121,8 +115,39 @@ private File setupOutputPdfFile(UploadedPresentation pres) {

private boolean convertOfficeDocToPdf(UploadedPresentation pres,
File pdfOutput) {
Office2PdfPageConverter converter = new Office2PdfPageConverter();
return converter.convert(pres.getUploadedFile(), pdfOutput, 0, pres, documentConverter);
boolean success = false;
int attempts = 0;

while(!success) {
LocalConverter documentConverter = LocalConverter
.builder()
.officeManager(currentManager)
.filterChain(new OfficeDocumentConversionFilter())
.build();

success = Office2PdfPageConverter.convert(pres.getUploadedFile(), pdfOutput, 0, pres, documentConverter);

if(!success) {
// In case of failure, try with other open Office Manager

if(++attempts != officeManagers.size()) {
// Go to next Office Manager ( if the last retry with the first one )
int currentManagerIndex = officeManagers.indexOf(currentManager);

boolean isLastManager = ( currentManagerIndex == officeManagers.size()-1 );
if(isLastManager) {
currentManager = officeManagers.get(0);
} else {
currentManager = officeManagers.get(currentManagerIndex+1);
}
} else {
// We tried to use all our office managers and it's still failing
break;
}
}
}

return success;
}

private void makePdfTheUploadedFileAndSetStepAsSuccess(UploadedPresentation pres, File pdf) {
Expand All @@ -139,19 +164,41 @@ public void setSkipOfficePrecheck(boolean skipOfficePrecheck) {
}

public void start() {
try {
officeManager.start();
} catch (OfficeException e) {
log.error("Could not start Office Manager", e);
for(int managerIndex = 0; managerIndex < 4; managerIndex ++) {
Integer instanceNumber = managerIndex + 1; // starts at 1

try {
final File workingDir = new File("/var/tmp/soffice_0" +instanceNumber);
ExternalOfficeManager officeManager = ExternalOfficeManager
.builder()
.connectTimeout(2000L)
.retryInterval(500L)
.portNumber(8200 + instanceNumber)
.connectOnStart(false) // If it's true and soffice is not available, exception is thrown here ( we don't want exception here - we want the manager alive trying to reconnect )
.workingDir(workingDir)
.build();

// Workaround for jodconverter not calling makeTempDir when connectOnStart=false (issue 211)
Method method = officeManager.getClass().getSuperclass().getDeclaredMethod("makeTempDir");
method.setAccessible(true);
method.invoke(officeManager);
// End of workaround for jodconverter not calling makeTempDir

officeManager.start();
officeManagers.add(officeManager);
} catch (Exception e) {
log.error("Could not start Office Manager " + instanceNumber + ". Details: " + e.getMessage());
}

currentManager = officeManagers.get(0);
}
}

public void stop() {
try {
officeManager.stop();
} catch (OfficeException e) {
officeManagers.forEach(officeManager -> officeManager.stop() );
} catch (Exception e) {
log.error("Could not stop Office Manager", e);
}

}
}
19 changes: 19 additions & 0 deletions bbb-libreoffice/assets/bbb-libreoffice.service
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
[Unit]
Description=BigBlueButton Libre Office container
Requires=network.target

[Service]
Type=simple
WorkingDirectory=/tmp
ExecStart=/usr/share/bbb-libreoffice/libreoffice_container.sh INSTANCE_NUMBER
ExecStop=/usr/bin/docker kill bbb-libreoffice-INSTANCE_NUMBER
Restart=always
RestartSec=60
SuccessExitStatus=
TimeoutStopSec=30
PermissionsStartOnly=true
LimitNOFILE=1024

[Install]
WantedBy=multi-user.target

33 changes: 33 additions & 0 deletions bbb-libreoffice/assets/libreoffice_container.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#!/bin/bash
INSTANCE_NUMBER=$1

if [ -z "$INSTANCE_NUMBER" ]; then
INSTANCE_NUMBER=0
fi;

_kill() {
CHECK_CONTAINER=`docker inspect bbb-libreoffice-${INSTANCE_NUMBER} &> /dev/null && echo 1 || echo 0`
if [ "$CHECK_CONTAINER" = "1" ]; then
echo "Killing container"
docker kill bbb-libreoffice-${INSTANCE_NUMBER};
sleep 1
fi;
}

trap _kill SIGINT


if (($INSTANCE_NUMBER >= 1 && $INSTANCE_NUMBER <= 10)); then
PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"

_kill

docker run --name bbb-libreoffice-${INSTANCE_NUMBER} -p 82${INSTANCE_NUMBER}:8000 -v/var/tmp/soffice${INSTANCE_NUMBER}:/var/tmp/soffice${INSTANCE_NUMBER} --rm bbb-libreoffice &

wait $!
else
echo ;
echo "Invalid or missing parameter INSTANCE_NUMBER"
echo " Usage: $0 INSTANCE_NUMBER"
exit 1
fi;
26 changes: 26 additions & 0 deletions bbb-libreoffice/docker/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
FROM openjdk:8-jre

ENV DEBIAN_FRONTEND noninteractive

RUN apt update

RUN addgroup --system --gid 996 libreoffice
RUN adduser --disabled-password --system --disabled-login --shell /sbin/nologin --gid 996 --uid 996 libreoffice

RUN apt -y install locales-all fontconfig libxt6 libxrender1
RUN apt -y install libreoffice --no-install-recommends

RUN dpkg-reconfigure fontconfig && fc-cache -f -s -v

RUN for i in `seq -w 1 10` ; do mkdir -m 777 /var/tmp/soffice${i}; done

VOLUME ["/usr/share/fonts/"]
RUN chown libreoffice /home/libreoffice/

ADD ./bbb-libreoffice-entrypoint.sh /home/libreoffice/
RUN chown -R libreoffice /home/libreoffice/
RUN chmod 700 /home/libreoffice/bbb-libreoffice-entrypoint.sh

USER libreoffice

ENTRYPOINT ["/home/libreoffice/bbb-libreoffice-entrypoint.sh" ]
7 changes: 7 additions & 0 deletions bbb-libreoffice/docker/bbb-libreoffice-entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/bin/bash

## Initialize environment
/usr/lib/libreoffice/program/soffice.bin -env:UserInstallation="file:///tmp/"

## Run daemon
/usr/lib/libreoffice/program/soffice.bin --accept="socket,host=0.0.0.0,port=8000,tcpNoDelay=1;urp;StarOffice.ServiceManager" --headless --invisible --nocrashreport --nodefault --nofirststartwizard --nolockcheck --nologo --norestore -env:UserInstallation="file:///tmp/"
51 changes: 51 additions & 0 deletions bbb-libreoffice/install.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#!/bin/bash
if [ "$EUID" -ne 0 ]; then
echo "Please run this script as root ( or with sudo )" ;
exit 1;
fi;

DOCKER_CHECK=`docker --version &> /dev/null && echo 1 || echo 0`

if [ "$DOCKER_CHECK" = "0" ]; then
echo "Docker not found";
apt update;
apt install apt-transport-https ca-certificates curl software-properties-common
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu bionic stable"
apt update
apt install docker-ce -y
systemctl enable docker
systemctl start docker
systemctl status docker
else
echo "Docker already installed";
fi


IMAGE_CHECK=`docker image inspect bbb-libreoffice &> /dev/null && echo 1 || echo 0`
if [ "$IMAGE_CHECK" = "0" ]; then
echo "Docker image doesn't exists, building"
docker build -t bbb-libreoffice docker/
else
echo "Docker image already exists";
fi

FOLDER_CHECK=`[ -d /usr/share/bbb-libreoffice/ ] && echo 1 || echo 0`
if [ "$FOLDER_CHECK" = "0" ]; then
echo "Install folder doesn't exists, installing"
mkdir -m 755 /usr/share/bbb-libreoffice/
cp assets/libreoffice_container.sh /usr/share/bbb-libreoffice/
chmod 700 /usr/share/bbb-libreoffice/libreoffice_container.sh
chown -R root /usr/share/bbb-libreoffice/

for i in `seq 1 4` ; do
cat assets/bbb-libreoffice.service | sed 's/INSTANCE_NUMBER/0'${i}'/g' > /lib/systemd/system/bbb-libreoffice-0${i}.service
systemctl daemon-reload
systemctl enable bbb-libreoffice-0${i}
systemctl start bbb-libreoffice-0${i}
done

else
echo "Install folder already exists"
fi;

29 changes: 29 additions & 0 deletions bbb-libreoffice/uninstall.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#!/bin/bash
if [ "$EUID" -ne 0 ]; then
echo "Please run this script as root ( or with sudo )" ;
exit 1;
fi;

IMAGE_CHECK=`docker image inspect bbb-libreoffice 2>&1 > /dev/null && echo 1 || echo 0`
if [ "$IMAGE_CHECK" = "1" ]; then
echo "Stopping services"
systemctl --no-pager --no-legend --value --state=running | grep bbb-libreoffice | awk -F '.service' '{print $1}' | xargs -n 1 systemctl stop

echo "Removing image"
docker image rm bbb-libreoffice
fi


FOLDER_CHECK=`[ -d /usr/share/bbb-libreoffice/ ] && echo 1 || echo 0`
if [ "$FOLDER_CHECK" = "1" ]; then
echo "Stopping services"
systemctl --no-pager --no-legend --value --state=running | grep bbb-libreoffice | awk -F '.service' '{print $1}' | xargs -n 1 systemctl stop

echo "Removing install folder"
rm -rf /usr/share/bbb-libreoffice/

echo "Removing service definitions"
rm /lib/systemd/system/bbb-libreoffice-0*
find /etc/systemd/ | grep bbb-libreoffice | xargs --no-run-if-empty -n 1 -I __ rm __
systemctl daemon-reload
fi;

0 comments on commit 22f88bf

Please sign in to comment.