resolver: Use self-built image
This commit updates the resolver component to use an image that is built locally.
This commit is contained in:
parent
dceff860e4
commit
2881a5f65c
71 changed files with 195 additions and 111 deletions
118
embed/resources.go
Normal file
118
embed/resources.go
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
// Package embed contains embedded resources
|
||||
package embed
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"io"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// resourceEmbed contains all the resources required by the WissKI-Distillery package.
|
||||
//go:embed all:resources
|
||||
var resourceEmbed embed.FS
|
||||
|
||||
// InstallResource install a resource src into dest.
|
||||
// When it encounters a directory, recursively installs the directory is called.
|
||||
// For each installation item, onInstallFile is called, unless onInstallFile is nil.
|
||||
//
|
||||
// If src points to a file, dst must either be an existing file, or not exist.
|
||||
// If src points to a directory, dst must either be an existing directory, or not exist.
|
||||
func InstallResource(dst, src string, onInstallFile func(dst, src string)) error {
|
||||
return installFile(dst, resourceEmbed, src, onInstallFile)
|
||||
}
|
||||
|
||||
var errExpectedFileButGotDirectory = errors.New("Expected a file, but got a directory")
|
||||
var errExpectedDirectoryButGotFile = errors.New("Expected a directory, but got a file")
|
||||
|
||||
func installFile(dst string, fsys embed.FS, src string, onInstallFile func(dst, src string)) error {
|
||||
// call the on-install file path
|
||||
if onInstallFile != nil {
|
||||
onInstallFile(dst, src)
|
||||
}
|
||||
|
||||
// open the source file!
|
||||
srcFile, err := fsys.Open(src)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "Error opening source file %s", src)
|
||||
}
|
||||
defer srcFile.Close()
|
||||
|
||||
// stat the source file to install
|
||||
srcStat, srcErr := srcFile.Stat()
|
||||
if srcErr != nil {
|
||||
return errors.Wrapf(srcErr, "Error calling stat on source %s", src)
|
||||
}
|
||||
|
||||
// if it is a directory, we should recurse!
|
||||
if srcStat.IsDir() {
|
||||
return installDir(dst, srcStat, srcFile, fsys, src, onInstallFile)
|
||||
}
|
||||
|
||||
// determine if we need to create the destination file, or if it already exists
|
||||
dstStat, dstErr := os.Stat(dst)
|
||||
switch {
|
||||
case os.IsNotExist(dstErr):
|
||||
case dstErr != nil:
|
||||
return errors.Wrapf(dstErr, "Error calling stat on destination %s", dst)
|
||||
case dstStat.IsDir():
|
||||
return errors.Wrapf(errExpectedFileButGotDirectory, "Error processing destination %s", dst)
|
||||
}
|
||||
|
||||
// Open the file
|
||||
dstFile, err := os.OpenFile(dst, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, srcStat.Mode())
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "Error opening destination %s", dst)
|
||||
}
|
||||
defer dstFile.Close()
|
||||
|
||||
// copy over the content
|
||||
_, err = io.Copy(dstFile, srcFile)
|
||||
return errors.Wrapf(err, "Error writing to destination %s", dst)
|
||||
|
||||
}
|
||||
|
||||
func installDir(dst string, srcStat fs.FileInfo, srcFile fs.File, fsys embed.FS, src string, onInstallFile func(dst, src string)) error {
|
||||
// make sure it is a directory!
|
||||
dir, ok := srcFile.(fs.ReadDirFile)
|
||||
if !ok {
|
||||
return errExpectedDirectoryButGotFile
|
||||
}
|
||||
|
||||
// create the destination
|
||||
dstStat, dstErr := os.Stat(dst)
|
||||
switch {
|
||||
case os.IsNotExist(dstErr):
|
||||
if err := os.MkdirAll(dst, srcStat.Mode()); err != nil {
|
||||
return errors.Wrapf(err, "Error creating destination directory %s", dst)
|
||||
}
|
||||
case dstErr != nil:
|
||||
return errors.Wrapf(dstErr, "Error calling stat on destination %s", dst)
|
||||
case !dstStat.IsDir():
|
||||
return errors.Wrapf(errExpectedDirectoryButGotFile, "Error opening destination %s", dst)
|
||||
case dstErr == nil:
|
||||
}
|
||||
|
||||
// read the directory
|
||||
entries, err := dir.ReadDir(-1)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "Error reading source directory %s", srcFile)
|
||||
}
|
||||
|
||||
// iterate over all the children
|
||||
for _, entry := range entries {
|
||||
if err := func(dst, src string) error {
|
||||
return installFile(dst, fsys, src, onInstallFile)
|
||||
}(
|
||||
filepath.Join(dst, entry.Name()),
|
||||
filepath.Join(src, entry.Name()),
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
1
embed/resources/.dockerignore
Normal file
1
embed/resources/.dockerignore
Normal file
|
|
@ -0,0 +1 @@
|
|||
data/
|
||||
8
embed/resources/compose/barrel/.dockerignore
Normal file
8
embed/resources/compose/barrel/.dockerignore
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
# Ignore everything
|
||||
*
|
||||
|
||||
# allow the following files:
|
||||
!conf/*
|
||||
!scripts/*
|
||||
!patch/*
|
||||
!wisskiutils/*
|
||||
28
embed/resources/compose/barrel/.env.sample
Normal file
28
embed/resources/compose/barrel/.env.sample
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
#######################
|
||||
# Meta Settings
|
||||
#######################
|
||||
|
||||
# Real path for volumes to be stored
|
||||
DATA_PATH=/var/www/deploy/instances/example.slug/data
|
||||
UTILS_DIR=/var/www/deploy/runtime/utils/
|
||||
|
||||
#######################
|
||||
### Web Server settings
|
||||
#######################
|
||||
# the hostname for the website
|
||||
VIRTUAL_HOST=example.com
|
||||
|
||||
# optional letsencrypt support
|
||||
# when blank, ignore
|
||||
LETSENCRYPT_HOST=
|
||||
LETSENCRYPT_EMAIL=
|
||||
|
||||
### SQL settings
|
||||
MYSQL_HOST=mysql
|
||||
MYSQL_USER=user
|
||||
MYSQL_PASS=pass
|
||||
|
||||
### GraphDB settings
|
||||
GRAPHDB_HOST=graphdb
|
||||
GRAPHDB_USER=user
|
||||
GRAPHDB_PASS=pass
|
||||
106
embed/resources/compose/barrel/Dockerfile
Normal file
106
embed/resources/compose/barrel/Dockerfile
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
FROM docker.io/library/php:8.0-apache-bullseye
|
||||
ARG COMPOSER_VERSION=2.3.8
|
||||
WORKDIR /var/www
|
||||
|
||||
# install and enable the various required php extension
|
||||
RUN apt-get update && apt-get install -y \
|
||||
curl \
|
||||
default-mysql-client \
|
||||
git \
|
||||
imagemagick \
|
||||
libcurl4-openssl-dev \
|
||||
libfreetype6-dev \
|
||||
libicu-dev \
|
||||
libjpeg62-turbo-dev \
|
||||
libpng-dev \
|
||||
libssh2-1-dev \
|
||||
libwebp-dev \
|
||||
libxml2-dev \
|
||||
libxpm-dev \
|
||||
sudo \
|
||||
unzip \
|
||||
vim \
|
||||
zip \
|
||||
&& \
|
||||
docker-php-source extract && \
|
||||
mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini" && \
|
||||
pear config-set php_ini "$PHP_INI_DIR/php.ini" && \
|
||||
docker-php-ext-configure gd \
|
||||
--enable-gd \
|
||||
--with-webp \
|
||||
--with-jpeg \
|
||||
--with-xpm \
|
||||
--with-freetype \
|
||||
--enable-gd-jis-conv \
|
||||
&& \
|
||||
docker-php-ext-install \
|
||||
curl \
|
||||
gd \
|
||||
intl \
|
||||
mysqli \
|
||||
opcache \
|
||||
pdo_mysql \
|
||||
soap \
|
||||
xml \
|
||||
&& \
|
||||
pecl install xmlrpc-1.0.0RC3 && \
|
||||
pecl install ssh2-1.3.1 && \
|
||||
pecl install apcu-5.1.21 && \
|
||||
pecl install uploadprogress-2.0.2 && \
|
||||
docker-php-ext-enable \
|
||||
apcu \
|
||||
curl \
|
||||
gd \
|
||||
intl \
|
||||
mysqli \
|
||||
mysqli \
|
||||
opcache \
|
||||
pdo_mysql \
|
||||
soap \
|
||||
ssh2 \
|
||||
uploadprogress \
|
||||
xml \
|
||||
xmlrpc \
|
||||
&& \
|
||||
docker-php-source delete
|
||||
|
||||
# enable the apache rewrite mod
|
||||
RUN a2enmod rewrite
|
||||
|
||||
# install composer and add it to path
|
||||
RUN curl -sS https://getcomposer.org/installer | php -- --version=$COMPOSER_VERSION && \
|
||||
mv composer.phar /usr/local/bin/composer
|
||||
ENV PATH "/usr/local/bin:/var/www/data/project/vendor/bin:$PATH"
|
||||
|
||||
# remove default configuration
|
||||
RUN rm /etc/apache2/sites-available/*.conf && \
|
||||
rm /etc/apache2/sites-enabled/*.conf
|
||||
|
||||
ADD patch/easyrdf.patch /patch/easyrdf.patch
|
||||
ADD patch/triples.patch /patch/triples.patch
|
||||
|
||||
# Add wisski configuration
|
||||
ADD conf/ports.conf /etc/apache2/ports.conf
|
||||
ADD conf/wisski.conf /etc/apache2/sites-available/wisski.conf
|
||||
ADD conf/wisski.ini /usr/local/etc/php/conf.d/wisski.ini
|
||||
RUN a2ensite wisski
|
||||
|
||||
# volumes for composer
|
||||
VOLUME /var/www/.composer
|
||||
VOLUME /var/www/data
|
||||
|
||||
# Add and configure the entrypoint
|
||||
ADD scripts/entrypoint.sh /entrypoint.sh
|
||||
|
||||
ENTRYPOINT [ "/bin/bash", "/entrypoint.sh" ]
|
||||
CMD ["apache2-foreground"]
|
||||
|
||||
# Add the provision script and WissKI utils
|
||||
ADD scripts/provision_container.sh /provision_container.sh
|
||||
ADD wisskiutils/ /wisskiutils
|
||||
|
||||
# Add the user_shell.sh
|
||||
ADD scripts/user_shell.sh /user_shell.sh
|
||||
|
||||
# expose port 8080
|
||||
EXPOSE 8080
|
||||
4
embed/resources/compose/barrel/conf/ports.conf
Normal file
4
embed/resources/compose/barrel/conf/ports.conf
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
# This file configures where apache should listen.
|
||||
# Because we are running as a limited user, we want to listen on a high port.
|
||||
# For this we use port 8080
|
||||
Listen 8080
|
||||
24
embed/resources/compose/barrel/conf/wisski.conf
Normal file
24
embed/resources/compose/barrel/conf/wisski.conf
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
<VirtualHost *:8080>
|
||||
# the document root -- /var/www/data/project/web
|
||||
DocumentRoot /var/www/data/project/web
|
||||
|
||||
<Directory /var/www/data/project/web>
|
||||
# add types for .owl and .rdf
|
||||
AddType application/rdf+xml .owl
|
||||
AddType application/rdf+xml .rdf
|
||||
|
||||
# Rewrite the 'ontology' directory
|
||||
RewriteEngine On
|
||||
RewriteOptions InheritDownBefore
|
||||
ReWriteRule ^(ontology/[^/]+/).+ $1 [R=303,END]
|
||||
ReWriteRule ^(ontology/[^/]+)/$ sites/default/files/$1.owl [END]
|
||||
|
||||
# Allow overrides of symlinks
|
||||
Options Indexes FollowSymLinks
|
||||
AllowOverride All
|
||||
Require all granted
|
||||
</Directory>
|
||||
|
||||
ErrorLog /dev/stderr
|
||||
CustomLog /dev/stdout combined
|
||||
</VirtualHost>
|
||||
14
embed/resources/compose/barrel/conf/wisski.ini
Normal file
14
embed/resources/compose/barrel/conf/wisski.ini
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
; File Uploads up to 1GB
|
||||
file_uploads = On
|
||||
upload_max_filesize = 1000M
|
||||
post_max_size = 1000M
|
||||
|
||||
; Composer uses an absurd amount of memory
|
||||
; 4GB ought to be enough
|
||||
memory_limit = 4G
|
||||
|
||||
; Increase various limits for some long running WissKI operations
|
||||
max_execution_time = 3000
|
||||
max_input_time = 600
|
||||
max_input_nesting_level = 640
|
||||
max_input_vars = 10000
|
||||
33
embed/resources/compose/barrel/docker-compose.yml
Normal file
33
embed/resources/compose/barrel/docker-compose.yml
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
version: "3.7"
|
||||
|
||||
services:
|
||||
barrel:
|
||||
build: .
|
||||
restart: always
|
||||
hostname: ${VIRTUAL_HOST}.wisski
|
||||
environment:
|
||||
# port and hostname for this image to use
|
||||
VIRTUAL_HOST: ${VIRTUAL_HOST}
|
||||
VIRTUAL_PORT: 8080
|
||||
|
||||
# optional letsencrypt email
|
||||
LETSENCRYPT_HOST: ${LETSENCRYPT_HOST}
|
||||
LETSENCRYPT_EMAIL: ${LETSENCRYPT_EMAIL}
|
||||
|
||||
# label it with the current slug
|
||||
labels:
|
||||
eu.wiss-ki.barrel.slug: ${SLUG}
|
||||
eu.wiss-ki.barrel.authfile: /var/www/.ssh/authorized_keys,/var/www/.ssh/global_authorized_keys
|
||||
|
||||
# volumes that are mounted
|
||||
volumes:
|
||||
- ${GLOBAL_AUTHORIZED_KEYS_FILE}:/var/www/.ssh/global_authorized_keys:ro
|
||||
- ${DATA_PATH}/.composer:/var/www/.composer
|
||||
- ${DATA_PATH}/data:/var/www/data
|
||||
- ${DATA_PATH}/authorized_keys:/var/www/.ssh/authorized_keys
|
||||
- ${UTILS_DIR}:/utils:ro
|
||||
|
||||
networks:
|
||||
default:
|
||||
name: distillery
|
||||
external: true
|
||||
4
embed/resources/compose/barrel/patch/easyrdf.patch
Normal file
4
embed/resources/compose/barrel/patch/easyrdf.patch
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
281c281
|
||||
< if (preg_match("|^HTTP/([\d\.x]+) (\d+) ([^\r\n]+)|", $status, $m)) {
|
||||
---
|
||||
> if(preg_match("|^HTTP/([\d\.x]+) (\d+) ([^\r\n]*)|", $status, $m)) {
|
||||
8
embed/resources/compose/barrel/patch/triples.patch
Normal file
8
embed/resources/compose/barrel/patch/triples.patch
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
100c100
|
||||
< if($result->o instanceof \EasyRdf_Resource) {
|
||||
---
|
||||
> if($result->o instanceof \EasyRdf\Resource) {
|
||||
118c118
|
||||
< $object_text = $result->o->getValue();
|
||||
---
|
||||
> $object_text = $result->o->dumpValue('string');
|
||||
11
embed/resources/compose/barrel/scripts/entrypoint.sh
Executable file
11
embed/resources/compose/barrel/scripts/entrypoint.sh
Executable file
|
|
@ -0,0 +1,11 @@
|
|||
#!/bin/bash
|
||||
|
||||
# This script contains
|
||||
|
||||
# chown the volumes to make sure they can be read and written by the limited user
|
||||
chown www-data:www-data /var/www
|
||||
chown www-data:www-data /var/www/.composer
|
||||
chown www-data:www-data /var/www/data/
|
||||
|
||||
# run the original entrypoint
|
||||
docker-php-entrypoint "$@"
|
||||
174
embed/resources/compose/barrel/scripts/provision_container.sh
Normal file
174
embed/resources/compose/barrel/scripts/provision_container.sh
Normal file
|
|
@ -0,0 +1,174 @@
|
|||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
function log_info() {
|
||||
echo -e "\033[1m$1\033[0m"
|
||||
}
|
||||
|
||||
function log_ok() {
|
||||
echo -e "\033[0;32m$1\033[0m"
|
||||
}
|
||||
|
||||
log_info " => Reading configuration variables"
|
||||
|
||||
INSTANCE_DOMAIN="$1"
|
||||
echo "INSTANCE_DOMAIN=$INSTANCE_DOMAIN"
|
||||
shift 1
|
||||
|
||||
MYSQL_DATABASE="$1"
|
||||
echo "MYSQL_DATABASE=$MYSQL_DATABASE"
|
||||
MYSQL_USER="$2"
|
||||
echo "MYSQL_USER=$MYSQL_USER"
|
||||
MYSQL_PASSWORD="$3"
|
||||
echo "MYSQL_PASSWORD=$MYSQL_PASSWORD"
|
||||
|
||||
shift 3
|
||||
|
||||
GRAPHDB_REPO="$1"
|
||||
echo "GRAPHDB_REPO=$GRAPHDB_REPO"
|
||||
GRAPHDB_USER="$2"
|
||||
echo "GRAPHDB_USER=$GRAPHDB_USER"
|
||||
GRAPHDB_PASSWORD="$3"
|
||||
echo "GRAPHDB_PASSWORD=$GRAPHDB_PASSWORD"
|
||||
shift 3
|
||||
|
||||
GRAPHDB_HEADER="$(printf "%s:%s" "$GRAPHDB_USER" "$GRAPHDB_PASSWORD" | base64 -w 0)"
|
||||
|
||||
DRUPAL_USER="$1"
|
||||
echo "DRUPAL_USER=$DRUPAL_USER"
|
||||
DRUPAL_PASS="$2"
|
||||
echo "DRUPAL_PASS=$DRUPAL_PASS"
|
||||
shift 2
|
||||
|
||||
DRUPAL_VERSION="$1"
|
||||
echo "DRUPAL_VERSION=$DRUPAL_VERSION"
|
||||
shift 1
|
||||
|
||||
WISSKI_VERSION="$1"
|
||||
echo "WISSKI_VERSION=$WISSKI_VERSION"
|
||||
shift 1
|
||||
|
||||
log_info " => Preparing installation environment"
|
||||
BASE_DIR="/var/www/data"
|
||||
COMPOSER_DIR="$BASE_DIR/project"
|
||||
WEB_DIR="$COMPOSER_DIR/web"
|
||||
ONTOLOGY_DIR="$WEB_DIR/sites/default/files/ontology"
|
||||
|
||||
log_info " => Creating '$COMPOSER_DIR'"
|
||||
mkdir -p "$COMPOSER_DIR"
|
||||
cd "$COMPOSER_DIR"
|
||||
|
||||
# workaround for making the drupal sites directory writable
|
||||
function drupal_sites_permission_workaround() {
|
||||
chmod -R u+w "$WEB_DIR/sites/" || true
|
||||
}
|
||||
|
||||
# install a module with composer and enable it with drush
|
||||
# Example:
|
||||
#
|
||||
# composer_install_and_enable << EOF
|
||||
# drupal/some_module:1.23 some_module
|
||||
# drupal/other_module:2.34
|
||||
# EOF
|
||||
#
|
||||
# Will install both modules, but only enable the first one.
|
||||
function composer_install_and_enable() {
|
||||
while IFS= read -r line; do
|
||||
echo "$line" | (
|
||||
read composer drush;
|
||||
drupal_sites_permission_workaround
|
||||
composer require "$composer"
|
||||
if [ -n "$drush" ]; then
|
||||
drush pm-enable --yes "$drush"
|
||||
fi
|
||||
)
|
||||
done
|
||||
}
|
||||
|
||||
|
||||
# Create a new composer project.
|
||||
log_info " => Creating composer project"
|
||||
if [ -z "${DRUPAL_VERSION}" ]; then
|
||||
composer --no-interaction create-project 'drupal/recommended-project:^9.0.0' .
|
||||
else
|
||||
composer --no-interaction create-project "drupal/recommended-project:$DRUPAL_VERSION" .
|
||||
fi
|
||||
|
||||
# needed for composer > 2.2
|
||||
composer --no-interaction config allow-plugins true
|
||||
|
||||
# Install drush so that we can automate a lot of things
|
||||
log_info " => Installing 'drush'"
|
||||
composer require drush/drush
|
||||
|
||||
# Use 'drush' to run the site-installation.
|
||||
# Here we need to use the username, password and database creds we made above.
|
||||
log_info " => Running drupal installation scripts"
|
||||
drush site-install standard --yes --site-name=${INSTANCE_DOMAIN} \
|
||||
--account-name=$DRUPAL_USER --account-pass=$DRUPAL_PASS \
|
||||
--db-url=mysql://${MYSQL_USER}:${MYSQL_PASSWORD}@sql/${MYSQL_DATABASE}
|
||||
drupal_sites_permission_workaround
|
||||
|
||||
# create a directory for ontologies.
|
||||
log_info " => Creating '$ONTOLOGY_DIR'"
|
||||
mkdir -p "$ONTOLOGY_DIR"
|
||||
|
||||
# Install the Wisski packages.
|
||||
log_info " => Installing Wisski packages"
|
||||
cd "$COMPOSER_DIR"
|
||||
|
||||
# install the development version when requested
|
||||
if [ -z "${WISSKI_VERSION}" ]; then
|
||||
composer require 'drupal/wisski'
|
||||
else
|
||||
composer require "drupal/wisski:$WISSKI_VERSION"
|
||||
fi
|
||||
|
||||
# Install dependencies of WissKI
|
||||
log_info " => Installing and patching Wisski dependencies"
|
||||
pushd "$WEB_DIR/modules/contrib/wisski"
|
||||
composer install
|
||||
|
||||
# Patch EasyRDF (for now)
|
||||
EASYRDF_RESPONSE="./vendor/easyrdf/easyrdf/lib/EasyRdf/Http/Response.php"
|
||||
if [ -f "$EASYRDF_RESPONSE" ]; then
|
||||
patch -N "$EASYRDF_RESPONSE" < "/patch/easyrdf.patch"
|
||||
fi
|
||||
popd
|
||||
|
||||
log_info " => Installing and enabling additional modules"
|
||||
composer_install_and_enable << EOF
|
||||
drupal/inline_entity_form:^1.0@RC
|
||||
drupal/imagemagick
|
||||
drupal/image_effects
|
||||
drupal/colorbox
|
||||
drupal/devel:^4.1 devel
|
||||
drupal/geofield:^1.40 geofield
|
||||
drupal/geofield_map:^2.85 geofield_map
|
||||
drupal/imce:^2.4 imce
|
||||
EOF
|
||||
|
||||
log_info " => Enable Wisski modules"
|
||||
drush pm-enable --yes wisski_core wisski_linkblock wisski_pathbuilder wisski_adapter_sparql11_pb wisski_salz
|
||||
drupal_sites_permission_workaround
|
||||
|
||||
log_info " => Setting up WissKI Salz Adapter"
|
||||
drush php:script /wisskiutils/create_adapter.php "$INSTANCE_DOMAIN" "$GRAPHDB_REPO" "$GRAPHDB_HEADER"
|
||||
|
||||
log_info " => Updating TRUSTED_HOST_PATTERNS in settings.php"
|
||||
|
||||
/bin/bash /wisskiutils/set_trusted_host.sh
|
||||
|
||||
log_info " => Running initial cron"
|
||||
drush core-cron
|
||||
|
||||
log_info " => Provisioning is now complete. "
|
||||
log_ok "Your installation details are as follows:"
|
||||
function printdetails() {
|
||||
echo "URL: http://$INSTANCE_DOMAIN"
|
||||
echo "Username: $DRUPAL_USER"
|
||||
echo "Password: $DRUPAL_PASS"
|
||||
}
|
||||
printdetails
|
||||
|
||||
exit 0
|
||||
5
embed/resources/compose/barrel/scripts/user_shell.sh
Executable file
5
embed/resources/compose/barrel/scripts/user_shell.sh
Executable file
|
|
@ -0,0 +1,5 @@
|
|||
#!/bin/bash
|
||||
|
||||
# This script is used to start a user shell inside the docker container.
|
||||
cd "/var/www/data/project"
|
||||
sudo -u www-data "PATH=/var/www/data/project/vendor/bin:$PATH" /bin/bash "$@"
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This script will automatically create a WissKI Salz Adapter for use within the distillery.
|
||||
* It will not update any existing adapter and is rather primitive.
|
||||
*/
|
||||
|
||||
$argc = $_SERVER['argc']-3;
|
||||
$argv = array_slice($_SERVER['argv'], 3);
|
||||
|
||||
// read parameters from the command line
|
||||
if ($argc != 3) {
|
||||
die("Usage: drush php:script create_adapter.php INSTANCE_DOMAIN GRAPHDB_REPO HEADER");
|
||||
}
|
||||
$INSTANCE_DOMAIN = $argv[0];
|
||||
$GRAPHDB_REPO = $argv[1];
|
||||
$HEADER = $argv[2];
|
||||
|
||||
//
|
||||
// PROPERTIES FOR THE ADAPTER
|
||||
//
|
||||
|
||||
$id = 'default'; // id
|
||||
$type = 'sparql11_with_pb'; // plugin
|
||||
$machine_name = 'default'; // machine-name
|
||||
$label = 'Default WissKI Distillery Adapter';
|
||||
$description = 'Adapter for ' . $INSTANCE_DOMAIN; // description
|
||||
$writable = TRUE; // writable
|
||||
$is_preferred_local_store = TRUE; // is_preferred_local_store
|
||||
$header = $HEADER; // header
|
||||
$read_url = 'http://triplestore:7200/repositories/' . $GRAPHDB_REPO; // read_url
|
||||
$write_url = 'http://triplestore:7200/repositories/' . $GRAPHDB_REPO . '/statements'; // write_url
|
||||
$is_federatable = TRUE; // is_federatable
|
||||
$default_graph_uri = 'https://' . $INSTANCE_DOMAIN . '/';
|
||||
$same_as_properties = ['http://www.w3.org/2002/07/owl#sameAs']; // same_as_properties
|
||||
$ontology_graphs = []; // ontology_graphs
|
||||
|
||||
//
|
||||
// Do the creation!
|
||||
//
|
||||
|
||||
$storage = \Drupal::entityTypeManager()->getStorage('wisski_salz_adapter');
|
||||
$adapter = $storage->create([
|
||||
"id" => $id,
|
||||
"label" => $label,
|
||||
"description" => $description,
|
||||
]);
|
||||
$adapter->setEngineConfig([
|
||||
"id" => $type,
|
||||
"machine-name" => $machine_name,
|
||||
"header" => $header,
|
||||
"writeable" => $writable,
|
||||
"is_preferred_local_store" => $is_preferred_local_store,
|
||||
"read_url" => $read_url,
|
||||
"write_url" => $write_url,
|
||||
"is_federatable" => $is_federatable,
|
||||
"default_graph" => $default_graph_uri,
|
||||
"same_as_properties" => $same_as_properties,
|
||||
"ontology_graphs" => $ontology_graphs,
|
||||
]);
|
||||
$adapter->save();
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This script will list all the URIs that this system is aware of.
|
||||
* This works by listing all the default graph uris of all the adapters.
|
||||
*/
|
||||
|
||||
use Drupal\wisski_pathbuilder\Entity\WisskiPathEntity;
|
||||
|
||||
// load all the pathbuilders
|
||||
$pbs = \Drupal::entityTypeManager()->getStorage('wisski_pathbuilder')->loadMultiple();
|
||||
|
||||
// map over the pathbuilders
|
||||
$xmls = array_map(function($pb) {
|
||||
$xml = new \SimpleXMLElement("<pathbuilderinterface></pathbuilderinterface>");
|
||||
|
||||
$paths = $pb->getAllPaths();
|
||||
foreach ($paths as $key => $path) {
|
||||
$id = $path->getID();
|
||||
|
||||
$path = $pb->getPbPath($id);
|
||||
|
||||
$pathChild = $xml->addChild("path");
|
||||
$pathObject = WisskiPathEntity::load($id);
|
||||
|
||||
foreach ($path as $subkey => $value) {
|
||||
|
||||
if (in_array($subkey, ['relativepath'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($subkey == "parent") {
|
||||
$subkey = "group_id";
|
||||
}
|
||||
|
||||
$pathChild->addChild($subkey, htmlspecialchars($value));
|
||||
}
|
||||
|
||||
$pathArray = $pathChild->addChild('path_array');
|
||||
foreach ($pathObject->getPathArray() as $subkey => $value) {
|
||||
$pathArray->addChild($subkey % 2 == 0 ? 'x' : 'y', $value);
|
||||
}
|
||||
|
||||
$pathChild->addChild('datatype_property', htmlspecialchars($pathObject->getDatatypeProperty()));
|
||||
$pathChild->addChild('short_name', htmlspecialchars($pathObject->getShortName()));
|
||||
$pathChild->addChild('disamb', htmlspecialchars($pathObject->getDisamb()));
|
||||
$pathChild->addChild('description', htmlspecialchars($pathObject->getDescription()));
|
||||
$pathChild->addChild('uuid', htmlspecialchars($pathObject->uuid()));
|
||||
if ($pathObject->getType() == "Group" || $pathObject->getType() == "Smartgroup") {
|
||||
$pathChild->addChild('is_group', "1");
|
||||
} else {
|
||||
$pathChild->addChild('is_group', "0");
|
||||
}
|
||||
$pathChild->addChild('name', htmlspecialchars($pathObject->getName()));
|
||||
}
|
||||
|
||||
// turn it into XML
|
||||
$dom = dom_import_simplexml($xml)->ownerDocument;
|
||||
$dom->formatOutput = TRUE;
|
||||
return $dom->saveXML();
|
||||
}, $pbs);
|
||||
|
||||
echo json_encode($xmls);
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This script will list all the URIs that this system is aware of.
|
||||
* This works by listing all the default graph uris of all the adapters.
|
||||
*/
|
||||
|
||||
// iterate over all adapters
|
||||
$storage = \Drupal::entityTypeManager()->getStorage('wisski_salz_adapter');
|
||||
foreach ($storage->loadMultiple() as $adapter) {
|
||||
// read the configuration, and check if we have a default graph
|
||||
$conf = $adapter->getEngine()->getConfiguration();
|
||||
if(!array_key_exists('default_graph', $conf)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// and echo it out
|
||||
echo $conf['default_graph'] . "\n";
|
||||
}
|
||||
13
embed/resources/compose/barrel/wisskiutils/set_trusted_host.sh
Executable file
13
embed/resources/compose/barrel/wisskiutils/set_trusted_host.sh
Executable file
|
|
@ -0,0 +1,13 @@
|
|||
#!/bin/bash
|
||||
|
||||
# This utility script can be used to configure the trusted host settings inside of settings.php.
|
||||
# It doesn't take care of corner cases and should only be used when needed.
|
||||
|
||||
INSTANCE_DOMAIN="$(hostname -f)"
|
||||
INSTANCE_DOMAIN="${INSTANCE_DOMAIN%.wisski}"
|
||||
|
||||
TRUSTED_HOST_PATTERN="${INSTANCE_DOMAIN//\./\\\\.}"
|
||||
TRUSTED_HOST_PATTERNS='["'$TRUSTED_HOST_PATTERN'"]'
|
||||
|
||||
echo "Setting 'trusted_host_patterns' to $TRUSTED_HOST_PATTERNS"
|
||||
bash /wisskiutils/settings_php_set.sh 'trusted_host_patterns' "$TRUSTED_HOST_PATTERNS"
|
||||
17
embed/resources/compose/barrel/wisskiutils/settings_php_get.sh
Executable file
17
embed/resources/compose/barrel/wisskiutils/settings_php_get.sh
Executable file
|
|
@ -0,0 +1,17 @@
|
|||
#!/bin/bash
|
||||
|
||||
# settings_php_get.sh name
|
||||
# Gets the 'settings_php_get.php' setting 'name' as json-encoded value, or null when it does not exist.
|
||||
|
||||
NAME=$1
|
||||
|
||||
if [ -z "$NAME" ]; then
|
||||
echo "Usage: get_settings_setting.sh NAME"
|
||||
exit 1
|
||||
fi;
|
||||
|
||||
echo "$NAME" | drush php:eval '
|
||||
use \Drupal\Core\Site\Settings;
|
||||
$name=trim(file_get_contents("php://stdin"));
|
||||
echo json_encode(Settings::get($name));
|
||||
';
|
||||
56
embed/resources/compose/barrel/wisskiutils/settings_php_set.sh
Executable file
56
embed/resources/compose/barrel/wisskiutils/settings_php_set.sh
Executable file
|
|
@ -0,0 +1,56 @@
|
|||
#!/bin/bash
|
||||
|
||||
# settings_php_set.sh name value
|
||||
# Sets the 'settings.php' setting 'name' to 'value'.
|
||||
# Value must be json-encoded.
|
||||
|
||||
NAME=$1
|
||||
VALUE=$2
|
||||
|
||||
if [ -z "$NAME" ]; then
|
||||
echo "Usage: settings_php_set.sh NAME VALUE"
|
||||
exit 1
|
||||
fi;
|
||||
|
||||
if [ -z "$VALUE" ]; then
|
||||
echo "Usage: settings_php_set.sh NAME VALUE"
|
||||
exit 1
|
||||
fi;
|
||||
|
||||
cd /var/www/data/project
|
||||
chmod u+w web/sites/default/settings.php
|
||||
|
||||
(echo "$NAME"; echo "$VALUE" ) | drush php:eval '
|
||||
include_once DRUPAL_ROOT . "/core/includes/install.inc";
|
||||
|
||||
// read NAME and VALUE from STDIN
|
||||
$content=file_get_contents("php://stdin");
|
||||
$newline=strpos($content, "\n");
|
||||
$name=trim(substr($content, 0, $newline));
|
||||
$jvalue=trim(substr($content, $newline + 1));
|
||||
|
||||
// decode json values
|
||||
$value = @json_decode($jvalue);
|
||||
if ($data === null && json_last_error() !== JSON_ERROR_NONE) {
|
||||
echo "Invalid JSON, cannot update settings.php. \n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
// make parameters to drush_rewrite_settings
|
||||
$settings["settings"][$name] = (object)[
|
||||
"value" => $value,
|
||||
"required" => TRUE,
|
||||
];
|
||||
|
||||
// find the actual settings.php file to rewrite
|
||||
$filename = DRUPAL_ROOT . "/" . \Drupal::service("site.path") . "/settings.php";
|
||||
drupal_rewrite_settings($settings, $filename);
|
||||
|
||||
echo "Wrote " . $filename . "\n";
|
||||
return 0;
|
||||
';
|
||||
EXIT=$?
|
||||
|
||||
chmod u-w web/sites/default/settings.php
|
||||
|
||||
exit $?
|
||||
5
embed/resources/compose/dis/Dockerfile
Normal file
5
embed/resources/compose/dis/Dockerfile
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
FROM docker.io/library/alpine
|
||||
|
||||
COPY wdcli /wdcli
|
||||
EXPOSE 8888
|
||||
CMD ["/wdcli","--internal-in-docker","--config","${CONFIG_PATH}","dis_server","--bind","0.0.0.0:8888"]
|
||||
28
embed/resources/compose/dis/docker-compose.yml
Normal file
28
embed/resources/compose/dis/docker-compose.yml
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
version: "3.7"
|
||||
|
||||
services:
|
||||
wdresolve:
|
||||
build: .
|
||||
restart: always
|
||||
environment:
|
||||
# port and hostname for this image to use
|
||||
VIRTUAL_HOST: ${VIRTUAL_HOST}
|
||||
VIRTUAL_PORT: 8888
|
||||
VIRTUAL_PATH: /dis/
|
||||
|
||||
CONFIG_PATH: ${CONFIG_PATH}
|
||||
|
||||
# optional letsencrypt email
|
||||
LETSENCRYPT_HOST: ${LETSENCRYPT_HOST}
|
||||
LETSENCRYPT_EMAIL: ${LETSENCRYPT_EMAIL}
|
||||
|
||||
volumes:
|
||||
- "${CONFIG_PATH}:${CONFIG_PATH}:ro"
|
||||
- "${DEPLOY_ROOT}:${DEPLOY_ROOT}:ro"
|
||||
- "${GLOBAL_AUTHORIZED_KEYS_FILE}:${GLOBAL_AUTHORIZED_KEYS_FILE}:ro"
|
||||
- "${SELF_OVERRIDES_FILE}:${SELF_OVERRIDES_FILE}:ro"
|
||||
|
||||
networks:
|
||||
default:
|
||||
name: distillery
|
||||
external: true
|
||||
26
embed/resources/compose/reserve/docker-compose.yml
Normal file
26
embed/resources/compose/reserve/docker-compose.yml
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
version: "3.7"
|
||||
|
||||
services:
|
||||
static:
|
||||
image: tkw01536/gostatic
|
||||
restart: always
|
||||
environment:
|
||||
# port and hostname for this image to use
|
||||
VIRTUAL_HOST: ${VIRTUAL_HOST}
|
||||
VIRTUAL_PORT: 8043
|
||||
|
||||
# optional letsencrypt email
|
||||
LETSENCRYPT_HOST: ${LETSENCRYPT_HOST}
|
||||
LETSENCRYPT_EMAIL: ${LETSENCRYPT_EMAIL}
|
||||
|
||||
ports:
|
||||
- 8043
|
||||
|
||||
# volumes that are mounted
|
||||
volumes:
|
||||
- ./index.html:/srv/http/index.html:ro
|
||||
|
||||
networks:
|
||||
default:
|
||||
name: distillery
|
||||
external: true
|
||||
4
embed/resources/compose/reserve/index.html
Normal file
4
embed/resources/compose/reserve/index.html
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
<!DOCTYPE html>
|
||||
|
||||
This domain name is reserved.
|
||||
Content is a work in progress.
|
||||
5
embed/resources/compose/resolver/Dockerfile
Normal file
5
embed/resources/compose/resolver/Dockerfile
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
FROM docker.io/library/alpine
|
||||
|
||||
COPY wdcli /wdcli
|
||||
EXPOSE 8888
|
||||
CMD ["/wdcli","--internal-in-docker","--config","${CONFIG_PATH}","resolver_server","--bind","0.0.0.0:8888"]
|
||||
29
embed/resources/compose/resolver/docker-compose.yml
Normal file
29
embed/resources/compose/resolver/docker-compose.yml
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
version: "3.7"
|
||||
|
||||
services:
|
||||
wdresolve:
|
||||
build: .
|
||||
restart: always
|
||||
environment:
|
||||
# port and hostname for this image to use
|
||||
VIRTUAL_HOST: ${VIRTUAL_HOST}
|
||||
VIRTUAL_PORT: 8888
|
||||
VIRTUAL_PATH: /go/
|
||||
|
||||
CONFIG_PATH: ${CONFIG_PATH}
|
||||
|
||||
# optional letsencrypt email
|
||||
LETSENCRYPT_HOST: ${LETSENCRYPT_HOST}
|
||||
LETSENCRYPT_EMAIL: ${LETSENCRYPT_EMAIL}
|
||||
|
||||
volumes:
|
||||
- "${CONFIG_PATH}:${CONFIG_PATH}:ro"
|
||||
- "${DEPLOY_ROOT}:${DEPLOY_ROOT}:ro"
|
||||
- "${GLOBAL_AUTHORIZED_KEYS_FILE}:${GLOBAL_AUTHORIZED_KEYS_FILE}:ro"
|
||||
- "${SELF_OVERRIDES_FILE}:${SELF_OVERRIDES_FILE}:ro"
|
||||
- "${RESOLVER_CONFIG}:${RESOLVER_CONFIG}:ro"
|
||||
|
||||
networks:
|
||||
default:
|
||||
name: distillery
|
||||
external: true
|
||||
28
embed/resources/compose/self/docker-compose.yml
Normal file
28
embed/resources/compose/self/docker-compose.yml
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
version: "3.7"
|
||||
|
||||
services:
|
||||
tr:
|
||||
image: ghcr.io/tkw1536/tr:latest
|
||||
restart: always
|
||||
volumes:
|
||||
- "${OVERRIDES_FILE}:/overrides.json:ro"
|
||||
environment:
|
||||
# port and hostname for this image to use
|
||||
VIRTUAL_HOST: ${VIRTUAL_HOST}
|
||||
VIRTUAL_PORT: 8080
|
||||
VIRTUAL_PATH: /
|
||||
|
||||
# optional letsencrypt email
|
||||
LETSENCRYPT_HOST: ${LETSENCRYPT_HOST}
|
||||
LETSENCRYPT_EMAIL: ${LETSENCRYPT_EMAIL}
|
||||
|
||||
# the overrides file
|
||||
OVERRIDES: /overrides.json
|
||||
|
||||
# where to redirect to
|
||||
TARGET: ${TARGET}
|
||||
|
||||
networks:
|
||||
default:
|
||||
name: distillery
|
||||
external: true
|
||||
35
embed/resources/compose/sql/docker-compose.yml
Normal file
35
embed/resources/compose/sql/docker-compose.yml
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
version: "3.7"
|
||||
|
||||
services:
|
||||
sql:
|
||||
image: mariadb
|
||||
volumes:
|
||||
- "./data/:/var/lib/mysql"
|
||||
ports:
|
||||
- 127.0.0.1:3306:3306
|
||||
environment:
|
||||
# This combination of environment variables will configure a passwordless root user
|
||||
# that can only connect to the container from 'localhost'.
|
||||
# This means we can only connect using 'docker-compose exec sql mysql -C '...' '.
|
||||
- "MYSQL_ALLOW_EMPTY_PASSWORD=yes"
|
||||
- "MYSQL_ROOT_HOST=localhost"
|
||||
restart: always
|
||||
phpmyadmin:
|
||||
image: phpmyadmin/phpmyadmin
|
||||
environment:
|
||||
- "PMA_HOST=sql"
|
||||
- "HIDE_PHP_VERSION=true"
|
||||
- "UPLOAD_LIMIT=100M"
|
||||
# phpmyadmin running on localhost:8080 so that we can easily access the system graphically.
|
||||
# By default no admin account is created, so initial shell access to make one is needed.
|
||||
ports:
|
||||
- 127.0.0.1:8080:80
|
||||
depends_on:
|
||||
- sql
|
||||
restart: always
|
||||
|
||||
|
||||
networks:
|
||||
default:
|
||||
name: distillery
|
||||
external: true
|
||||
17
embed/resources/compose/ssh/docker-compose.yml
Normal file
17
embed/resources/compose/ssh/docker-compose.yml
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
version: "3.7"
|
||||
|
||||
services:
|
||||
ssh:
|
||||
image: ghcr.io/tkw1536/dockersshd:latest
|
||||
command: -hostkey /keys/hostkey -shell /user_shell.sh -keylabel eu.wiss-ki.barrel.authfile -userlabel eu.wiss-ki.barrel.slug -L triplestore:7200 -L phpmyadmin:80 -L sql:3306
|
||||
ports:
|
||||
- "2222:2222"
|
||||
volumes:
|
||||
- './data/keys:/keys'
|
||||
- '/var/run/docker.sock:/var/run/docker.sock:ro'
|
||||
restart: always
|
||||
|
||||
networks:
|
||||
default:
|
||||
name: distillery
|
||||
external: true
|
||||
3
embed/resources/compose/triplestore/.dockerignore
Normal file
3
embed/resources/compose/triplestore/.dockerignore
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
*
|
||||
!*.zip
|
||||
!entrypoint.sh
|
||||
64
embed/resources/compose/triplestore/Dockerfile
Normal file
64
embed/resources/compose/triplestore/Dockerfile
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
# This Dockerfile contains instructions to compile and run GraphDB inside a Docker container.
|
||||
# It is roughly based on https://github.com/Ontotext-AD/graphdb-docker/blob/master/free-edition/Dockerfile
|
||||
# but has been modified for performance and security.
|
||||
|
||||
# This image is intended to be built like:
|
||||
# docker build --build-arg graphdb_src=graphdb.zip .
|
||||
|
||||
# We first make a base image to base further builds on.
|
||||
# We don't use alpine here, as that uses significantly slower musl instead of glibc.
|
||||
FROM adoptopenjdk/openjdk11:debian-slim as base
|
||||
|
||||
# Create a user called graphdb
|
||||
RUN useradd -ms /bin/bash graphdb
|
||||
|
||||
# make a base images, to add the sources to.
|
||||
FROM base as sources
|
||||
|
||||
# install unzip
|
||||
RUN apt-get update && apt-get install -y unzip
|
||||
|
||||
# add the source file (by default graphdb.zip) to the image
|
||||
ARG src=graphdb.zip
|
||||
ADD ${src} /graphdb.zip
|
||||
|
||||
# unpack it into a temporary directory
|
||||
RUN unzip "$src" -d "/unpack/"
|
||||
|
||||
# Move it into /opt/graphdb, and chown it to graphdb
|
||||
RUN mv "/unpack"/* /opt/graphdb
|
||||
RUN chown -R graphdb:graphdb /opt/graphdb
|
||||
|
||||
# finally make an image that will run
|
||||
FROM base as final
|
||||
|
||||
# add the entrypoint script
|
||||
ADD entrypoint.sh /entrypoint.sh
|
||||
|
||||
# copy over the sources
|
||||
COPY --from=sources /opt/graphdb /opt/graphdb
|
||||
|
||||
# set environment variables for graphdb_home and path
|
||||
ENV GRAPHDB_HOME=/opt/graphdb
|
||||
ENV PATH=$GRAPHDB_HOME/bin:$PATH
|
||||
|
||||
# Workaround for CVE-2021-44228
|
||||
# (not sure if we are vulnerable, but just because)
|
||||
ENV LOG4J_FORMAT_MSG_NO_LOOKUPS=true
|
||||
|
||||
# expose a port
|
||||
EXPOSE 7200
|
||||
|
||||
# setup a healthcheck, that checks if the server is up.
|
||||
RUN apt-get update && apt-get install -y curl
|
||||
HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 CMD curl --fail 127.0.0.1:7200/rest/repositories || exit 1
|
||||
|
||||
# Add volumes for data, work and logs as these might be accessible from the outside.
|
||||
# To add your own configuration, manually mount a config file into /opt/graphdb/work
|
||||
VOLUME /opt/graphdb/data
|
||||
VOLUME /opt/graphdb/work
|
||||
VOLUME /opt/graphdb/logs
|
||||
|
||||
# setup command and entrypoint
|
||||
CMD ["-Dgraphdb.home=/opt/graphdb"]
|
||||
ENTRYPOINT ["/bin/bash", "/entrypoint.sh"]
|
||||
22
embed/resources/compose/triplestore/docker-compose.yml
Normal file
22
embed/resources/compose/triplestore/docker-compose.yml
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
version: "3.7"
|
||||
|
||||
services:
|
||||
triplestore:
|
||||
build: .
|
||||
ports:
|
||||
- "127.0.0.1:7200:7200"
|
||||
volumes:
|
||||
- './data/data:/opt/graphdb/data'
|
||||
- './data/work:/opt/graphdb/work'
|
||||
- './data/logs:/opt/graphdb/logs'
|
||||
command: "\"-Dgraphdb.home=/opt/graphdb -Ddefault.min.distinct.threshold=2G\""
|
||||
# Use 1GB of heap space
|
||||
environment:
|
||||
GDB_HEAP_SIZE: 16G
|
||||
|
||||
restart: always
|
||||
|
||||
networks:
|
||||
default:
|
||||
name: distillery
|
||||
external: true
|
||||
13
embed/resources/compose/triplestore/entrypoint.sh
Normal file
13
embed/resources/compose/triplestore/entrypoint.sh
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# Because we want to run graphdb as a limited user
|
||||
# we need to make sure that the volumes are writable.
|
||||
# Because of that, we 'chown'
|
||||
|
||||
chown graphdb:graphdb /opt/graphdb/data
|
||||
chown graphdb:graphdb /opt/graphdb/work
|
||||
chown graphdb:graphdb /opt/graphdb/logs
|
||||
|
||||
# switch to the graphdb user, and run graphdb
|
||||
su graphdb -c "/opt/graphdb/bin/graphdb $@"
|
||||
51
embed/resources/compose/web/docker-compose.yml
Normal file
51
embed/resources/compose/web/docker-compose.yml
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
version: "3.7"
|
||||
|
||||
services:
|
||||
nginx-proxy:
|
||||
image: ghcr.io/nginx-proxy/nginx-proxy:alpine
|
||||
environment:
|
||||
- DEFAULT_HOST=${DEFAULT_HOST}
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
volumes:
|
||||
- "vhost:/etc/nginx/vhost.d"
|
||||
- "./global.conf:/etc/nginx/conf.d/global.conf:ro"
|
||||
- "./proxy.conf:/etc/nginx/proxy.conf:ro"
|
||||
- "htpasswd:/etc/nginx/htpasswd"
|
||||
- "html:/usr/share/nginx/html"
|
||||
- "/var/run/docker.sock:/tmp/docker.sock:ro"
|
||||
- "certs:/etc/nginx/certs"
|
||||
labels:
|
||||
com.github.jrcs.letsencrypt_nginx_proxy_companion.nginx_proxy: true
|
||||
restart: always
|
||||
networks:
|
||||
- default
|
||||
|
||||
letsencrypt-nginx-proxy-companion:
|
||||
image: docker.io/nginxproxy/acme-companion:latest
|
||||
volumes:
|
||||
- "/var/run/docker.sock:/var/run/docker.sock:ro"
|
||||
- "htpasswd:/etc/nginx/htpasswd"
|
||||
- "vhost:/etc/nginx/vhost.d"
|
||||
- "html:/usr/share/nginx/html"
|
||||
- "/var/run/docker.sock:/tmp/docker.sock:ro"
|
||||
- "certs:/etc/nginx/certs"
|
||||
- "acme:/etc/acme.sh"
|
||||
restart: always
|
||||
networks:
|
||||
- default
|
||||
depends_on:
|
||||
- nginx-proxy
|
||||
|
||||
volumes:
|
||||
acme:
|
||||
vhost:
|
||||
html:
|
||||
certs:
|
||||
htpasswd:
|
||||
|
||||
networks:
|
||||
default:
|
||||
name: distillery
|
||||
external: true
|
||||
4
embed/resources/compose/web/global.conf
Normal file
4
embed/resources/compose/web/global.conf
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
# Nginx Configuration File
|
||||
# These should match with distillery/resources/compose/barrel/conf/wisski.ini.
|
||||
|
||||
client_max_body_size 1000m;
|
||||
19
embed/resources/compose/web/proxy.conf
Normal file
19
embed/resources/compose/web/proxy.conf
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
# HTTP 1.1 support
|
||||
proxy_http_version 1.1;
|
||||
proxy_buffering off;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $proxy_connection;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
proxy_set_header X-Forwarded-Ssl $proxy_x_forwarded_ssl;
|
||||
proxy_set_header X-Forwarded-Port $proxy_x_forwarded_port;
|
||||
|
||||
# Mitigate httpoxy attack (see README for details)
|
||||
proxy_set_header Proxy "";
|
||||
|
||||
# Timeouts for the proxy connection - in sync with the appropriate max_execution time.
|
||||
proxy_connect_timeout 3000s;
|
||||
proxy_read_timeout 3000s;
|
||||
proxy_send_timeout 3000s;
|
||||
2
embed/resources/runtime/utils/README
Normal file
2
embed/resources/runtime/utils/README
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
Files in this folder are utility scripts to be used from within individual WissKI instances.
|
||||
They are mounted under /utils/ and should be used with care.
|
||||
16
embed/resources/runtime/utils/blind_update.sh
Normal file
16
embed/resources/runtime/utils/blind_update.sh
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
#!/bin/bash
|
||||
|
||||
# This utility script can be used to blindly update all dependencies to their latest versions.
|
||||
# It does not perform any checking whatsoever.
|
||||
|
||||
# update the main modules
|
||||
cd /var/www/data/project || exit 1
|
||||
chmod u+rw web/sites/default/
|
||||
composer update
|
||||
|
||||
# update the db
|
||||
drush -y updatedb
|
||||
|
||||
# update the wisski dependencies
|
||||
cd /var/www/data/project/web/modules/contrib/wisski || exit 1
|
||||
composer update
|
||||
25
embed/resources/runtime/utils/create_admin.sh
Normal file
25
embed/resources/runtime/utils/create_admin.sh
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
# read user
|
||||
USER=$1
|
||||
if [ -z "$USER" ]; then
|
||||
echo "Usage: create_admin.sh USERNAME"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# read password
|
||||
echo "Enter Password for $USER:"
|
||||
read -s PASS
|
||||
echo "Enter the same password again:"
|
||||
read -s PASS2
|
||||
|
||||
if [ "$PASS" != "$PASS2" ]; then
|
||||
echo "Passwords not equal"
|
||||
exit 1
|
||||
fi;
|
||||
|
||||
# create the user and add the admin role
|
||||
cd /var/www/data/project/
|
||||
drush user:create "$USER" --password="$PASS"
|
||||
drush user-add-role administrator "$USER"
|
||||
8
embed/resources/runtime/utils/cron.sh
Executable file
8
embed/resources/runtime/utils/cron.sh
Executable file
|
|
@ -0,0 +1,8 @@
|
|||
#!/bin/bash
|
||||
|
||||
# This utility script can be used to run all cron tasks.
|
||||
|
||||
cd /var/www/data/project || exit 1
|
||||
export PATH=/var/www/data/project/vendor/bin:$PATH
|
||||
|
||||
drush core-cron
|
||||
22
embed/resources/runtime/utils/install_colorbox.sh
Normal file
22
embed/resources/runtime/utils/install_colorbox.sh
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# make a temporary directory and cd into it
|
||||
TEMPDIR=$(mktemp -d)
|
||||
pushd "$TEMPDIR"
|
||||
|
||||
# curl the colorbox zip and unpack it
|
||||
curl -L https://github.com/jackmoore/colorbox/archive/master.zip --output master.zip
|
||||
unzip master.zip
|
||||
|
||||
# make the directory for libraries, and remove the old colorbox installation
|
||||
chmod u+rw /var/www/data/project/web/sites/default/
|
||||
mkdir -p /var/www/data/project/web/sites/default/libraries/
|
||||
rm -rf /var/www/data/project/web/sites/default/libraries/colorbox
|
||||
|
||||
# copy over the new installation
|
||||
mv colorbox-master/ /var/www/data/project/web/sites/default/libraries/colorbox
|
||||
|
||||
# cleanup
|
||||
popd
|
||||
rm -rf "$TEMPDIR"
|
||||
6
embed/resources/runtime/utils/patch_easyrdf.sh
Executable file
6
embed/resources/runtime/utils/patch_easyrdf.sh
Executable file
|
|
@ -0,0 +1,6 @@
|
|||
#!/bin/sh
|
||||
|
||||
# This script can be used to repatch EasyRDF when needed.
|
||||
cd /var/www/data/project/web/modules/contrib/wisski || exit 1
|
||||
EASYRDF_RESPONSE="./vendor/easyrdf/easyrdf/lib/EasyRdf/Http/Response.php"
|
||||
patch -N "$EASYRDF_RESPONSE" < "/patch/easyrdf.patch"
|
||||
6
embed/resources/runtime/utils/patch_triples.sh
Normal file
6
embed/resources/runtime/utils/patch_triples.sh
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
#!/bin/sh
|
||||
|
||||
# This script can be used to repatch EasyRDF when needed.
|
||||
cd /var/www/data/project/web/modules/contrib/wisski/ || exit 1
|
||||
TRIPLESTABCONTROLLER="./wisski_adapter_sparql11_pb/src/Controller/Sparql11TriplesTabController.php"
|
||||
patch -N "$TRIPLESTABCONTROLLER" < "/patch/triples.patch"
|
||||
22
embed/resources/runtime/utils/use_wisski.sh
Normal file
22
embed/resources/runtime/utils/use_wisski.sh
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# read user
|
||||
VERSION=$1
|
||||
if [ -z "$VERSION" ]; then
|
||||
echo "Usage: use_wisski.sh VERSION"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# update the main modules
|
||||
cd /var/www/data/project
|
||||
chmod u+rw web/sites/default/
|
||||
composer require "drupal/wisski:$VERSION"
|
||||
|
||||
# update the wisski dependencies
|
||||
pushd /var/www/data/project/web/modules/contrib/wisski
|
||||
composer update
|
||||
popd
|
||||
|
||||
# update the db
|
||||
drush -y updatedb
|
||||
26
embed/resources/runtime/utils/wisski_2x_3x.sh
Normal file
26
embed/resources/runtime/utils/wisski_2x_3x.sh
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# temporarily extend permissions
|
||||
chmod 777 web/sites/default
|
||||
chmod 666 web/sites/default/*settings.php
|
||||
chmod 666 web/sites/default/*services.yml
|
||||
|
||||
# update the core itself
|
||||
composer require 'drupal/core-recommended:^9' 'drupal/core-composer-scaffold:^9' 'drupal/core-project-message:^9' --update-with-dependencies --no-update
|
||||
composer update
|
||||
composer require 'drupal/wisski'
|
||||
|
||||
# update requirements for wisski!
|
||||
pushd web/modules/contrib/wisski || exit 1
|
||||
composer update
|
||||
popd || exit 1
|
||||
|
||||
# run the update and clear the cache!
|
||||
drush updatedb --yes
|
||||
# drush cc
|
||||
|
||||
# and reset everything back to normal
|
||||
chmod 755 web/sites/default
|
||||
chmod 644 web/sites/default/*settings.php
|
||||
chmod 644 web/sites/default/*services.yml
|
||||
63
embed/resources/templates/bootstrap/env
Normal file
63
embed/resources/templates/bootstrap/env
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
# Several docker-compose files are created to manage global services and the system itself.
|
||||
# On top of this all real-system space will be created under this directory.
|
||||
DEPLOY_ROOT=${DEPLOY_ROOT}
|
||||
|
||||
# Each created Drupal Instance corresponds to a single domain name.
|
||||
# These domain names should either be a complete domain name or a sub-domain of a default domain.
|
||||
# This setting configures the default domain-name to create subdomains of.
|
||||
DEFAULT_DOMAIN=${DEFAULT_DOMAIN}
|
||||
|
||||
# By default, the default domain redirects to the distillery repository.
|
||||
# If you want to change this, set an alternate domain name here.
|
||||
SELF_REDIRECT=
|
||||
|
||||
# By default, only the 'self' domain above is caught.
|
||||
# To catch additional domains, add them here (comma seperated)
|
||||
SELF_EXTRA_DOMAINS=
|
||||
|
||||
# You can override individual URLS in the homepage.
|
||||
# Do this by adding URLs (without trailing '/'s) into a JSON file
|
||||
SELF_OVERRIDES_FILE=${SELF_OVERRIDES_FILE}
|
||||
|
||||
# The system can support setting up certificate(s) automatically.
|
||||
# It can be enabled by setting an email for certbot certificates.
|
||||
# This email address can be configured here.
|
||||
CERTBOT_EMAIL=
|
||||
|
||||
# The maximum age (in days) for backups to be kept.
|
||||
# Backups older than this will be removed when a new backup is made.
|
||||
MAX_BACKUP_AGE=30
|
||||
|
||||
|
||||
# Each Drupal instance requires a corresponding system user, database users and databases.
|
||||
# These are also set by the appropriate domain name.
|
||||
# To differentiate them from other users of the system, these names can be prefixed.
|
||||
# The prefix to use can be configured here.
|
||||
# When changing these please consider that no system user may exist that has the same name as a mysql user.
|
||||
# This is a MariaDB restriction.
|
||||
MYSQL_USER_PREFIX=mysql-factory-
|
||||
MYSQL_DATABASE_PREFIX=mysql-factory-
|
||||
GRAPHDB_USER_PREFIX=graphdb-factory-
|
||||
GRAPHDB_REPO_PREFIX=graphdb-factory-
|
||||
|
||||
# In addition to the filesystem the WissKI distillery requires a single SQL table.
|
||||
# It uses this database to store a list of installed things
|
||||
DISTILLERY_BOOKKEEPING_DATABASE=distillery
|
||||
DISTILLERY_BOOKKEEPING_TABLE=distillery
|
||||
|
||||
|
||||
# Various components use password-based-authentication.
|
||||
# These passwords are generated automatically.
|
||||
# This variable can be used to determine their length.
|
||||
PASSWORD_LENGTH=64
|
||||
|
||||
# A file to be used for global authorized_keys for the ssh server.
|
||||
GLOBAL_AUTHORIZED_KEYS_FILE=${AUTHORIZED_KEYS_FILE}
|
||||
|
||||
# The admin user and password of the GraphDB interface, to be used for queries
|
||||
GRAPHDB_ADMIN_USER=${GRAPHDB_ADMIN_USER}
|
||||
GRAPHDB_ADMIN_PASSWORD=${GRAPHDB_ADMIN_PASSWORD}
|
||||
|
||||
# The admin password to use for access to mysql
|
||||
MYSQL_ADMIN_USER=${MYSQL_ADMIN_USER}
|
||||
MYSQL_ADMIN_PASSWORD=${MYSQL_ADMIN_PASSWORD}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
# This file contains authorized_keys files valid for every repository in the distillery.
|
||||
# To add a key, add one file per line.
|
||||
1
embed/resources/templates/bootstrap/overrides.json
Normal file
1
embed/resources/templates/bootstrap/overrides.json
Normal file
|
|
@ -0,0 +1 @@
|
|||
{}
|
||||
10
embed/resources/templates/docker-env/barrel
Normal file
10
embed/resources/templates/docker-env/barrel
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
DATA_PATH=${DATA_PATH}
|
||||
UTILS_DIR=${UTILS_DIR}
|
||||
|
||||
SLUG=${SLUG}
|
||||
VIRTUAL_HOST=${VIRTUAL_HOST}
|
||||
|
||||
LETSENCRYPT_HOST=${LETSENCRYPT_HOST}
|
||||
LETSENCRYPT_EMAIL=${LETSENCRYPT_EMAIL}
|
||||
|
||||
GLOBAL_AUTHORIZED_KEYS_FILE=${GLOBAL_AUTHORIZED_KEYS_FILE}
|
||||
9
embed/resources/templates/docker-env/dis
Normal file
9
embed/resources/templates/docker-env/dis
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
VIRTUAL_HOST=${VIRTUAL_HOST}
|
||||
|
||||
LETSENCRYPT_HOST=${LETSENCRYPT_HOST}
|
||||
LETSENCRYPT_EMAIL=${LETSENCRYPT_EMAIL}
|
||||
|
||||
CONFIG_PATH=${CONFIG_PATH}
|
||||
DEPLOY_ROOT=${DEPLOY_ROOT}
|
||||
GLOBAL_AUTHORIZED_KEYS_FILE=${GLOBAL_AUTHORIZED_KEYS_FILE}
|
||||
SELF_OVERRIDES_FILE=${SELF_OVERRIDES_FILE}
|
||||
4
embed/resources/templates/docker-env/reserve
Normal file
4
embed/resources/templates/docker-env/reserve
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
VIRTUAL_HOST=${VIRTUAL_HOST}
|
||||
|
||||
LETSENCRYPT_HOST=${LETSENCRYPT_HOST}
|
||||
LETSENCRYPT_EMAIL=${LETSENCRYPT_EMAIL}
|
||||
10
embed/resources/templates/docker-env/resolver
Normal file
10
embed/resources/templates/docker-env/resolver
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
VIRTUAL_HOST=${VIRTUAL_HOST}
|
||||
|
||||
LETSENCRYPT_HOST=${LETSENCRYPT_HOST}
|
||||
LETSENCRYPT_EMAIL=${LETSENCRYPT_EMAIL}
|
||||
|
||||
CONFIG_PATH=${CONFIG_PATH}
|
||||
DEPLOY_ROOT=${DEPLOY_ROOT}
|
||||
GLOBAL_AUTHORIZED_KEYS_FILE=${GLOBAL_AUTHORIZED_KEYS_FILE}
|
||||
SELF_OVERRIDES_FILE=${SELF_OVERRIDES_FILE}
|
||||
RESOLVER_CONFIG=${RESOLVER_CONFIG}
|
||||
7
embed/resources/templates/docker-env/self
Normal file
7
embed/resources/templates/docker-env/self
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
VIRTUAL_HOST=${VIRTUAL_HOST}
|
||||
|
||||
LETSENCRYPT_HOST=${LETSENCRYPT_HOST}
|
||||
LETSENCRYPT_EMAIL=${LETSENCRYPT_EMAIL}
|
||||
|
||||
TARGET=${TARGET}
|
||||
OVERRIDES_FILE=${OVERRIDES_FILE}
|
||||
1
embed/resources/templates/docker-env/web
Normal file
1
embed/resources/templates/docker-env/web
Normal file
|
|
@ -0,0 +1 @@
|
|||
DEFAULT_HOST=${DEFAULT_HOST}
|
||||
57
embed/resources/templates/repository/graphdb-repo.ttl
Normal file
57
embed/resources/templates/repository/graphdb-repo.ttl
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
# This file is used to initialize a new GraphDB repository.
|
||||
# In this file the variables ${GRAPHDB_REPO} and ${INSTANCE_DOMAIN} will be replaced.
|
||||
# All other variables will be left untouched.
|
||||
|
||||
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>.
|
||||
@prefix rep: <http://www.openrdf.org/config/repository#>.
|
||||
@prefix sr: <http://www.openrdf.org/config/repository/sail#>.
|
||||
@prefix sail: <http://www.openrdf.org/config/sail#>.
|
||||
@prefix owlim: <http://www.ontotext.com/trree/owlim#>.
|
||||
|
||||
[] a rep:Repository ;
|
||||
rep:repositoryID "${GRAPHDB_REPO}" ;
|
||||
rdfs:label "${INSTANCE_DOMAIN}" ;
|
||||
rep:repositoryImpl [
|
||||
rep:repositoryType "graphdb:SailRepository" ;
|
||||
sr:sailImpl [
|
||||
sail:sailType "graphdb:Sail" ;
|
||||
|
||||
owlim:owlim-license "" ;
|
||||
|
||||
owlim:base-URL "http://${INSTANCE_DOMAIN}/" ;
|
||||
owlim:defaultNS "" ;
|
||||
owlim:entity-index-size "10000000" ;
|
||||
owlim:entity-id-size "32" ;
|
||||
owlim:imports "" ;
|
||||
owlim:repository-type "file-repository" ;
|
||||
owlim:ruleset "empty" ;
|
||||
owlim:storage-folder "storage" ;
|
||||
|
||||
owlim:enable-context-index "false" ;
|
||||
owlim:cache-memory "80m" ;
|
||||
owlim:tuple-index-memory "80m" ;
|
||||
|
||||
owlim:enablePredicateList "false" ;
|
||||
owlim:predicate-memory "0%" ;
|
||||
|
||||
owlim:fts-memory "0%" ;
|
||||
owlim:ftsIndexPolicy "never" ;
|
||||
owlim:ftsLiteralsOnly "true" ;
|
||||
|
||||
owlim:in-memory-literal-properties "false" ;
|
||||
owlim:enable-literal-index "true" ;
|
||||
owlim:index-compression-ratio "-1" ;
|
||||
|
||||
owlim:check-for-inconsistencies "false" ;
|
||||
owlim:disable-sameAs "false" ;
|
||||
owlim:enable-optimization "true" ;
|
||||
owlim:transaction-mode "safe" ;
|
||||
owlim:transaction-isolation "true" ;
|
||||
owlim:query-timeout "0" ;
|
||||
owlim:query-limit-results "0" ;
|
||||
owlim:throw-QueryEvaluationException-on-timeout "false" ;
|
||||
owlim:useShutdownHooks "true" ;
|
||||
owlim:read-only "false" ;
|
||||
owlim:nonInterpretablePredicates "http://www.w3.org/2000/01/rdf-schema#label;http://www.w3.org/1999/02/22-rdf-syntax-ns#type;http://www.ontotext.com/owlim/ces#gazetteerConfig;http://www.ontotext.com/owlim/ces#metadataConfig" ;
|
||||
]
|
||||
].
|
||||
110
embed/resources_template.go
Normal file
110
embed/resources_template.go
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
package embed
|
||||
|
||||
import (
|
||||
"io"
|
||||
"io/fs"
|
||||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/exp/maps"
|
||||
"golang.org/x/exp/slices"
|
||||
)
|
||||
|
||||
var templateRegexp = regexp.MustCompile(`\${[^}]+}`)
|
||||
|
||||
// InstallTemplates open the resource src, and installs it into dst.
|
||||
// the template resource must fit into memory.
|
||||
//
|
||||
// For each variable ${THING} inside dest, a key 'THING' must exist in context.
|
||||
// Extra or missing template keys are an error.
|
||||
func InstallTemplate(dst, src string, context map[string]string) error {
|
||||
bytes, srcMode, err := doTemplate(src, context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// determine if we need to create the destination file, or if it already exists
|
||||
dstStat, dstErr := os.Stat(dst)
|
||||
switch {
|
||||
case os.IsNotExist(dstErr):
|
||||
case dstErr != nil:
|
||||
return errors.Wrapf(dstErr, "Error calling stat on destination %s", dst)
|
||||
case dstStat.IsDir():
|
||||
return errors.Wrapf(errExpectedFileButGotDirectory, "Error processing destination %s", dst)
|
||||
}
|
||||
|
||||
// open and write the destination file
|
||||
dstFile, err := os.OpenFile(dst, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, srcMode)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "Unable to open file %s", dst)
|
||||
}
|
||||
_, err = dstFile.Write(bytes)
|
||||
return errors.Wrapf(err, "Unable to write destination %s", dst)
|
||||
}
|
||||
|
||||
// ReadTemplate is like InstallTemplate, except that it writes template into a byte slice and returns it.
|
||||
func ReadTemplate(src string, context map[string]string) ([]byte, error) {
|
||||
bytes, _, err := doTemplate(src, context)
|
||||
return bytes, err
|
||||
}
|
||||
|
||||
func doTemplate(src string, context map[string]string) (bytes []byte, mode fs.FileMode, err error) {
|
||||
// open the source file!
|
||||
srcFile, err := resourceEmbed.Open(src)
|
||||
if err != nil {
|
||||
return nil, mode, errors.Wrapf(err, "Error opening source file %s", src)
|
||||
}
|
||||
defer srcFile.Close()
|
||||
|
||||
// stat the source file to install
|
||||
srcStat, srcErr := srcFile.Stat()
|
||||
if srcErr != nil {
|
||||
return nil, mode, errors.Wrapf(srcErr, "Error calling stat on source %s", src)
|
||||
}
|
||||
|
||||
// should not be a directory
|
||||
if srcStat.IsDir() {
|
||||
return nil, mode, errors.Wrapf(errExpectedFileButGotDirectory, "Error calling stat on source %s", src)
|
||||
}
|
||||
|
||||
// read the template and replace
|
||||
templates, err := io.ReadAll(srcFile)
|
||||
if err != nil {
|
||||
return nil, mode, errors.Wrapf(err, "Unable to read src file %s", src)
|
||||
}
|
||||
|
||||
// keep track of context keys that have not been used
|
||||
unuusedContext := make(map[string]struct{}, len(context))
|
||||
for key := range context {
|
||||
unuusedContext[key] = struct{}{}
|
||||
}
|
||||
|
||||
// replace the template regexp
|
||||
// keeping track of unuused errors
|
||||
var hadError error
|
||||
templates = templateRegexp.ReplaceAllFunc(templates, func(b []byte) []byte {
|
||||
name := string(b[2 : len(b)-1]) // remove the leading ${ and trailing }
|
||||
delete(unuusedContext, name) // mark the key as having been read
|
||||
|
||||
value, ok := context[name]
|
||||
if hadError != nil && !ok {
|
||||
hadError = errors.Errorf("key %s missing in context", name)
|
||||
}
|
||||
return []byte(value)
|
||||
})
|
||||
|
||||
if hadError != nil {
|
||||
return nil, mode, hadError
|
||||
}
|
||||
|
||||
if len(unuusedContext) != 0 {
|
||||
keys := maps.Keys(unuusedContext)
|
||||
slices.Sort(keys)
|
||||
return nil, mode, errors.Errorf("additional keys %s in context", strings.Join(keys, ","))
|
||||
}
|
||||
|
||||
// return the data and the mode!
|
||||
return templates, srcStat.Mode(), nil
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue